EGSnrc C++ class library  Report PIRS-898 (2021)
Iwan Kawrakow, Ernesto Mainegra-Hing, Frederic Tessier, Reid Townson and Blake Walters
egs_vhp_geometry.cpp
Go to the documentation of this file.
1 /*
2 ###############################################################################
3 #
4 # EGSnrc egs++ voxelized human phantom geometry
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, 2008
25 #
26 # Contributors: Frederic Tessier
27 # Hubert Ho
28 # Marc Chamberland
29 #
30 ###############################################################################
31 #
32 # A "Voxelized Human Phantom" (VHP) geometry.
33 #
34 # Although a VHP geometry is just a XYZ geometry, due to the huge number of
35 # voxels one has to be more careful with memory use for media indices, etc.
36 # That's why this separate geometry implementation. With Richard Kramer's
37 # phantom data the implementation requires ~12 MB to hold all the organ data
38 # in memory. Richard's ASCII phantom data was also transformed into binary
39 # format with the result that loading them is almost instantaneous.
40 #
41 # For now the implementation only provides the macro geometry, i.e., no
42 # spongiosa micro matrices. Adding the micro matrices is the next step.
43 #
44 ###############################################################################
45 */
46 
47 
53 #include "egs_vhp_geometry.h"
54 #include "egs_input.h"
55 #include "egs_functions.h"
56 
57 #include <vector>
58 #include <fstream>
59 #ifndef NO_SSTREAM
60  #include <sstream>
61  #define S_STREAM std::istringstream
62 #else
63  #include <strstream>
64  #define S_STREAM std::istrstream
65 #endif
66 
67 
68 using namespace std;
69 
70 static bool EGS_VHP_LOCAL inputSet = false;
71 
72 #ifndef SKIP_DOXYGEN
73 EGS_VoxelInfo *EGS_VoxelGeometry::v = 0;
74 int EGS_VoxelGeometry::nv = 0;
75 
76 VHP_OrganData::VHP_OrganData(const char *fname, int slice_min, int slice_max)
77  : nslice(0), ok(false) {
78  ifstream data(fname,ios::binary);
79  if (!data) {
80  egsWarning("VHP_OrganData: failed to open file %s for reading\n",
81  fname);
82  return;
83  }
84  char endian;
85  data.read(&endian,sizeof(endian));
86  char my_endian = egsGetEndian();
87  if (endian != my_endian) {
88  egsWarning("VHP_OrganData: wrong endianess. \n"
89  "This machine has endianess %d, data was written on %d\n"
90  "This requires byte swaping, which has not been implemented yet\n",
91  (int)my_endian,(int)endian);
92  return;
93  }
94  data.read((char *)&dx, sizeof(dx));
95  data.read((char *)&dy, sizeof(dy));
96  data.read((char *)&dz, sizeof(dz));
97  data.read((char *)&nslice,sizeof(nslice));
98  if (slice_min < 0) {
99  slice_min = 0;
100  }
101  if (slice_max > nslice) {
102  slice_max = nslice;
103  }
104  int nwant = slice_max - slice_min;
105  slices = new VHP_SliceInfo [nwant];
106  nx = 0, ny = 0;
107  int is = 0;
108  for (int islice=0; islice<nslice; ++islice) {
109  if (islice >= slice_min) {
110  slices[is].readData(data);
111  int ni, nj;
112  slices[is++].getSliceDimensions(ni,nj);
113  if (ni > nx) {
114  nx = ni;
115  }
116  if (nj > ny) {
117  ny = nj;
118  }
119  }
120  else {
121  VHP_SliceInfo tmp;
122  tmp.readData(data);
123  }
124  if (islice == slice_max - 1) {
125  break;
126  }
127  }
128  nxy = nx*ny;
129  nslice = slice_max - slice_min;
130  if (data.fail()) {
131  egsWarning("VHP_OrganData: I/O error while reading data\n");
132  }
133  else {
134  ok = true;
135  }
136 }
137 
138 VHP_OrganData::~VHP_OrganData() {
139  if (nslice) {
140  delete [] slices;
141  }
142 }
143 
144 void VHP_RowInfo::readData(istream &in) {
145  unsigned short n;
146  in.read((char *)&n,sizeof(n));
147  if (n != nbin) {
148  if (nbin > 0) {
149  delete [] pix;
150  delete [] org;
151  nbin = 0;
152  }
153  }
154  if (n < 1) {
155  return;
156  }
157  if (!nbin) {
158  nbin = n;
159  pix = new unsigned short [nbin+1];
160  org = new unsigned char [nbin];
161  }
162  in.read((char *)pix,(nbin+1)*sizeof(unsigned short));
163  in.read((char *)org,nbin*sizeof(unsigned char));
164 }
165 
166 void VHP_SliceInfo::readData(istream &in) {
167  if (rinfo) {
168  delete [] rinfo;
169  rinfo = 0;
170  }
171  in.read((char *)&firstr,sizeof(firstr));
172  in.read((char *)&lastr,sizeof(lastr));
173  int nrow = lastr-firstr+1;
174  if (nrow > 0) {
175  rinfo = new VHP_RowInfo [nrow];
176  for (int j=0; j<nrow; ++j) {
177  rinfo[j].readData(in);
178  }
179  }
180 }
181 #endif
182 
183 EGS_VHPGeometry::EGS_VHPGeometry(const char *phantom_file,
184  const char *media_file, int slice_min, int slice_max,
185  const string &Name) :
186  EGS_BaseGeometry(Name), vg(0), micros(0), nmicro(0) {
187  organs = new VHP_OrganData(phantom_file,slice_min,slice_max);
188  if (!organs->isOK()) {
189  egsWarning("EGS_VHPGeometry: failed to construct organ data\n");
190  delete organs;
191  organs = 0;
192  return;
193  }
194  ifstream med_data(media_file);
195  if (!med_data) {
196  egsWarning("EGS_VHPGeometry: failed to open media data file %s\n",
197  media_file);
198  delete organs;
199  organs = 0;
200  return;
201  }
202  int norg;
203  med_data >> norg;
204  if (norg < 1) {
205  egsWarning("EGS_VHPGeometry: %d organs in media data file %s?\n",
206  norg,media_file);
207  delete organs;
208  organs = 0;
209  return;
210  }
211  int j;
212  for (j=0; j<256; ++j) {
213  organ_media[j] = -1;
214  organ_names[j] = "Undefined";
215  organ_micro[j] = -1;
216  }
217  char buf[1024];
218  med_data.getline(buf,1023);
219  for (j=0; j<norg; ++j) {
220  int iorg, imed;
221  char c;
222  med_data >> iorg >> imed >> c;
223  med_data.getline(buf,1023);
224  if (iorg < 0 || iorg > 255)
225  egsWarning("EGS_VHPGeometry: bad organ number %d on line %d\n",
226  iorg,j+2);
227  else {
228  organ_media[iorg] = imed;
229  }
230  organ_names[iorg] = c;
231  organ_names[iorg] += buf;
232  }
233  int nmed;
234  med_data >> nmed;
235  med_data.getline(buf,1023);
236  vector<string> media_names;
237  vector<int> media_indeces;
238  for (j=0; j<nmed; ++j) {
239  med_data.getline(buf,1023);
240  string med(buf);
241  media_names.push_back(med);
242  media_indeces.push_back(EGS_BaseGeometry::addMedium(med));
243  }
244  egsInformation("EGS_VHPGeometry: media information\n");
245  for (j=0; j<nmed; ++j) {
246  egsInformation("Medium %s registered as medium number %d\n",
247  media_names[j].c_str(),media_indeces[j]);
248  }
249  for (j=0; j<256; ++j) {
250  if (organ_media[j] >= 0) {
251  if (organ_media[j] >= nmed) {
252  egsWarning("EGS_VHPGeometry: invalid medium index %d\n",
253  organ_media[j]);
254  }
255  else {
256  organ_media[j] = media_indeces[organ_media[j]];
257  }
258  }
259  }
260  EGS_Float dx, dy, dz;
261  int nx, ny, nz;
262  organs->getVoxelSizes(dx,dy,dz);
263  organs->getPhantomDimensions(nx,ny,nz);
264  vg = new EGS_VoxelGeometry(nx,ny,nz,dx,dy,dz);
265  nreg = nx*ny*nz;
266  nmacro = nreg;
267  egsInformation("Phantom size in voxels: x=%d y=%d z=%d\n",nx,ny,nz);
268  egsInformation("Voxel sizes: dx=%g dy=%g dz=%g\n",dx,dy,dz);
269 }
270 
271 void EGS_VHPGeometry::setMicros(EGS_Input *input) {
272  if (!vg || !organs) {
273  egsWarning("EGS_VHPGeometry::setMicros: called for an invalid "
274  "VHP geometry\n");
275  return;
276  }
277  if (!input->getInputItem("micro matrix")) {
278  egsWarning("EGS_VHPGeometry::setMicros: no micro matrix definitions\n");
279  return;
280  }
281  vector<EGS_MicroMatrixCluster *> mv;
282  string dir;
283  input->getInput("micro matrix folder",dir);
284  EGS_Float t_bsc;
285  bool ok = true;
286  const static char *err_msg =
287  "EGS_VHPGeometry::setMicros: wrong/missing '%s' input\n";
288  int err = input->getInput("BSC thickness",t_bsc);
289  if (err || t_bsc < 0) {
290  egsWarning(err_msg,"BSC thickness");
291  ok = false;
292  }
293  string tb_medium, bm_medium;
294  err = input->getInput("TB medium",tb_medium);
295  if (err) {
296  egsWarning(err_msg,"TB medium");
297  ok = false;
298  }
299  err = input->getInput("BM medium",bm_medium);
300  if (err) {
301  egsWarning(err_msg,"BM medium");
302  ok = false;
303  }
304  if (!ok) {
305  egsWarning("EGS_VHPGeometry::setMicros: wrong/missing inputs found\n"
306  " => no micro matrices set for use\n");
307  return;
308  }
309  int tb_med = addMedium(tb_medium), bm_med = addMedium(bm_medium);
310  vector<string> minput;
311  while (!input->getInput("micro matrix",minput)) {
312  delete input->takeInputItem("micro matrix");
313  if (minput.size() < 2) {
314  egsWarning("EGS_VHPGeometry::setMicros: 'micro matrix' input"
315  " requires at least two inputs => ignored\n");
316  continue;
317  }
318  string fname = dir.size() ? egsJoinPath(dir,minput[0]) : minput[0];
319  EGS_MicroMatrixCluster *mcluster = new EGS_MicroMatrixCluster(
320  vg->dx,vg->dy,vg->dz,t_bsc,tb_med,bm_med,fname.c_str());
321  if (!mcluster->isValid()) {
322  egsWarning("failed to construct micro cluster from %s\n",
323  fname.c_str());
324  delete mcluster;
325  }
326  else {
327  bool ok = true;
328  vector<int> orgs;
329  for (int i=1; i<minput.size(); ++i) {
330  S_STREAM s(minput[i].c_str());
331  int org;
332  s >> org;
333  if (s.fail()) {
334  egsWarning("EGS_VHPGeometry::setMicros: invalid input %s "
335  "for micro matrix %s\n",minput[i].c_str(),
336  minput[0].c_str());
337  ok = false;
338  }
339  else {
340  if (org < 0 || org > 255) {
341  egsWarning("EGS_VHPGeometry::setMicros: invalid input"
342  " %d for micro matrix %s\n",org,minput[0].c_str());
343  ok = false;
344  }
345  else {
346  orgs.push_back(org);
347  }
348  }
349  }
350  if (ok) {
351  mv.push_back(mcluster);
352  egsInformation("Using micro matrix data from\n %s\nfor"
353  " organs:",fname.c_str());
354  for (int i=0; i<orgs.size(); ++i) {
355  egsInformation(" %d",orgs[i]);
356  organ_micro[orgs[i]] = mv.size()-1;
357  }
358  egsInformation("\n");
359  }
360  else {
361  delete mcluster;
362  }
363  }
364  }
365  if (mv.size() > 0) {
366  if (nmicro > 0) {
367  for (int i=0; i<nmicro; ++i) {
368  delete micros[i];
369  }
370  delete [] micros;
371  }
372  nmicro = mv.size();
373  micros = new EGS_MicroMatrixCluster* [nmicro];
374  nmax = 0;
375  for (int i=0; i<nmicro; ++i) {
376  micros[i] = mv[i];
377  int nr = micros[i]->nxy*micros[i]->nz;
378  int nm = micros[i]->mxy*micros[i]->mz;
379  if (nm*nr > nmax) {
380  nmax = nm*nr;
381  }
382  }
383  nmacro = vg->nxy*vg->nz;
384  EGS_I64 ntot = nmax;
385  ntot *= nmicro;
386  ntot += nmacro;
387  if (ntot > 2147483647) egsFatal("EGS_VHPGeometry::setMicros: "
388  "too many micro regions\n");
389  nreg = nmacro + nmax*nmicro;
390  egsInformation("Using regions 0...%d to identify macro voxels\n",
391  nmacro-1);
392  egsInformation("Using regions %d...%d to identify micro voxels\n",
393  nmacro,nreg-1);
394  }
395 }
396 
397 EGS_VHPGeometry::~EGS_VHPGeometry() {
398  if (organs) {
399  delete organs;
400  }
401  if (vg) {
402  delete vg;
403  }
404  if (nmicro > 0) {
405  for (int j=0; j<nmicro; ++j) {
406  delete micros[j];
407  }
408  delete [] micros;
409  }
410 
411 }
412 
413 void EGS_VHPGeometry::setMedia(EGS_Input *,int,const int *) {
414  egsWarning("EGS_VHPGeometry::setMedia: don't use this method.\n"
415  " Media are fixed by the organ data defining an VHP geometry\n");
416 }
417 
418 void EGS_VHPGeometry::printInfo() const {
420  if (isOK()) {
421  egsInformation(" voxel sizes: %g %g %g\n",vg->dx,vg->dy,vg->dz);
422  egsInformation(" phantom size: %d %d %d\n",vg->nx,vg->ny,vg->nz);
423  }
424  else {
425  egsInformation(" undefined VHP geometry\n");
426  }
427 }
428 
429 string EGS_VHPGeometry::type = "EGS_VHPGeometry";
430 
431 #ifndef SKIP_DOXYGEN
432 VHPBox EGS_MicroMatrixCluster::bm_boxes[64];
433 bool EGS_MicroMatrixCluster::bm_boxes_initialized = false;
434 
435 EGS_MicroMatrixCluster::EGS_MicroMatrixCluster(
436  EGS_Float Dx, EGS_Float Dy, EGS_Float Dz, EGS_Float bsc_thickness,
437  int tb_med, int bm_med, const char *micro_file) : med_tb(tb_med), med_bm(bm_med),
438  micros(0), vg(0) {
439  //
440  // *** open micro-matrix file
441  //
442  ifstream in(micro_file,ios::binary);
443  if (!in) {
444  egsWarning("EGS_MicroMatrixCluster: failed to open file %s\n",
445  micro_file);
446  return;
447  }
448 
449  //
450  // *** read data
451  //
452  unsigned char Mx, My, Mz;
453  in.read((char *)&Mx,sizeof(Mx));
454  in.read((char *)&My,sizeof(My));
455  in.read((char *)&Mz,sizeof(Mz));
456  mx = Mx;
457  my = My;
458  mz = Mz;
459  mxy = mx*my;
460  nmic = mxy*mz;
461  micros = new unsigned char *[nmic];
462  in.read((char *)&Mx,sizeof(Mx));
463  in.read((char *)&My,sizeof(My));
464  in.read((char *)&Mz,sizeof(Mz));
465  nx = Mx;
466  ny = My;
467  nz = Mz;
468  nxy = nx*ny;
469  int nxyz = nxy*nz, j;
470  nreg = nxyz;
471  {
472  for (int j=0; j<nmic; ++j) {
473  micros[j] = new unsigned char [nxyz];
474  in.read((char *)micros[j],nxyz*sizeof(unsigned char));
475  if (in.fail()) {
476  egsWarning("EGS_MicroMatrixCluster: I/O error while reading "
477  "%d'th micto-matrix from file %s\n",j+1,micro_file);
478  for (int i=0; i<=j; ++i) {
479  delete [] micros[j];
480  }
481  delete [] micros;
482  micros = 0;
483  return;
484  }
485  }
486  }
487 
488  //
489  // *** initialize micro- and macro-voxel sizes and numbers
490  //
491  dx = Dx;
492  dy = Dy;
493  dz = Dz;
494  dxi = 1/dx;
495  dyi = 1/dy;
496  dzi = 1/dz;
497  EGS_Float ddx = Dx/nx, ddy = Dy/ny, ddz = Dz/nz;
498  egsInformation("Macro voxel sizes: %g %g %g\n",dx,dy,dz);
499  egsInformation("Micro voxel sizes: %g %g %g\n",ddx,ddy,ddz);
500  egsInformation("Number of micros: %d %d %d\n",mx,my,mz);
501  egsInformation("Number of micro-voxles: %d %d %d\n",nx,ny,nz);
502 
503  //
504  // *** create an object for geometry computations
505  //
506  vg = new EGS_VoxelGeometry(nx,ny,nz,ddx,ddy,ddz);
507 
508  //
509  // *** initialize the 64 boxes needed for sub-micro-voxel energy deposition
510  // if needed
511  //
512  if (!bm_boxes_initialized) {
513  bm_boxes_initialized = true;
514  for (int ixm=0; ixm<2; ++ixm) {
515  EGS_Float xmin = bsc_thickness*ixm;
516  for (int ixp=0; ixp<2; ++ixp) {
517  EGS_Float xmax = ddx - bsc_thickness*ixp;
518  for (int iym=0; iym<2; ++iym) {
519  EGS_Float ymin = bsc_thickness*iym;
520  for (int iyp=0; iyp<2; ++iyp) {
521  EGS_Float ymax = ddy - bsc_thickness*iyp;
522  for (int izm=0; izm<2; ++izm) {
523  EGS_Float zmin = bsc_thickness*izm;
524  for (int izp=0; izp<2; ++izp) {
525  EGS_Float zmax = ddz - bsc_thickness*izp;
526  int ibox = ixm+2*ixp+4*iym+8*iyp+16*izm+32*izp;
527  bm_boxes[ibox].xmin = xmin;
528  bm_boxes[ibox].xmax = xmax;
529  bm_boxes[ibox].ymin = ymin;
530  bm_boxes[ibox].ymax = ymax;
531  bm_boxes[ibox].zmin = zmin;
532  bm_boxes[ibox].zmax = zmax;
533  }
534  }
535  }
536  }
537  }
538  }
539  }
540 
541  //
542  // *** process micro data. After this loop the mico-matrices will contain
543  // 0 for TB voxels
544  // 1 for BSC-only voxels (possible if BSC thickness > voxel size/2)
545  // 2 for BM-only voxels (i.e., no TB neighbours)
546  // >2 index of VHPBox corresponding to the BSC layers found in the voxel
547  //
548  // we also compute the TB, BM and BSC volumes
549  //
550  v_tb = new EGS_Float [nmic];
551  v_bm = new EGS_Float [nmic];
552  v_bsc = new EGS_Float [nmic];
553  double tot_tb = 0, tot_bm = 0, tot_bsc = 0;
554  for (j=0; j<nmic; ++j) {
555  int iz = j/mxy;
556  int iy = (j-iz*mxy)/mx;
557  int ix = j-iz*mxy-iy*mx;
558  int ixm = ix-1;
559  if (ixm < 0) {
560  ixm = mx-1;
561  }
562  int ixp = ix+1;
563  if (ixp >= mx) {
564  ixp = 0;
565  }
566  int iym = iy-1;
567  if (iym < 0) {
568  iym = my-1;
569  }
570  int iyp = iy+1;
571  if (iyp >= my) {
572  iyp = 0;
573  }
574  int izm = iz-1;
575  if (izm < 0) {
576  izm = mz-1;
577  }
578  int izp = iz+1;
579  if (izp >= mz) {
580  izp = 0;
581  }
582  EGS_Float bsc_vol = 0, bm_vol = 0, tb_vol = 0;
583  for (int jx=0; jx<nx; ++jx) {
584  for (int jy=0; jy<ny; ++jy) {
585  for (int jz=0; jz<nz; ++jz) {
586  int ireg = jx + jy*nx + jz*nxy;
587  if (micros[j][ireg]) {
588  int micxm = !(jx > 0 ? micros[j][ireg-1] :
589  micros[ixm+iy*mx+iz*mxy][nx-1+jy*nx+jz*nxy]);
590  int micxp = !(jx < nx-1 ? micros[j][ireg+1] :
591  micros[ixp+iy*mx+iz*mxy][jy*nx+jz*nxy]);
592  int micym = !(jy > 0 ? micros[j][ireg-nx] :
593  micros[ix+iym*mx+iz*mxy][jx+(ny-1)*nx+jz*nxy]);
594  int micyp = !(jy < ny-1 ? micros[j][ireg+nx] :
595  micros[ix+iyp*mx+iz*mxy][jx+jz*nxy]);
596  int miczm = !(jz > 0 ? micros[j][ireg-nxy] :
597  micros[ix+iy*mx+izm*mxy][jx+jy*nx+(nz-1)*nxy]);
598  int miczp = !(jz < nz-1 ? micros[j][ireg+nxy] :
599  micros[ix+iy*mx+izp*mxy][jx+jy*nx]);
600  if ((micxm && micxp && 2*bsc_thickness>ddx) ||
601  (micym && micyp && 2*bsc_thickness>ddy) ||
602  (miczm && miczp && 2*bsc_thickness>ddz)) {
603  micros[j][ireg] = 1; // i.e. all BSC
604  bsc_vol += 1;
605  }
606  else {
607  int ibox=micxm+2*micxp+4*micym+8*micyp+
608  16*miczm+32*miczp;
609  micros[j][ireg] = ibox + 2;
610  if (!ibox) {
611  bm_vol += 1;
612  }
613  else {
614  double v =
615  (bm_boxes[ibox].xmax-bm_boxes[ibox].xmin)*
616  (bm_boxes[ibox].ymax-bm_boxes[ibox].ymin)*
617  (bm_boxes[ibox].zmax-bm_boxes[ibox].zmin);
618  v /= (ddx*ddy*ddz);
619  bm_vol += v;
620  bsc_vol += 1 - v;
621  }
622  }
623  }
624  else {
625  tb_vol += 1;
626  }
627  }
628  }
629  }
630  egsInformation("Micro-matrix %d from %s:\n",j+1,micro_file);
631  egsInformation(" TB volume fraction: %g\n",tb_vol/nxyz);
632  egsInformation(" BM volume fraction: %g\n",bm_vol/nxyz);
633  egsInformation(" BSC volume fraction: %g\n",bsc_vol/nxyz);
634  egsInformation(" Total: %g\n",(tb_vol+bm_vol+bsc_vol)/nxyz);
635  v_tb[j] = tb_vol*ddx*ddy*ddz;
636  v_bm[j] = bm_vol*ddx*ddy*ddz;
637  v_bsc[j] = bsc_vol*ddx*ddy*ddz;
638  tot_tb += tb_vol;
639  tot_bm += bm_vol;
640  tot_bsc += bsc_vol;
641  }
642  egsInformation("Average volume fractions:\n");
643  egsInformation(" TB volume fraction: %g\n",tot_tb/(nmic*nxyz));
644  egsInformation(" BM volume fraction: %g\n",tot_bm/(nmic*nxyz));
645  egsInformation(" BSC volume fraction: %g\n",tot_bsc/(nmic*nxyz));
646 }
647 
648 EGS_MicroMatrixCluster::~EGS_MicroMatrixCluster() {
649 }
650 #endif
651 
652 EGS_TestMicro::EGS_TestMicro(EGS_Float Dx, EGS_Float Dy, EGS_Float Dz,
653  EGS_Float bsc_t,int tb_med, int bm_med,const char *micro_file,
654  const string &Name) : EGS_BaseGeometry(Name) {
655  micro = new EGS_MicroMatrixCluster(Dx,Dy,Dz,bsc_t,tb_med,bm_med,micro_file);
656  vg = new EGS_VoxelGeometry(micro->mx,micro->my,micro->mz,Dx,Dy,Dz);
657  nr = micro->nx*micro->ny*micro->nz;
658  nreg = nr*micro->mx*micro->my*micro->mz;
659 }
660 
661 void EGS_TestMicro::setMedia(EGS_Input *, int, const int *) {
662  egsFatal("EGS_TestMicro::setMedia(EGS_Input*,int,const int *):\n"
663  " Don't use this method. Media are only set via the micro matrix"
664  " data\n");
665 }
666 
667 EGS_TestMicro::~EGS_TestMicro() {
668 }
669 
670 string EGS_TestMicro::type = "EGS_TestMicro";
671 
672 const static EGS_VHP_LOCAL char *vhp_error_msg1 =
673  "createGeometry(VHP): wrong/missing %s input for micro_test geometry\n";
674 
675 extern "C" {
676 
677  static void setInputs() {
678  inputSet = true;
679 
680  setBaseGeometryInputs(false);
681 
682  geomBlockInput->getSingleInput("library")->setValues({"egs_vhp_geometry"});
683 
684  // Format: name, isRequired, description, vector string of allowed values
685  geomBlockInput->addSingleInput("phantom data", true, "The full filepath to the phantom data file, including the extension.");
686  geomBlockInput->addSingleInput("media data", true, "The full filepath to the media data file, including the extension.");
687  geomBlockInput->addSingleInput("slice range", false, "Two numbers, slice indices (indexed from 0). The first number must be smaller. Used to select a given slice range instead of using the entire phantom.");
688 
689  // For bone spongiosa
690  geomBlockInput->addSingleInput("BSC thickness", false, "The thickness of the bone surface cells layer, in cm.");
691  geomBlockInput->addSingleInput("TB medium", false, "The trabecular bone medium name.");
692  geomBlockInput->addSingleInput("BM medium", false, "The bone marrow medium name.");
693  geomBlockInput->addSingleInput("micro matrix", false, "The binary micro matrix filename followed by organ indices (defined in the media data file).");
694  }
695 
696  EGS_VHP_EXPORT string getExample() {
697  string example;
698  example = {
699  R"(
700  # For file format definitions and more inputs, see the documentation.
701  #:start geometry:
702  library = egs_vhp_geometry
703  name = some_name
704  phantom data = phantom_data_file
705  media data = media_data_file
706  slice range = min_slice max_slice
707  :stop geometry:
708 )"};
709  return example;
710  }
711 
712  EGS_VHP_EXPORT shared_ptr<EGS_BlockInput> getInputs() {
713  if(!inputSet) {
714  setInputs();
715  }
716  return geomBlockInput;
717  }
718 
719  EGS_VHP_EXPORT EGS_BaseGeometry *createGeometry(EGS_Input *input) {
720  string type;
721  int err = input->getInput("type",type);
722  if (!err && type == "micro_test") {
723  bool ok = true;
724  vector<EGS_Float> vs;
725  err = input->getInput("voxel sizes",vs);
726  if (err || vs.size() != 3) {
727  egsWarning(vhp_error_msg1,"'voxel sizes'");
728  ok = false;
729  }
730  EGS_Float bsc_t;
731  err = input->getInput("BSC thickness",bsc_t);
732  if (err) {
733  egsWarning(vhp_error_msg1,"'BSC thickness'");
734  ok = false;
735  }
736  string tb_medium, bm_medium;
737  int err1 = input->getInput("TB medium",tb_medium);
738  int err2 = input->getInput("BM medium",bm_medium);
739  if (err1) {
740  egsWarning(vhp_error_msg1,"'TB medium'");
741  }
742  if (err2) {
743  egsWarning(vhp_error_msg1,"'BM medium'");
744  }
745  if (err1 || err2) {
746  ok = false;
747  }
748  string micro_data;
749  err = input->getInput("micro data file",micro_data);
750  if (err) {
751  egsWarning(vhp_error_msg1,"'micro data file'");
752  ok = false;
753  }
754  if (!ok) {
755  return 0;
756  }
757  int tb_med = EGS_BaseGeometry::addMedium(tb_medium);
758  int bm_med = EGS_BaseGeometry::addMedium(bm_medium);
759  EGS_TestMicro *result = new EGS_TestMicro(vs[0],vs[1],vs[2],bsc_t,
760  tb_med,bm_med,micro_data.c_str());
761  result->setName(input);
762  result->setBoundaryTolerance(input);
763  result->setLabels(input);
764  return result;
765  }
766  string phantom, media;
767  int err1 = input->getInput("phantom data",phantom);
768  int err2 = input->getInput("media data",media);
769  if (err1) egsWarning("createGeometry(EGS_VHPGeometry): "
770  "missing 'phantom data' input\n");
771  if (err2) egsWarning("createGeometry(EGS_VHPGeometry): "
772  "missing 'media data' input\n");
773  if (err1 || err2) {
774  return 0;
775  }
776  vector<int> srange;
777  err1 = input->getInput("slice range",srange);
778  EGS_VHPGeometry *result;
779  if (!err1 && srange.size() == 2 && srange[1] > srange[0]) result =
780  new EGS_VHPGeometry(phantom.c_str(),media.c_str(),srange[0],srange[1]);
781  else {
782  result = new EGS_VHPGeometry(phantom.c_str(),media.c_str());
783  }
784  if (!result->isOK()) {
785  egsWarning("createGeometry(EGS_VHPGeometry): failed to construct "
786  "geometry");
787  delete result;
788  return 0;
789  }
790  result->setName(input);
791  result->setBoundaryTolerance(input);
792  result->setMicros(input);
793  result->setLabels(input);
794  return result;
795  }
796 
797 }
Base geometry class. Every geometry class must be derived from EGS_BaseGeometry.
int nreg
Number of local regions in this geometry.
void setName(EGS_Input *inp)
Set the name of the geometry from the input inp.
int setLabels(EGS_Input *input)
Set the labels from an input block.
virtual void printInfo() const
Print information about this geometry.
static int addMedium(const string &medname)
Add a medium or get the index of an existing medium.
void setBoundaryTolerance(EGS_Input *inp)
Set the value of the boundary tolerance from the input inp.
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_Input * takeInputItem(const string &key, bool self=true)
Get the property named key.
Definition: egs_input.cpp:229
EGS_Input * getInputItem(const string &key) const
Same as the previous function but now ownership remains with the EGS_Input object.
Definition: egs_input.cpp:248
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
A Voxelized Human Phantom (VHP) geometry.
Global egspp functions header file.
EGS_GLIB_EXPORT EGS_BaseGeometry * createGeometry(EGS_Input *input)
Definition: egs_glib.cpp:84
EGS_Input class header file.
Voxelized Human Phantom (VHP) geometry: 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.
string egsJoinPath(const string &first, const string &second)
Join two path variables (or a path and a file name) using the platform specific directory separator a...
EGS_InfoFunction EGS_EXPORT egsWarning
Always use this function for reporting warnings.