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 #
28 ###############################################################################
29 */
30 
31 
37 #include "egs_voxelized_shape.h"
38 #include "egs_input.h"
39 #include "egs_functions.h"
40 
41 #include <fstream>
42 using namespace std;
43 
44 void EGS_VoxelizedShape::EGS_VoxelizedShapeFormat0(const char *fname,
45  const string &Name,EGS_ObjectFactory *f) {
46  prob=0;
47  xpos=0;
48  ypos=0;
49  zpos=0;
50  map=0;
51  nx=0;
52  ny=0;
53  nz=0;
54  nxy=0;
55  nreg=0;
56  type=-1;
57  const static char *func = "EGS_VoxelizedShape::EGS_VoxelizedShape";
58  otype = "voxelized_shape";
59  if (!fname) {
60  return;
61  }
62  ifstream data(fname,ios::binary);
63  if (!data) {
64  egsWarning("%s: failed to open file %s\n",func,fname);
65  return;
66  }
67  char endian, form;
68  data.read(&endian,1);
69  data.read(&form,1);
70  if (data.fail()) {
71  egsWarning("%s: failed to read endianess and format from %s\n",func,fname);
72  return;
73  }
74  if (form < 0 || form > 1) {
75  egsWarning("%s: unknwon format %d found in file %s\n",func,(int)form,fname);
76  return;
77  }
78  if (endian != egsGetEndian()) {
79  egsWarning("%s: data in %s from a machine with different endianess.\n"
80  " Byte swaping not implemented yet.\n",func,fname);
81  return;
82  }
83  short snx, sny, snz;
84  data.read((char *)&snx,sizeof(short));
85  data.read((char *)&sny,sizeof(short));
86  data.read((char *)&snz,sizeof(short));
87  if (data.fail()) {
88  egsWarning("%s: failed to read number of voxels from %s\n",func,fname);
89  return;
90  }
91  if (snx < 1 || snx > 10000 || sny < 1 || sny > 10000 || snz < 1 || snz > 10000) {
92  egsWarning("%s: number of voxels seems strange: nx=%d, ny=%d, nz=%d\n",
93  func,snx,sny,snz);
94  return;
95  }
96  nx = snx;
97  ny = sny;
98  nz = snz;
99  nxy = nx*ny;
100  nreg = nxy*nz;
101  egsInformation("Distribution has %d x %d x %d voxels\n",nx,ny,nz);
102  float *x = new float [nx+1], *y = new float [ny+1], *z = new float [nz+1];
103  data.read((char *)x, (nx+1)*sizeof(float));
104  data.read((char *)y, (ny+1)*sizeof(float));
105  data.read((char *)z, (nz+1)*sizeof(float));
106  if (data.fail()) {
107  egsWarning("%s: failed to read voxel boundaries\n",func);
108  delete [] x;
109  delete [] y;
110  delete [] z;
111  return;
112  }
113  int nmap;
114  float *p;
115  if (form == 0) {
116  p = new float [nreg];
117  egsInformation("Format 0, reading %d values\n",nreg);
118  data.read((char *)p, nreg*sizeof(float));
119  if (data.fail()) {
120  egsWarning("%s: failed to read probabilities\n",func);
121  delete [] p;
122  delete [] x;
123  delete [] y;
124  delete [] z;
125  return;
126  }
127  nmap = nreg;
128  }
129  else {
130  egsInformation("Format 1, reading data\n");
131  data.read((char *)&nmap, sizeof(int));
132  if (data.fail() || nmap < 1) {
133  egsWarning("%s: failed to read nmap\n",func);
134  delete [] x;
135  delete [] y;
136  delete [] z;
137  return;
138  }
139  map = new int [nmap];
140  p = new float [nmap];
141  data.read((char *)map, nmap*sizeof(int));
142  data.read((char *)p, nmap*sizeof(float));
143  if (data.fail()) {
144  egsWarning("%s: failed to read probabilities and bin numbers\n",func);
145  delete [] p;
146  delete [] map;
147  delete [] x;
148  delete [] y;
149  delete [] z;
150  return;
151  }
152  }
153  EGS_Float *p1 = new EGS_Float [nmap];
154  int j;
155  for (j=0; j<nmap; ++j) {
156  p1[j] = p[j];
157  }
158  delete [] p;
159  egsInformation("Making alias table\n");
160  prob = new EGS_SimpleAliasTable(nmap,p1);
161  xpos = new EGS_Float [nx+1];
162  ypos = new EGS_Float [ny+1];
163  zpos = new EGS_Float [nz+1];
164  for (j=0; j<=nx; ++j) {
165  xpos[j] = x[j];
166  }
167  for (j=0; j<=ny; ++j) {
168  ypos[j] = y[j];
169  }
170  for (j=0; j<=nz; ++j) {
171  zpos[j] = z[j];
172  }
173  delete [] x;
174  delete [] y;
175  delete [] z;
176  type = form;
177  egsInformation("Done\n");
178 }
179 
180 EGS_VoxelizedShape::EGS_VoxelizedShape(int file_format, const char *fname,
181  const string &Name,EGS_ObjectFactory *f) : EGS_BaseShape(Name,f),
182  prob(0), xpos(0), ypos(0), zpos(0), map(0), nx(0), ny(0), nz(0), nxy(0),
183  nreg(0), type(-1) {
184  const static char *func = "EGS_VoxelizedShape::EGS_VoxelizedShape";
185  if (file_format == 0) { // binary file format -> call original constructor
186  string s(fname);
187  EGS_VoxelizedShapeFormat0(s.c_str());
188  return;
189  }
190  if (file_format != 1) { // unknown file format
191  egsWarning("%s: unknown file format = %d\n",func,file_format);
192  return;
193  }
194  // interfile format -> continue
195  otype = "voxelized_shape";
196  if (!fname) {
197  return;
198  }
199  ifstream h_file(fname);
200  if (!h_file) {
201  egsWarning("%s: failed to open file %s\n",func,fname);
202  return;
203  }
204  string data_file("");
205  int data_type = -1;
206  int Nx, Ny, Nz;
207  float scale_x=0.0, scale_y=0.0, scale_z=0.0;
208  for (EGS_I64 loopCount=0; loopCount<=loopMax; ++loopCount) {
209  if (loopCount == loopMax) {
210  egsFatal("EGS_VoxelizedShape::EGS_VoxelizedShape: Too many iterations were required! Input may be invalid, or consider increasing loopMax.");
211  return;
212  }
213  string line, key, value;
214  size_t pos;
215  getline(h_file, line);
216  if (h_file.eof() || h_file.fail() || !h_file.good()) {
217  break;
218  }
219  pos = line.find(":=");
220  if (pos == string::npos) {
221  continue;
222  }
223  key = line.substr(0, int(pos));
224  value = line.substr(int(pos)+2);
225  while ((key[0] == '!') || (key[0] == ' ')) {
226  key.erase(0,1);
227  }
228  while (key[key.length()-1] == ' ') {
229  key.erase(key.length()-1, 1);
230  }
231  while (value[0] == ' ') {
232  value.erase(0,1);
233  }
234  while (value[value.length()-1] == ' ') {
235  value.erase(value.length()-1, 1);
236  }
237  if (key == "matrix size [1]") {
238  sscanf(value.c_str(), "%u", &Nx);
239  }
240  else if (key == "matrix size [2]") {
241  sscanf(value.c_str(), "%u", &Ny);
242  }
243  else if ((key == "number of slices") || (key == "number of images")) {
244  sscanf(value.c_str(), "%u", &Nz);
245  }
246  else if (key == "scaling factor (mm/pixel) [1]") {
247  sscanf(value.c_str(), "%f", &scale_x);
248  }
249  else if (key == "scaling factor (mm/pixel) [2]") {
250  sscanf(value.c_str(), "%f", &scale_y);
251  }
252  else if (key == "slice thickness (pixels)") {
253  sscanf(value.c_str(), "%f", &scale_z); // ????????????????
254  }
255  else if (key == "name of data file") {
256  data_file = value;
257  }
258  else if (key == "number format") {
259  if ((value == "float") || (value == "FLOAT")) {
260  data_type = 0;
261  }
262  else if ((value == "unsigned integer") || (value == "UNSIGNED INTEGER")) {
263  data_type = 1;
264  }
265  else if ((value == "signed integer") || (value == "SIGNED INTEGER")) {
266  data_type = 2;
267  }
268  else {
269  egsWarning("%s: unrecognised 'number format' type: %s \n",func,value.c_str());
270  }
271  }
272  }
273  if (Nx < 1 || Ny < 1 || Nz < 1 || scale_x <= 0.0 || scale_y <= 0.0 || scale_z <= 0.0 || data_file == "" || data_type == -1) {
274  egsWarning("%s: invalid interfile header information: "
275  "Nx=%d Ny=%d Nz=%d scale_x=%f scale_y=%f scale_z=%f "
276  "data_file='%s' number_format=%d\n",func,Nx,Ny,Nz,scale_x,scale_y,scale_z,data_file.c_str(),data_type);
277  return;
278  }
279  nx = Nx;
280  ny = Ny;
281  nz = Nz;
282  nxy = nx*ny;
283  nreg = nxy*nz;
284  egsInformation("Distribution has %d x %d x %d voxels\n",nx,ny,nz);
285  float *x = new float [nx+1], *y = new float [ny+1], *z = new float [nz+1];
286  scale_x /= 10.0;
287  scale_y /= 10.0;
288  scale_z /= 10.0; // convert to cm
289  {
290  int j;
291  for (j=0; j<=nx; j++) {
292  x[j] = -(float)nx*scale_x/2.0 + j*scale_x;
293  }
294  for (j=0; j<=ny; j++) {
295  y[j] = -(float)ny*scale_y/2.0 + j*scale_y;
296  }
297  for (j=0; j<=nz; j++) {
298  z[j] = -(float)nz*scale_z/2.0 + j*scale_z;
299  }
300  }
301  ifstream i_file(data_file.c_str(),ios::binary);
302  if (!i_file) {
303  egsWarning("%s: failed to open interfile data "
304  "%s\n",func,data_file.c_str());
305  return;
306  }
307  int nmap = nreg;
308  float *p = new float [nreg];
309  if (data_type == 0) {
310  i_file.read((char *)p, nreg*sizeof(float));
311  }
312  else if (data_type == 1) {
313  unsigned short int *p_tmp = new unsigned short int [nreg];
314  i_file.read((char *)p_tmp, nreg*sizeof(unsigned short int));
315  for (int cc = 0; cc<nreg; cc++) {
316  p[cc] = (float)(p_tmp[cc]);
317  }
318  delete [] p_tmp;
319  }
320  else {
321  short int *p_tmp = new short int [nreg];
322  i_file.read((char *)p_tmp, nreg*sizeof(short int));
323  for (int cc = 0; cc<nreg; cc++) {
324  p[cc] = (float)(p_tmp[cc]);
325  }
326  delete [] p_tmp;
327  }
328  EGS_Float *p1 = new EGS_Float [nmap];
329  int j;
330  for (j=0; j<nmap; ++j) {
331  p1[j] = p[j];
332  }
333  delete [] p;
334  egsInformation("Making alias table\n");
335  prob = new EGS_SimpleAliasTable(nmap,p1);
336  xpos = new EGS_Float [nx+1];
337  ypos = new EGS_Float [ny+1];
338  zpos = new EGS_Float [nz+1];
339  for (j=0; j<=nx; ++j) {
340  xpos[j] = x[j];
341  }
342  for (j=0; j<=ny; ++j) {
343  ypos[j] = y[j];
344  }
345  for (j=0; j<=nz; ++j) {
346  zpos[j] = z[j];
347  egsInformation("%f ", zpos[j]);
348  }
349  delete [] x;
350  delete [] y;
351  delete [] z;
352  type = 0;
353  egsInformation("Done\n");
354 }
355 
356 EGS_VoxelizedShape::~EGS_VoxelizedShape() {
357  if (isValid()) {
358  delete prob;
359  delete [] xpos;
360  delete [] ypos;
361  delete [] zpos;
362  if (type == 1) {
363  delete [] map;
364  }
365  }
366 }
367 
368 
369 extern "C" {
370 
371  EGS_VOXELIZED_SHAPE_EXPORT EGS_BaseShape *createShape(EGS_Input *input,
372  EGS_ObjectFactory *f) {
373  static const char *func = "createShape(voxelized shape)";
374  if (!input) {
375  egsWarning("%s: null input?\n",func);
376  return 0;
377  }
378  string fname;
379  int err = input->getInput("file name",fname);
380  int file_format;
381  int err2 = input->getInput("file format",file_format);
382  if (err) {
383  egsWarning("%s: missing 'file name' input\n",func);
384  return 0;
385  }
386  if (err2) {
387  egsInformation("%s: 'file format' input missing. Using default 'binary'"
388  "file format \n",func);
389  file_format = 0;
390  }
391  EGS_VoxelizedShape *shape = new EGS_VoxelizedShape(file_format, fname.c_str());
392  if (!shape->isValid()) {
393  delete shape;
394  return 0;
395  }
396  shape->setName(input);
397  shape->setTransformation(input);
398  return shape;
399  }
400 
401 }
const EGS_I64 loopMax
The maximum number of iterations for near-infinite loops.
Definition: egs_functions.h:95
int nx
! Voxel map (for type=1)
void setTransformation(EGS_Input *inp)
Set the transformation attached to this shape.
Definition: egs_shapes.cpp:68
EGS_Input class header file.
Global egspp functions header file.
Base shape class. All shapes in the EGSnrc C++ class library are derived from EGS_BaseShape.
Definition: egs_shapes.h:112
EGS_VoxelizedShape(int file_format, const char *fname, const string &Name="", EGS_ObjectFactory *f=0)
Conctructor.
EGS_InfoFunction EGS_EXPORT egsFatal
Always use this function for reporting fatal errors.
A &quot;voxelized shape&quot;.
EGS_InfoFunction EGS_EXPORT egsInformation
Always use this function for reporting the progress of a simulation and any other type of information...
A class for sampling random bins from a given probability distribution using the alias table techniqu...
An object factory.
int egsGetEndian()
Get the endianess of the machine.
EGS_Float * xpos
! The alias table for randomly picking voxels
A &quot;voxelized shape&quot;: header.
void setName(EGS_Input *inp)
Set the name of the object from the information provided by inp.
EGS_Float * zpos
! The y-positions of the grid
int * map
! The z-positions of the grid
A class for storing information in a tree-like structure of key-value pairs. This class is used throu...
Definition: egs_input.h:182
EGS_Float * ypos
! The x-positions of the grid
string otype
The object type.
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:338
EGS_InfoFunction EGS_EXPORT egsWarning
Always use this function for reporting warnings.