EGSnrc C++ class library  Report PIRS-898 (2021)
Iwan Kawrakow, Ernesto Mainegra-Hing, Frederic Tessier, Reid Townson and Blake Walters
egs_voxelized_shape.cpp
Go to the documentation of this file.
1 /*
2 ###############################################################################
3 #
4 # EGSnrc egs++ voxelized shape
5 # Copyright (C) 2015 National Research Council Canada
6 #
7 # This file is part of EGSnrc.
8 #
9 # EGSnrc is free software: you can redistribute it and/or modify it under
10 # the terms of the GNU Affero General Public License as published by the
11 # Free Software Foundation, either version 3 of the License, or (at your
12 # option) any later version.
13 #
14 # EGSnrc is distributed in the hope that it will be useful, but WITHOUT ANY
15 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16 # FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
17 # more details.
18 #
19 # You should have received a copy of the GNU Affero General Public License
20 # along with EGSnrc. If not, see <http://www.gnu.org/licenses/>.
21 #
22 ###############################################################################
23 #
24 # Author: Iwan Kawrakow, 2009
25 #
26 # Contributors: Frederic Tessier
27 # Reid Townson
28 # Hannah Gallop
29 #
30 ###############################################################################
31 */
32 
33 
39 #include "egs_voxelized_shape.h"
40 #include "egs_input.h"
41 #include "egs_functions.h"
42 
43 #include <fstream>
44 using namespace std;
45 
46 static bool EGS_VOXELIZED_SHAPE_LOCAL inputSet = false;
47 static shared_ptr<EGS_BlockInput> EGS_VOXELIZED_SHAPE_LOCAL shapeBlockInput = make_shared<EGS_BlockInput>("shape");
48 
49 void EGS_VoxelizedShape::EGS_VoxelizedShapeFormat0(const char *fname,
50  const string &Name,EGS_ObjectFactory *f) {
51  prob=0;
52  xpos=0;
53  ypos=0;
54  zpos=0;
55  map=0;
56  nx=0;
57  ny=0;
58  nz=0;
59  nxy=0;
60  nreg=0;
61  type=-1;
62  const static char *func = "EGS_VoxelizedShape::EGS_VoxelizedShape";
63  otype = "voxelized_shape";
64  if (!fname) {
65  return;
66  }
67  ifstream data(fname,ios::binary);
68  if (!data) {
69  egsWarning("%s: failed to open file %s\n",func,fname);
70  return;
71  }
72  char endian, form;
73  data.read(&endian,1);
74  data.read(&form,1);
75  if (data.fail()) {
76  egsWarning("%s: failed to read endianess and format from %s\n",func,fname);
77  return;
78  }
79  if (form < 0 || form > 1) {
80  egsWarning("%s: unknwon format %d found in file %s\n",func,(int)form,fname);
81  return;
82  }
83  if (endian != egsGetEndian()) {
84  egsWarning("%s: data in %s from a machine with different endianess.\n"
85  " Byte swaping not implemented yet.\n",func,fname);
86  return;
87  }
88  short snx, sny, snz;
89  data.read((char *)&snx,sizeof(short));
90  data.read((char *)&sny,sizeof(short));
91  data.read((char *)&snz,sizeof(short));
92  if (data.fail()) {
93  egsWarning("%s: failed to read number of voxels from %s\n",func,fname);
94  return;
95  }
96  if (snx < 1 || snx > 10000 || sny < 1 || sny > 10000 || snz < 1 || snz > 10000) {
97  egsWarning("%s: number of voxels seems strange: nx=%d, ny=%d, nz=%d\n",
98  func,snx,sny,snz);
99  return;
100  }
101  nx = snx;
102  ny = sny;
103  nz = snz;
104  nxy = nx*ny;
105  nreg = nxy*nz;
106  egsInformation("Distribution has %d x %d x %d voxels\n",nx,ny,nz);
107  float *x = new float [nx+1], *y = new float [ny+1], *z = new float [nz+1];
108  data.read((char *)x, (nx+1)*sizeof(float));
109  data.read((char *)y, (ny+1)*sizeof(float));
110  data.read((char *)z, (nz+1)*sizeof(float));
111  if (data.fail()) {
112  egsWarning("%s: failed to read voxel boundaries\n",func);
113  delete [] x;
114  delete [] y;
115  delete [] z;
116  return;
117  }
118  int nmap;
119  float *p;
120  if (form == 0) {
121  p = new float [nreg];
122  egsInformation("Format 0, reading %d values\n",nreg);
123  data.read((char *)p, nreg*sizeof(float));
124  if (data.fail()) {
125  egsWarning("%s: failed to read probabilities\n",func);
126  delete [] p;
127  delete [] x;
128  delete [] y;
129  delete [] z;
130  return;
131  }
132  nmap = nreg;
133  }
134  else {
135  egsInformation("Format 1, reading data\n");
136  data.read((char *)&nmap, sizeof(int));
137  if (data.fail() || nmap < 1) {
138  egsWarning("%s: failed to read nmap\n",func);
139  delete [] x;
140  delete [] y;
141  delete [] z;
142  return;
143  }
144  map = new int [nmap];
145  p = new float [nmap];
146  data.read((char *)map, nmap*sizeof(int));
147  data.read((char *)p, nmap*sizeof(float));
148  if (data.fail()) {
149  egsWarning("%s: failed to read probabilities and bin numbers\n",func);
150  delete [] p;
151  delete [] map;
152  delete [] x;
153  delete [] y;
154  delete [] z;
155  return;
156  }
157  }
158  EGS_Float *p1 = new EGS_Float [nmap];
159  int j;
160  for (j=0; j<nmap; ++j) {
161  p1[j] = p[j];
162  }
163  delete [] p;
164  egsInformation("Making alias table\n");
165  prob = new EGS_SimpleAliasTable(nmap,p1);
166  xpos = new EGS_Float [nx+1];
167  ypos = new EGS_Float [ny+1];
168  zpos = new EGS_Float [nz+1];
169  for (j=0; j<=nx; ++j) {
170  xpos[j] = x[j];
171  }
172  for (j=0; j<=ny; ++j) {
173  ypos[j] = y[j];
174  }
175  for (j=0; j<=nz; ++j) {
176  zpos[j] = z[j];
177  }
178  delete [] x;
179  delete [] y;
180  delete [] z;
181  type = form;
182  egsInformation("Done\n");
183 }
184 
185 EGS_VoxelizedShape::EGS_VoxelizedShape(int file_format, const char *fname,
186  const string &Name,EGS_ObjectFactory *f) : EGS_BaseShape(Name,f),
187  prob(0), xpos(0), ypos(0), zpos(0), map(0), nx(0), ny(0), nz(0), nxy(0),
188  nreg(0), type(-1) {
189  const static char *func = "EGS_VoxelizedShape::EGS_VoxelizedShape";
190  if (file_format == 0) { // binary file format -> call original constructor
191  string s(fname);
192  EGS_VoxelizedShapeFormat0(s.c_str());
193  return;
194  }
195  if (file_format != 1) { // unknown file format
196  egsWarning("%s: unknown file format = %d\n",func,file_format);
197  return;
198  }
199  // interfile format -> continue
200  otype = "voxelized_shape";
201  if (!fname) {
202  return;
203  }
204  ifstream h_file(fname);
205  if (!h_file) {
206  egsWarning("%s: failed to open file %s\n",func,fname);
207  return;
208  }
209  string data_file("");
210  int data_type = -1;
211  int Nx, Ny, Nz;
212  float scale_x=0.0, scale_y=0.0, scale_z=0.0;
213  for (EGS_I64 loopCount=0; loopCount<=loopMax; ++loopCount) {
214  if (loopCount == loopMax) {
215  egsFatal("EGS_VoxelizedShape::EGS_VoxelizedShape: Too many iterations were required! Input may be invalid, or consider increasing loopMax.");
216  return;
217  }
218  string line, key, value;
219  size_t pos;
220  getline(h_file, line);
221  if (h_file.eof() || h_file.fail() || !h_file.good()) {
222  break;
223  }
224  pos = line.find(":=");
225  if (pos == string::npos) {
226  continue;
227  }
228  key = line.substr(0, int(pos));
229  value = line.substr(int(pos)+2);
230  while ((key[0] == '!') || (key[0] == ' ')) {
231  key.erase(0,1);
232  }
233  while (key[key.length()-1] == ' ') {
234  key.erase(key.length()-1, 1);
235  }
236  while (value[0] == ' ') {
237  value.erase(0,1);
238  }
239  while (value[value.length()-1] == ' ') {
240  value.erase(value.length()-1, 1);
241  }
242  if (key == "matrix size [1]") {
243  sscanf(value.c_str(), "%u", &Nx);
244  }
245  else if (key == "matrix size [2]") {
246  sscanf(value.c_str(), "%u", &Ny);
247  }
248  else if ((key == "number of slices") || (key == "number of images")) {
249  sscanf(value.c_str(), "%u", &Nz);
250  }
251  else if (key == "scaling factor (mm/pixel) [1]") {
252  sscanf(value.c_str(), "%f", &scale_x);
253  }
254  else if (key == "scaling factor (mm/pixel) [2]") {
255  sscanf(value.c_str(), "%f", &scale_y);
256  }
257  else if (key == "slice thickness (pixels)") {
258  sscanf(value.c_str(), "%f", &scale_z); // ????????????????
259  }
260  else if (key == "name of data file") {
261  data_file = value;
262  }
263  else if (key == "number format") {
264  if ((value == "float") || (value == "FLOAT")) {
265  data_type = 0;
266  }
267  else if ((value == "unsigned integer") || (value == "UNSIGNED INTEGER")) {
268  data_type = 1;
269  }
270  else if ((value == "signed integer") || (value == "SIGNED INTEGER")) {
271  data_type = 2;
272  }
273  else {
274  egsWarning("%s: unrecognised 'number format' type: %s \n",func,value.c_str());
275  }
276  }
277  }
278  if (Nx < 1 || Ny < 1 || Nz < 1 || scale_x <= 0.0 || scale_y <= 0.0 || scale_z <= 0.0 || data_file == "" || data_type == -1) {
279  egsWarning("%s: invalid interfile header information: "
280  "Nx=%d Ny=%d Nz=%d scale_x=%f scale_y=%f scale_z=%f "
281  "data_file='%s' number_format=%d\n",func,Nx,Ny,Nz,scale_x,scale_y,scale_z,data_file.c_str(),data_type);
282  return;
283  }
284  nx = Nx;
285  ny = Ny;
286  nz = Nz;
287  nxy = nx*ny;
288  nreg = nxy*nz;
289  egsInformation("Distribution has %d x %d x %d voxels\n",nx,ny,nz);
290  float *x = new float [nx+1], *y = new float [ny+1], *z = new float [nz+1];
291  scale_x /= 10.0;
292  scale_y /= 10.0;
293  scale_z /= 10.0; // convert to cm
294  {
295  int j;
296  for (j=0; j<=nx; j++) {
297  x[j] = -(float)nx*scale_x/2.0 + j*scale_x;
298  }
299  for (j=0; j<=ny; j++) {
300  y[j] = -(float)ny*scale_y/2.0 + j*scale_y;
301  }
302  for (j=0; j<=nz; j++) {
303  z[j] = -(float)nz*scale_z/2.0 + j*scale_z;
304  }
305  }
306  ifstream i_file(data_file.c_str(),ios::binary);
307  if (!i_file) {
308  egsWarning("%s: failed to open interfile data "
309  "%s\n",func,data_file.c_str());
310  return;
311  }
312  int nmap = nreg;
313  float *p = new float [nreg];
314  if (data_type == 0) {
315  i_file.read((char *)p, nreg*sizeof(float));
316  }
317  else if (data_type == 1) {
318  unsigned short int *p_tmp = new unsigned short int [nreg];
319  i_file.read((char *)p_tmp, nreg*sizeof(unsigned short int));
320  for (int cc = 0; cc<nreg; cc++) {
321  p[cc] = (float)(p_tmp[cc]);
322  }
323  delete [] p_tmp;
324  }
325  else {
326  short int *p_tmp = new short int [nreg];
327  i_file.read((char *)p_tmp, nreg*sizeof(short int));
328  for (int cc = 0; cc<nreg; cc++) {
329  p[cc] = (float)(p_tmp[cc]);
330  }
331  delete [] p_tmp;
332  }
333  EGS_Float *p1 = new EGS_Float [nmap];
334  int j;
335  for (j=0; j<nmap; ++j) {
336  p1[j] = p[j];
337  }
338  delete [] p;
339  egsInformation("Making alias table\n");
340  prob = new EGS_SimpleAliasTable(nmap,p1);
341  xpos = new EGS_Float [nx+1];
342  ypos = new EGS_Float [ny+1];
343  zpos = new EGS_Float [nz+1];
344  for (j=0; j<=nx; ++j) {
345  xpos[j] = x[j];
346  }
347  for (j=0; j<=ny; ++j) {
348  ypos[j] = y[j];
349  }
350  for (j=0; j<=nz; ++j) {
351  zpos[j] = z[j];
352  egsInformation("%f ", zpos[j]);
353  }
354  delete [] x;
355  delete [] y;
356  delete [] z;
357  type = 0;
358  egsInformation("Done\n");
359 }
360 
361 EGS_VoxelizedShape::~EGS_VoxelizedShape() {
362  if (isValid()) {
363  delete prob;
364  delete [] xpos;
365  delete [] ypos;
366  delete [] zpos;
367  if (type == 1) {
368  delete [] map;
369  }
370  }
371 }
372 
373 
374 extern "C" {
375 
376  static void setInputs() {
377  inputSet = true;
378 
379  setShapeInputs(shapeBlockInput);
380  shapeBlockInput->getSingleInput("library")->setValues({"egs_voxelized_shape"});
381 
382  shapeBlockInput->addSingleInput("file name", true, "The filename for a binary file that contains sampling probabilities for an XYZ voxel grid. See the documentation for file format details.");
383  }
384 
385  EGS_VOXELIZED_SHAPE_EXPORT string getExample() {
386  string example;
387  example = {
388  R"(
389  # Example of egs_voxelized_shape
390  #:start shape:
391  library = egs_voxelized_shape
392  file name = some_file
393  :stop shape:
394 )"};
395  return example;
396  }
397 
398  EGS_VOXELIZED_SHAPE_EXPORT shared_ptr<EGS_BlockInput> getInputs() {
399  if(!inputSet) {
400  setInputs();
401  }
402  return shapeBlockInput;
403  }
404 
405  EGS_VOXELIZED_SHAPE_EXPORT EGS_BaseShape *createShape(EGS_Input *input,
406  EGS_ObjectFactory *f) {
407 
408  static const char *func = "createShape(voxelized shape)";
409  if (!input) {
410  egsWarning("%s: null input?\n",func);
411  return 0;
412  }
413  string fname;
414  int err = input->getInput("file name",fname);
415  int file_format;
416  int err2 = input->getInput("file format",file_format);
417  if (err) {
418  egsWarning("%s: missing 'file name' input\n",func);
419  return 0;
420  }
421  if (err2) {
422  egsInformation("%s: 'file format' input missing. Using default 'binary'"
423  "file format \n",func);
424  file_format = 0;
425  }
426  EGS_VoxelizedShape *shape = new EGS_VoxelizedShape(file_format, fname.c_str());
427  if (!shape->isValid()) {
428  delete shape;
429  return 0;
430  }
431  shape->setName(input);
432  shape->setTransformation(input);
433  return shape;
434  }
435 }
Base shape class. All shapes in the EGSnrc C++ class library are derived from EGS_BaseShape.
Definition: egs_shapes.h:145
void setTransformation(EGS_Input *inp)
Set the transformation attached to this shape.
Definition: egs_shapes.cpp:69
A class for storing information in a tree-like structure of key-value pairs. This class is used throu...
Definition: egs_input.h:182
int getInput(const string &key, vector< string > &values) const
Assign values to an array of strings from an input identified by key.
Definition: egs_input.cpp:341
An object factory.
void setName(EGS_Input *inp)
Set the name of the object from the information provided by inp.
string otype
The object type.
A class for sampling random bins from a given probability distribution using the alias table techniqu...
A "voxelized shape".
EGS_Float * zpos
! The y-positions of the grid
EGS_Float * xpos
! The alias table for randomly picking voxels
int * map
! The z-positions of the grid
EGS_Float * ypos
! The x-positions of the grid
int nx
! Voxel map (for type=1)
EGS_VoxelizedShape(int file_format, const char *fname, const string &Name="", EGS_ObjectFactory *f=0)
Conctructor.
Global egspp functions header file.
EGS_Input class header file.
A "voxelized shape": header.
int egsGetEndian()
Get the endianess of the machine.
EGS_InfoFunction EGS_EXPORT egsInformation
Always use this function for reporting the progress of a simulation and any other type of information...
EGS_InfoFunction EGS_EXPORT egsFatal
Always use this function for reporting fatal errors.
const EGS_I64 loopMax
The maximum number of iterations for near-infinite loops.
Definition: egs_functions.h:96
EGS_InfoFunction EGS_EXPORT egsWarning
Always use this function for reporting warnings.