EGSnrc C++ class library  Report PIRS-898 (2021)
Iwan Kawrakow, Ernesto Mainegra-Hing, Frederic Tessier, Reid Townson and Blake Walters
egs_base_geometry.cpp
Go to the documentation of this file.
1 /*
2 ###############################################################################
3 #
4 # EGSnrc egs++ base 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, 2005
25 #
26 # Contributors: Frederic Tessier
27 # Marc Chamberland
28 # Reid Townson
29 # Ernesto Mainegra-Hing
30 # Hugo Bouchard
31 # Hubert Ho
32 #
33 ###############################################################################
34 */
35 
36 
44 #include "egs_base_geometry.h"
45 #include "egs_functions.h"
46 #include "egs_library.h"
47 #include "egs_input.h"
48 #include "egs_application.h"
49 
50 #include <algorithm>
51 #include <vector>
52 #include <cstdio>
53 #include <cstdarg>
54 #include <cstdlib>
55 
56 using namespace std;
57 
58 typedef EGS_BaseGeometry *(*EGS_GeometryCreationFunction)(EGS_Input *);
59 
60 #ifndef SKIP_DOXYGEN
66 class EGS_LOCAL EGS_GeometryPrivate {
67 public:
68 
69  int nnow, ntot;
70  EGS_BaseGeometry **geoms;
71  vector<string> media;
72  vector<EGS_Library *> glibs;
73  static string geom_delimeter;
74  static string libkey;
75  static string create_key;
76  string dso_path;
77  EGS_Application *app;
78 
79  EGS_GeometryPrivate() : nnow(0), ntot(0), geoms(0), app(0) {
80  //egsInformation("EGS_GeometryPrivate() at 0x%x\n",this);
81  setUp();
82  };
83 
84  EGS_GeometryPrivate(const EGS_GeometryPrivate &p) :
85  nnow(0), ntot(0), geoms(0), app(0) {
86  //egsInformation("EGS_GeometryPrivate(0x%x) at 0x%x\n",&p,this);
87  setUp();
88  };
89 
90  void setUp() {
91  char *hhouse = getenv("HEN_HOUSE");
92  if (!hhouse) {
93  egsFatal("Environment variable HEN_HOUSE must be defined\n");
94  }
95  dso_path = hhouse;
96 #if defined WIN32 && !defined CYGWIN
97  char c = '\\';
98 #else
99  char c = '/';
100 #endif
101  if (dso_path[dso_path.size()-1] != c) {
102  dso_path += c;
103  }
104  //dso_path += "geometry"; dso_path += c;
105  dso_path += "egs++";
106  dso_path += c;
107  dso_path += "dso";
108  dso_path += c;
109  dso_path += CONFIG_NAME;
110  };
111 
112  ~EGS_GeometryPrivate() {
113  //egsInformation("Destructing EGS_GeometryPrivate at 0x%x, "
114  // "ntot=%d nnow=%d\n",this,ntot,nnow);
115  if (!ntot) {
116  return;
117  }
118  clearGeometries();
119  delete [] geoms;
120  //egsInformation("Deleting geometry libs\n");
121  {
122  for (unsigned int j=0; j<glibs.size(); j++) {
123  delete glibs[j];
124  }
125  }
126  };
127 
128  void clearGeometries() {
129  media.clear();
130  if (!ntot) {
131  return;
132  }
133  int j = 0, iloop = 0;
134  while (nnow > 0) {
135  if (geoms[j]->deref() == -1) {
136  removeGeometry(geoms[j]);
137  }
138  else {
139  geoms[j++]->ref();
140  }
141  if (j >= nnow && nnow) {
142  j = 0;
143  ++iloop;
144 
145  for (int i=0; i<nnow; ++i) {
146  if (!geoms[i]->deref()) {
147  removeGeometry(geoms[i]);
148  }
149  }
150 
151  if (iloop > 20) {
152 // egsWarning("~EGS_GeometryPrivate(): failed "
153 // "to delete all geometries after 20 loops!\n");
154 
155  break;
156  }
157  }
158  }
159  };
160 
161  void grow(int ngrow) {
162  ntot += ngrow;
163  EGS_BaseGeometry **tmp = new EGS_BaseGeometry* [ntot];
164  for (int j=0; j<nnow; j++) {
165  tmp[j] = geoms[j];
166  }
167  if (geoms) {
168  delete [] geoms;
169  }
170  geoms = tmp;
171  };
172 
173  int addGeometry(EGS_BaseGeometry *g) {
174  if (!g) {
175  return -1;
176  }
177  for (int j=0; j<nnow; j++) {
178  if (geoms[j]->getName() == g->getName()) {
179  return -1;
180  }
181  }
182  if (nnow >= ntot) {
183  grow(10);
184  }
185  geoms[nnow++] = g;
186  return nnow-1;
187 
188  };
189 
190  void removeGeometry(EGS_BaseGeometry *g) {
191  ntot--;
192  EGS_BaseGeometry **tmp = new EGS_BaseGeometry* [ntot];
193  int i=0;
194  for (int j=0; j<nnow; j++) {
195  if (geoms[j] != g) {
196  tmp[i++] = geoms[j];
197  }
198  }
199  if (geoms) {
200  delete [] geoms;
201  }
202  nnow--;
203  geoms = tmp;
204  };
205 
206  EGS_BaseGeometry *getGeometry(const string &name) {
207  for (int j=0; j<nnow; j++)
208  if (geoms[j]->getName() == name) {
209  return geoms[j];
210  }
211  return 0;
212  };
213 
214  int addMedium(const string &Name) {
215  if (EGS_Input::compare(Name,"vacuum")) {
216  return -1;
217  }
218  for (unsigned int j=0; j<media.size(); j++)
219  if (media[j] == Name) {
220  return j;
221  }
222  media.push_back(Name);
223  return media.size()-1;
224  };
225 
226  int getMediumIndex(const string &Name) {
227  for (unsigned int j=0; j<media.size(); j++)
228  if (media[j] == Name) {
229  return j;
230  }
231  return -1;
232  };
233 
234  int nMedia() const {
235  return media.size();
236  };
237 
238  const char *getMediumName(int ind) const {
239  if (ind < 0 || ind > media.size()-1) {
240  return 0;
241  }
242  return media[ind].c_str();
243  };
244 
245  void containsDynamic(bool &hasdynamic) {
246  hasdynamic = false;
247  };
248 
249  EGS_Float getMediumRho(int ind) const {
250  if (ind==-1) {
251  return -1;
252  }
253  else {
254  if (app) {
255  return app->getMediumRho(ind);
256  }
257  else {
258  return -1;
259  }
260  }
261  };
262 
263  void setApplication(EGS_Application *App) {
264  app = App;
265  };
266 
267  EGS_BaseGeometry *createSingleGeometry(EGS_Input *i);
268 
269 };
270 
271 class EGS_LOCAL EGS_PrivateGeometryLists {
272 public:
273  EGS_PrivateGeometryLists() : nnow(0), ntot(0) {
274  addList(new EGS_GeometryPrivate);
275  };
276  ~EGS_PrivateGeometryLists() {
277  //egsInformation("Deleting geometry lists\n");
278  if (ntot > 0) {
279  for (int j=0; j<nnow; j++) {
280  //egsInformation("Deleting list %d\n",j);
281  delete lists[j];
282  }
283  delete [] lists;
284  }
285  };
286  int size() const {
287  return nnow;
288  };
289  EGS_GeometryPrivate &operator[](int j) {
290  return *lists[j];
291  };
292  void addList(EGS_GeometryPrivate *l) {
293  if (!l) {
294  return;
295  }
296  if (nnow >= ntot) {
297  EGS_GeometryPrivate **tmp = new EGS_GeometryPrivate* [ntot+10];
298  for (int j=0; j<nnow; j++) {
299  tmp[j] = lists[j];
300  }
301  if (ntot > 0) {
302  delete [] lists;
303  }
304  lists = tmp;
305  ntot += 10;
306  }
307  lists[nnow++] = l;
308  };
309  int nnow, ntot;
310  EGS_GeometryPrivate **lists;
311 };
312 
313 string EGS_GeometryPrivate::geom_delimeter = "geometry definition";
314 string EGS_GeometryPrivate::libkey = "library";
315 string EGS_GeometryPrivate::create_key = "createGeometry";
316 #endif
317 
318 int EGS_BaseGeometry::active_glist = 0;
319 
320 static char buf_unique[32];
321 
323 
324 #ifndef SKIP_DOXYGEN
325 EGS_BaseGeometry *EGS_GeometryPrivate::createSingleGeometry(EGS_Input *i) {
326  string libname;
327  if (!i) {
328  egsWarning("createSingleGeometry: null input?\n");
329  return 0;
330  }
331  int error = i->getInput(EGS_GeometryPrivate::libkey,libname);
332  if (error) {
333  egsWarning("createSingleGeometry: input item %s does not define the"
334  " geometry library\n",i->name());
335  return 0;
336  }
337  EGS_Library *lib = 0;
338  for (unsigned int j=0; j<glibs.size(); j++) {
339  if (libname == glibs[j]->libraryName()) {
340  lib = glibs[j];
341  break;
342  }
343  }
344  if (!lib) {
345  lib = new EGS_Library(libname.c_str(),dso_path.c_str());
346  lib->load();
347  if (!lib->isLoaded()) {
348  egsWarning("createSingleGeometry: Failed to load library '%s' from"
349  " %s\n",libname.c_str(),dso_path.c_str());
350  return 0;
351  }
352  glibs.push_back(lib);
353  }
354  EGS_GeometryCreationFunction gcreate = (EGS_GeometryCreationFunction)
355  lib->resolve(EGS_GeometryPrivate::create_key.c_str());
356  if (!gcreate) {
357  egsWarning("createSingleGeometry: failed to resolve the %s function\n"
358  " in geometry library %s\n",
359  EGS_GeometryPrivate::create_key.c_str(),lib->libraryName());
360  return 0;
361  }
362  EGS_BaseGeometry *g = gcreate(i);
363  if (!g) {
364  egsWarning("createSingleGeometry: got null geometry\n");
365  egsWarning(" library: %s\n",lib->libraryName());
366  egsWarning(" input:\n");
367  i->print(4,cerr);
368  return 0;
369  }
370  if (!addGeometry(g)) {
371  egsWarning("createSingleGeometry: failed to add the geometry %s\n"
372  " to the list of geometries. This implies that a geometry with"
373  " this name already exists\n",g->getName().c_str());
374  delete g;
375  return 0;
376  }
377  return g;
378 
379 }
380 #endif
381 
382 //static EGS_LOCAL vector<EGS_GeometryPrivate> egs_geometries;
383 static EGS_LOCAL EGS_PrivateGeometryLists egs_geometries;
384 
385 EGS_Float EGS_BaseGeometry::howfarToOutside(int ireg, const EGS_Vector &x,
386  const EGS_Vector &u) {
387  if (ireg < 0) {
388  return 0;
389  }
390  EGS_Vector xx(x);
391  EGS_Float ttot = 0;
392  for (EGS_I64 loopCount=0; loopCount<=loopMax; ++loopCount) {
393  if (loopCount == loopMax) {
394  egsFatal("EGS_BaseGeometry::howfarToOutside: Too many iterations were required! Input may be invalid, or consider increasing loopMax.");
395  return 0;
396  }
397  EGS_Float t = veryFar;
398  int inew = howfar(ireg,xx,u,t);
399  ttot += t;
400  if (inew < 0) {
401  break;
402  }
403  xx += u*t;
404  ireg = inew;
405  }
406  return ttot;
407 }
408 
410  int n = egs_geometries.size();
411  //egsInformation("EGS_BaseGeometry::setActiveGeometryList: size=%d list=%d\n",
412  // n,list);
413  for (int j=n; j<=list; j++)
414  //egs_geometries.push_back(EGS_GeometryPrivate());
415  {
416  egs_geometries.addList(new EGS_GeometryPrivate);
417  }
418  active_glist = list;
419 }
420 
421 /*
422 extern "C" void __list_geometries() {
423  egsInformation("The following %d geometries are defined:\n",
424  egs_geometries[active_glist].nnow);
425  for(int j=0; j<egs_geometries[active_glist].nnow; j++) {
426  egsInformation("%d %s %s\n",j,
427  egs_geometries[active_glist].geoms[j]->getType().c_str(),
428  egs_geometries[active_glist].geoms[j]->getName().c_str());
429  }
430 }
431 */
432 
433 EGS_BaseGeometry::EGS_BaseGeometry(const string &Name) : nreg(0), name(Name),
434  region_media(0), med(-1), has_rho_scaling(false), rhor(0),
435  has_B_scaling(false), has_Ref_rho(false), bfactor(0), rhoRef(1.0),
436  nref(0), debug(false), is_convex(true), bproperty(0), bp_array(0),
437  boundaryTolerance(distanceEpsilon) {
438 
439  halfBoundaryTolerance = boundaryTolerance/2.;
440  if (!egs_geometries.size()) {
441  egs_geometries.addList(new EGS_GeometryPrivate);
442  }
443  if (!name.size()) {
444  name = getUniqueName();
445  }
446  if (egs_geometries[active_glist].addGeometry(this) < 0)
447  egsFatal("EGS_BaseGeometry::EGS_BaseGeometry:\n"
448  " a geometry with name %s already exists\n",name.c_str());
449 }
450 
452  if (region_media) {
453  delete [] region_media;
454  }
455  if (rhor && has_rho_scaling) {
456  delete [] rhor;
457  }
458  if (bp_array) {
459  delete [] bp_array;
460  }
461  if (bfactor && has_B_scaling) {
462  delete [] bfactor;
463  }
464  //egsInformation("Deleting geometry at 0x%x, list=%d\n",this,active_glist);
465  egs_geometries[active_glist].removeGeometry(this);
466 }
467 
469  egs_geometries[active_glist].clearGeometries();
470 }
471 
473  return egs_geometries[active_glist].getGeometry(Name);
474 }
475 
476 EGS_BaseGeometry **EGS_BaseGeometry::getGeometries() {
477  return egs_geometries[active_glist].geoms;
478 }
479 
480 int EGS_BaseGeometry::getNGeometries() {
481  return egs_geometries[active_glist].nnow;
482 }
483 
484 void EGS_BaseGeometry::setMedium(const string &Name) {
485  med = egs_geometries[active_glist].addMedium(Name);
486  if (region_media)
487  for (int j=0; j<nreg; j++) {
488  region_media[j] = med;
489  }
490 }
491 
492 int EGS_BaseGeometry::addMedium(const string &medname) {
493  return egs_geometries[active_glist].addMedium(medname);
494 }
495 
496 int EGS_BaseGeometry::getMediumIndex(const string &medname) {
497  return egs_geometries[active_glist].getMediumIndex(medname);
498 }
499 
500 void EGS_BaseGeometry::setMedium(int istart, int iend, const string &Name,
501  int delta) {
502  int imed = egs_geometries[active_glist].addMedium(Name);
503  setMedium(istart,iend,imed,delta);
504 }
505 
506 void EGS_BaseGeometry::setMedium(int istart, int iend, int imed, int delta) {
507  if (nreg <= 1) {
508  med = imed;
509  return;
510  }
511  if (delta <= 0) {
512  return;
513  }
514  if (istart < 0) {
515  istart = 0;
516  }
517  if (iend > nreg-1) {
518  iend = nreg-1;
519  }
520  if (!region_media) {
521  region_media = new short [nreg];
522  for (int j=0; j<nreg; j++) {
523  region_media[j] = med;
524  }
525  }
526  for (int j=istart; j<=iend; j+=delta) {
527  region_media[j] = imed;
528  }
529 }
530 
532  return egs_geometries[active_glist].nMedia();
533 }
534 
535 const char *EGS_BaseGeometry::getMediumName(int ind) {
536  return egs_geometries[active_glist].getMediumName(ind);
537 }
538 
539 EGS_Float EGS_BaseGeometry::getMediumRho(int ind) const {
540  return egs_geometries[active_glist].getMediumRho(ind);
541 }
542 
543 void EGS_BaseGeometry::setApplication(EGS_Application *App) {
544  return egs_geometries[active_glist].setApplication(App);
545 }
546 
548  return egs_geometries[active_glist].createSingleGeometry(input);
549 }
550 
552  EGS_Input *ginput = input;
553  bool delete_it = false;
554  if (!input->isA(egs_geometries[active_glist].geom_delimeter)) {
555  ginput = input->takeInputItem(egs_geometries[active_glist].geom_delimeter);
556  delete_it = true;
557  }
558  if (!ginput) {
559  egsWarning("EGS_BaseGeometry::createGeometry: no geometry specification"
560  " in this input\n");
561  return 0;
562  }
563  EGS_Input *ij;
564  bool error = false;
565  while ((ij = ginput->takeInputItem("geometry")) != 0) {
566  EGS_BaseGeometry *g = egs_geometries[active_glist].createSingleGeometry(ij);
567  if (!g) {
568  error = true;
569  }
570  delete ij;
571  }
572  // Check to make sure that geometries have unique names
573  for (int j=0; j<egs_geometries[active_glist].nnow; j++) {
574  string gname = egs_geometries[active_glist].geoms[j]->getName();
575  for (int k=0; k<egs_geometries[active_glist].nnow; k++) {
576  if (k == j) {
577  continue;
578  }
579  if (gname == egs_geometries[active_glist].geoms[k]->getName()) {
580  egsFatal("\ncreateGeometry: Error: multiple geometries with"
581  " the same name exist: %s\n\n", gname.c_str());
582  return 0;
583  }
584  }
585  }
586  if (error) {
587  egsFatal("EGS_BaseGeometry::createGeometry: errors during geometry"
588  " definition\n");
589  return 0;
590  }
591  string sim_geom;
592  int err = ginput->getInput("simulation geometry",sim_geom);
593  if (err) {
594  egsWarning("EGS_BaseGeometry::createGeometry: missing/wrong keyword"
595  " 'simulation geometry'\n");
596  return 0;
597  }
598  EGS_BaseGeometry *g = egs_geometries[active_glist].getGeometry(sim_geom);
599  if (!g) egsWarning("EGS_BaseGeometry::createGeometry: a geometry with "
600  "the name %s does not exist\n",sim_geom.c_str());
601  if (delete_it) {
602  delete ginput;
603  }
604  return g;
605 }
606 
608  sprintf(buf_unique,"geometry%d",egs_geometries[active_glist].nnow);
609  string result(buf_unique);
610  return result;
611 }
612 
614  int err = i->getInput("name",name);
615  if (err) {
616  name = getUniqueName();
617  }
618  EGS_Input *inp;
619  int irep=0;
620  while ((inp = i->takeInputItem("replica"))) {
621  string typ;
622  int ncopy;
623  vector<EGS_Float> trans, trans_o;
624  vector<EGS_Float> rot_axis;
625  EGS_Float rot_angle, rot_angle_o;
626  int err1 = inp->getInput("type",typ);
627  int err2 = inp->getInput("number of copies",ncopy);
628  int err3 = inp->getInput("translation delta",trans);
629  int err4 = inp->getInput("first translation",trans_o);
630  int err5 = inp->getInput("rotation axis",rot_axis);
631  int err6 = inp->getInput("rotation delta",rot_angle);
632  int err7 = inp->getInput("first rotation",rot_angle_o);
633  bool do_it = true;
634  int ttype;
635  if (err1 || err2) {
636  if (err1) egsWarning("geometry replication: 'type' not defined ->"
637  " ignoring input\n");
638  if (err2) egsWarning("geometry replication: 'number of copies' "
639  "not defined -> ignoring input\n");
640  do_it = false;
641  }
642  else {
643  if (ncopy < 1) {
644  egsWarning("geometry replication: %d copies?\n",ncopy);
645  do_it = false;
646  }
647  if (typ == "line") {
648  if (err3 || trans.size() != 3) {
649  egsWarning("geometry replication: got %d inputs for "
650  "'translation', need 3\n",trans.size());
651  do_it = false;
652  }
653  else {
654  if (err4) {
655  trans_o.push_back(0);
656  trans_o.push_back(0);
657  trans_o.push_back(0);
658  }
659  }
660  ttype = 0;
661  }
662  else if (typ == "rotation") {
663  if (err5 || rot_axis.size() != 3) {
664  egsWarning("geometry replication: got %d inputs for "
665  "'rotation axis', need 3\n",rot_axis.size());
666  do_it = false;
667  }
668  if (err6) {
669  egsWarning("geometry replication: missing 'rotation delta'"
670  " input\n");
671  do_it = false;
672  }
673  if (err7) {
674  rot_angle_o = 0;
675  }
676  ttype = 1;
677  }
678  else {
679  egsWarning("geometry replication: unknown replica type %s\n",
680  typ.c_str());
681  do_it = false;
682  }
683  }
684  if (do_it) {
685  ++irep;
686  char buf[1024];
687  for (int icopy=1; icopy<=ncopy; icopy++) {
688  //string content(":start geometry:\n");
689  string content;
690  content += " library = egs_gtransformed\n";
691  sprintf(buf," name = %s_rep%d_%d\n",name.c_str(),irep,icopy);
692  content += buf;
693  sprintf(buf," my geometry = %s\n",name.c_str());
694  content += buf;
695  content += " :start transformation:\n";
696  if (ttype == 0)
697  sprintf(buf," translation = %g %g %g\n",
698  trans_o[0]+trans[0]*icopy,
699  trans_o[1]+trans[1]*icopy,
700  trans_o[2]+trans[2]*icopy);
701  else
702  sprintf(buf," rotation = %g %g %g %g\n",
703  rot_axis[0],rot_axis[1],rot_axis[2],
704  rot_angle_o+rot_angle*icopy);
705  content += buf;
706  content += " :stop transformation:\n";
707  //content += ":stop geometry:\n";
708  EGS_Input aux;
709  aux.setContentFromString(content);
710  EGS_BaseGeometry *g =
712  if (!g) egsWarning("geometry replication: failed to create"
713  " replica %d of %s\n",icopy,name.c_str());
714  //else egsInformation("geometry replication: created replica"
715  // " %s\n",g->getName().c_str());
716  }
717  }
718  }
719 }
720 
722  int err = i->getInput("boundary tolerance", boundaryTolerance);
723  if (err > 0) {
724  egsWarning("EGS_BaseGeometry::setBoundaryTolerance(): error while reading 'boundary tolerance' input\n");
725  return;
726  }
727  halfBoundaryTolerance = boundaryTolerance/2.;
728 }
729 
731  egsInformation("======================== geometry =====================\n");
732  egsInformation(" type = %s\n",getType().c_str());
733  egsInformation(" name = %s\n",getName().c_str());
734  egsInformation(" number of regions = %d\n",nreg);
735  if (hasBScaling()) {
736  egsInformation("\nB scaling ON\n");
737  }
738 }
739 
741  egsInformation("\nThe following geometries are defined:\n\n");
742  for (int j=0; j<egs_geometries[active_glist].nnow; j++) {
743  egs_geometries[active_glist].geoms[j]->printInfo();
744  }
745 }
746 
748  EGS_Input *input = inp;
749  bool delete_it = false;
750  if (!input->isA("media input")) {
751  input = inp->takeInputItem("media input");
752  if (!input) {
753  return;
754  }
755  // i.e., if there is no media related input for this geometry,
756  // we don't warn as we assume that media will be set from the outside
757  delete_it = true;
758  }
759  vector<string> media_names;
760  int err = input->getInput("media",media_names);
761  int *med_ind = 0;
762  int nmed = media_names.size();
763  if (!err && nmed > 0) {
764  med_ind = new int [nmed];
765  for (int j=0; j<nmed; j++) {
766  med_ind[j] = egs_geometries[active_glist].addMedium(media_names[j]);
767  }
768  }
769  else {
770  nmed = nMedia();
771  if (nmed < 1) {
772  if (delete_it) {
773  delete input;
774  }
775  return;
776  }
777  med_ind = new int [nmed];
778  for (int j=0; j<nmed; j++) {
779  med_ind[j] = j;
780  }
781  }
782  setMedia(input,nmed,med_ind);
783  setRelativeRho(input);
784  setBScaling(input);
785  delete [] med_ind;
786  if (delete_it) {
787  delete input;
788  }
789 }
790 
791 void EGS_BaseGeometry::setMedia(EGS_Input *input, int nmed, const int *mind) {
792  EGS_Input *i;
793  med = mind[0];
794  while ((i = input->takeInputItem("set medium"))) {
795  vector<int> inp;
796  int err = i->getInput("set medium",inp);
797  delete i;
798  if (!err) {
799  //if( inp.size() == 2 ) setMedium(inp[0],inp[0]+1,mind[inp[1]]);
800  if (inp.size() == 2) {
801  setMedium(inp[0],inp[0],mind[inp[1]]);
802  }
803  else if (inp.size() == 3) {
804  setMedium(inp[0],inp[1],mind[inp[2]]);
805  }
806  else if (inp.size() == 4) {
807  setMedium(inp[0],inp[1],mind[inp[2]],inp[3]);
808  }
809  else egsWarning("EGS_BaseGeometry::setMedia(): found %d inputs\n"
810  "in a 'set medium' input. 2 or 3 are allowed\n",inp.size());
811  }
812  else egsWarning("EGS_BaseGeometry::setMedia(): wrong 'set medium'"
813  " input\n");
814  }
815 }
816 
817 void EGS_BaseGeometry::setRelativeRho(int start, int end, EGS_Float rho) {
818  if (start < 0) {
819  start = 0;
820  }
821  if (end >= nreg) {
822  end = nreg-1;
823  }
824  if (end >= start) {
825  int j;
826  if (!rhor) {
827  rhor = new EGS_Float [nreg];
828  for (j=0; j<nreg; j++) {
829  rhor[j] = 1;
830  }
831  }
832  for (j=start; j<=end; j++) {
833  rhor[j] = rho;
834  }
835  has_rho_scaling = true;
836  }
837 }
838 
840  EGS_Input *i;
841  while ((i = input->takeInputItem("set relative density"))) {
842  vector<EGS_Float> tmp;
843  int err = i->getInput("set relative density",tmp);
844  if (!err) {
845  if (tmp.size() == 2) {
846  int start = (int)(tmp[0]+0.1);
847  int end = start;
848  setRelativeRho(start,end,tmp[1]);
849  }
850  else if (tmp.size() == 3) {
851  int start = (int)(tmp[0]+0.1);
852  int end = (int)(tmp[1]+0.1);
853  setRelativeRho(start,end,tmp[2]);
854  }
855  else {
856  egsWarning("EGS_BaseGeometry::setRelativeRho(): found %d "
857  "inputs in a 'set relative density' input.\n",tmp.size());
858  egsWarning(" 2 or 3 are allowed => input ignored\n");
859  }
860  }
861  delete i;
862  }
863 }
864 
865 void EGS_BaseGeometry::setBScaling(int start, int end, EGS_Float bf) {
866  if (start < 0) {
867  start = 0;
868  }
869  if (end >= nreg) {
870  end = nreg-1;
871  }
872  if (end >= start) {
873  int j;
874  if (!bfactor) {
875  bfactor = new EGS_Float [nreg];
876  for (j=0; j<nreg; j++) {
877  bfactor[j] = 1.0;
878  }
879  }
880  for (j=start; j<=end; j++) {
881  bfactor[j] = bf;
882  }
883  has_B_scaling = true;
884  }
885 }
886 
888  EGS_Input *i;
889  /* Check whether scaling of the B field requested */
890  while ((i = input->takeInputItem("set B scaling"))) {
891  vector<EGS_Float> tmp;
892  int err = i->getInput("set B scaling",tmp);
893  if (!err) {
894  if (tmp.size() == 2) {
895  int start = (int)(tmp[0]+0.1);
896  int end = start;
897  setBScaling(start, end, tmp[1]);
898  }
899  else if (tmp.size() == 3) {
900  int start = (int)(tmp[0]+0.1);
901  int end = (int)(tmp[1]+0.1);
902  setBScaling(start, end, tmp[2]);
903  }
904  else {
905  egsWarning("EGS_BaseGeometry::setBScaling(): found %d "
906  "inputs in a 'set B scaling' input.\n", tmp.size());
907  egsWarning(" 2 or 3 are allowed => input ignored\n");
908  }
909  }
910  delete i;
911  }
912  /* Check whether mass density scaling of the B field requested */
913  EGS_Float refD;
914  int err0 = input->getInput("B scaling reference density", refD);
915  if (!err0) {
916  rhoRef = refD;
917  has_Ref_rho = true;
918  }
919 
920 }
921 
923  const EGS_Vector &u, EGS_GeometryIntersections *isections) {
924  if (n < 1) {
925  return -1;
926  }
927  int ifirst = 0;
928  EGS_Float t, ttot = 0;
929  EGS_Vector x(X);
930  int imed;
931  if (ireg < 0) {
932  t = veryFar;
933  ireg = howfar(ireg,x,u,t,&imed);
934  if (ireg < 0) {
935  return 0;
936  }
937  isections[0].t = t;
938  isections[0].rhof = 1;
939  isections[0].ireg = -1;
940  isections[0].imed = -1;
941  ttot = t;
942  ++ifirst;
943  x += u*t;
944  }
945  else {
946  imed = medium(ireg);
947  }
948 
949  for (int j=ifirst; j<n; j++) {
950  isections[j].imed = imed;
951  isections[j].rhof = getRelativeRho(ireg);
952  isections[j].ireg = ireg;
953  t = veryFar;
954  int inew = howfar(ireg,x,u,t,&imed);
955  ttot += t;
956  isections[j].t = ttot;
957  if (inew < 0 || inew == ireg) {
958  return j+1;
959  }
960  ireg = inew;
961  x += u*t;
962  }
963 
964  return ireg >= 0 ? -1 : n;
965 
966 }
967 
969  bproperty = prop;
970  if (bp_array) {
971  delete [] bp_array;
972  bp_array = 0;
973  }
974 }
975 
977  if (bit < 0 || bit >= 8*sizeof(EGS_BPType)) {
978  egsWarning("EGS_BaseGeometry::addBooleanProperty: attempt to set the "
979  "%d'th bith!\n",bit);
980  return;
981  }
982  EGS_BPType prop = 1 << bit;
983  bproperty |= prop;
984  if (bp_array) {
985  for (int j=0; j<nreg; j++) {
986  bp_array[j] |= prop;
987  }
988  }
989 }
990 
991 void EGS_BaseGeometry::setBooleanProperty(EGS_BPType prop, int start, int end,
992  int step) {
993  if (start < 0) {
994  start = 0;
995  }
996  if (end >= nreg) {
997  end = nreg-1;
998  }
999  if (start == 0 && end == nreg-1 && step==1) {
1000  setBooleanProperty(prop);
1001  }
1002  else {
1003  if (!bp_array) {
1004  bp_array = new EGS_BPType [nreg];
1005  for (int j=0; j<nreg; j++) {
1006  bp_array[j] = 0;
1007  }
1008  }
1009  for (int j=start; j<=end; j+=step) {
1010  bp_array[j] = prop;
1011  }
1012  }
1013 }
1014 
1015 void EGS_BaseGeometry::addBooleanProperty(int bit, int start, int end,
1016  int step) {
1017  if (bit < 0 || bit >= 8*sizeof(EGS_BPType)) {
1018  egsWarning("EGS_BaseGeometry::addBooleanProperty: attempt to set the "
1019  "%d'th bith!\n",bit);
1020  return;
1021  }
1022  if (start < 0) {
1023  start = 0;
1024  }
1025  if (end >= nreg) {
1026  end = nreg-1;
1027  }
1028  if (start == 0 && end == nreg-1 && step==1) {
1029  addBooleanProperty(bit);
1030  }
1031  else {
1032  EGS_BPType prop = 1 << bit;
1033  if (!bp_array) {
1034  bp_array = new EGS_BPType [nreg];
1035  for (int j=0; j<nreg; j++) {
1036  bp_array[j] = 0;
1037  }
1038  }
1039  for (int j=start; j<=end; j+=step) {
1040  bp_array[j] |= prop;
1041  }
1042  }
1043 }
1044 
1045 // This function should be overwritten in all composite geometries
1046 // It is not overwritten by egs_lattice because that geometry effectively creates many geometries with the same name, so there's no way to identify which one to use
1047 int EGS_BaseGeometry::getGlobalRegionOffset(const string geomName) {
1048  if (getName() == geomName) {
1049  // If this geometry hasn't overwritten getGlobalRegionOffset, then it doesn't add an offset
1050  return 0;
1051  }
1052  else {
1053  // If this is not the named geometry, return -1 for not found
1054  return -1;
1055  }
1056 }
1057 
1058 // Gets region numbers from a string
1059 // Pushes the regions onto the array regs
1060 void EGS_BaseGeometry::getNumberRegions(const string &str, vector<int> &regs) {
1061 
1062  if (!str.empty()) {
1063 
1064  // Tokenize the input string
1065  vector<string> tokens = egsTokenize(str);
1066 
1067  // Search for tokens that are numbers, not strings
1068  // Push the region numbers onto the regions array
1069  for (int i=0; i<tokens.size(); i++) {
1070  if (tokens[i].find_first_not_of("-0123456789") == std::string::npos) {
1071  regs.push_back(atoi(tokens[i].c_str()));
1072  }
1073  }
1074  }
1075 }
1076 
1077 void EGS_BaseGeometry::getLabelRegions(const string &str, vector<int> &regs, bool sanitize) {
1078 
1079  // Tokenize the input string
1080  vector<string> tokens = egsTokenize(str);
1081 
1082  // Start insertion at the beginning of regs
1083  size_t insert_pos = 0;
1084  bool foundLabel;
1085 
1086  // Get all regions lists for this named label
1087  for (int j = 0; j < tokens.size(); j++) {
1088  foundLabel = false;
1089  for (int i = 0; i < labels.size(); i++) {
1090  if (labels[i].name.compare(tokens[j]) == 0) {
1091 
1092  // Insert at the current position
1093  regs.insert(regs.begin() + insert_pos, labels[i].regions.begin(), labels[i].regions.end());
1094 
1095  // Update the insertion position to reflect the newly added elements
1096  insert_pos += labels[i].regions.size();
1097 
1098  foundLabel = true;
1099  break;
1100  }
1101  }
1102 
1103  // Just increment the insertion position by one, because this token was a number not a label.
1104  // Precondition: regs must be pre-populated by getNumberRegions() before calling this function
1105  // with sanitize=false, so that each non-label token has a corresponding entry already in regs.
1106  // Otherwise, advancing insert_pos will walk out of bounds.
1107  if (!foundLabel && regs.size() > 0) {
1108  if (insert_pos >= regs.size()) {
1109  egsFatal("EGS_BaseGeometry::getLabelRegions(): insert_pos out of bounds "
1110  "for geometry %s. Was getNumberRegions() called before "
1111  "getLabelRegions() for input \"%s\"?\n",
1112  getName().c_str(), str.c_str());
1113  }
1114  insert_pos += 1;
1115  }
1116  }
1117 
1118  // Sort region list and remove duplicates
1119  // By default this is always done
1120  // Turn it off if the list contains parameters that are not regions and/or you want to maintain the original order
1121  if(sanitize) {
1122  sort(regs.begin(), regs.end());
1123  regs.erase(unique(regs.begin(), regs.end()), regs.end());
1124  }
1125 }
1126 
1128  EGS_Input *i;
1129  int labelCount=0;
1130  while ((i = input->takeInputItem("set label"))) {
1131 
1132  // get input string
1133  string inp;
1134  int err = i->getInput("set label", inp);
1135  delete i;
1136 
1137  // bail out on read error
1138  if (err) {
1139  egsWarning("EGS_BaseGeometry::setLabels(): error while reading 'set label' input\n");
1140  return 0;
1141  }
1142 
1143  // set the labels from input string
1144  int nLabel = setLabels(inp);
1145 
1146  // increase label count
1147  labelCount += nLabel;
1148  }
1149 
1150  return labelCount;
1151 }
1152 
1153 int EGS_BaseGeometry::setLabels(const string &inp) {
1154 
1155  // label class to store label name and region list
1156  EGS_Label label;
1157 
1158  // list of tokens
1159  vector<string> tokens = egsTokenize(inp);
1160 
1161  // bail out if there are no tokens at all
1162  if (tokens.empty()) {
1163  egsWarning("EGS_BaseGeometry::setLabels(): no label specified\n");
1164  return 0;
1165  }
1166 
1167  // set label name
1168  label.name = tokens[0];
1169 
1170  // if no region is listed, apply label to all regions by default
1171  if (tokens.size() == 1) {
1172  label.regions.reserve(nreg); // allocate once
1173  for (int i = 0; i < nreg; i++) {
1174  label.regions.push_back(i);
1175  }
1176  }
1177  else {
1178  // parse numbers and number ranges
1179  label.regions = egsParseIntegerRanges(tokens.begin() + 1, tokens.end());
1180 
1181  // validate regions
1182  if (!validateRegions(label.regions)) {
1183  egsWarning("EGS_BaseGeometry::setLabels(): geometry %s, label %s, invalid regions\n", getName().c_str(), name.c_str());
1184  return 0;
1185  }
1186  }
1187 
1188  // warn if there is no region for this label
1189  if (label.regions.size() == 0) {
1190  egsWarning("EGS_BaseGeometry::setLabels(): geometry %s, label \"%s\": no region specified\n", getName().c_str(), label.name.c_str());
1191  return 0;
1192  }
1193 
1194  // push current label onto vector of labels
1195  labels.push_back(label);
1196 
1197  return 1;
1198 }
1199 
1200 bool EGS_BaseGeometry::validateRegions(const vector<int> &regions) {
1201 
1202  // validate region numbers (stop upon first invalid region)
1203  for (int reg : regions) {
1204  if (reg < 0 || reg >= nreg) {
1205  egsWarning("EGS_BaseGeometry::validateRegions(): geometry %s, region %d is out of bounds\n", getName().c_str(), reg);
1206  return false;
1207  }
1208  }
1209  return true;
1210 }
Base class for advanced EGSnrc C++ applications.
Base geometry class. Every geometry class must be derived from EGS_BaseGeometry.
virtual int getGlobalRegionOffset(const string geomName)
Get the global region number for the first region in the geometry.
virtual int computeIntersections(int ireg, int n, const EGS_Vector &x, const EGS_Vector &u, EGS_GeometryIntersections *isections)
Calculates intersection distances to region boundaries.
static int nMedia()
Get the number of media registered so far by all geometries.
bool validateRegions(const std::vector< int > &regions)
Validate that all region numbers are within valid bounds.
EGS_BPType bproperty
A bit mask of boolean properties for the entire geometry.
virtual EGS_Float howfarToOutside(int ireg, const EGS_Vector &x, const EGS_Vector &u)
virtual void setBScaling(int start, int end, EGS_Float bf)
Set the B field scaling factor in regions.
void setMedia(EGS_Input *inp)
Set the media in the geometry from the input pointed to by inp.
static EGS_BaseGeometry * createSingleGeometry(EGS_Input *inp)
Create a single geometry from the input inp.
virtual const string & getType() const =0
Get the geometry type.
static void describeGeometries()
Describes all existing geometries.
int nreg
Number of local regions in this geometry.
virtual int howfar(int ireg, const EGS_Vector &x, const EGS_Vector &u, EGS_Float &t, int *newmed=0, EGS_Vector *normal=0)=0
Calculate the distance to a boundary from x along the direction u.
bool has_B_scaling
Does this geometry has B field scaling factor?
bool has_rho_scaling
Does this geometry have relative mass density scvaling?
EGS_Float boundaryTolerance
Boundary tolerance for geometries that need it.
bool hasBScaling() const
Does this geometry object have a B field scaling feature?
short * region_media
Array of media indeces.
void setName(EGS_Input *inp)
Set the name of the geometry from the input inp.
static void setActiveGeometryList(int list)
Set the currently active geometry list.
void setMedium(const string &Name)
Set all regions to a medium with name Name.
static EGS_BaseGeometry * createGeometry(EGS_Input *)
Create a geometry (or geometries) from a given input.
const string & getName() const
Get the name of this geometry.
EGS_Float * rhor
Array with relative mass densities.
virtual EGS_Float getRelativeRho(int ireg) const
Get the relative mass density in region ireg.
EGS_Float * bfactor
Array with B field scaling factors.
int med
Medium index.
virtual void setBooleanProperty(EGS_BPType prop)
Set the boolean properties of the entire geometry to prop.
static string getUniqueName()
Get a unique geometry name.
static void clearGeometries()
Clears (deletes) all geometries in the currently active geometry list.
virtual int medium(int ireg) const
Returns the medium index in region ireg.
static int error_flag
Set to non-zero status if a geometry problem is encountered.
string name
Name of this geometry.
int regions() const
Returns the number of local regions in this geometry.
int setLabels(EGS_Input *input)
Set the labels from an input block.
virtual void setRelativeRho(int start, int end, EGS_Float rho)
Set the relative mass density in regions.
virtual void printInfo() const
Print information about this geometry.
int ref()
Increase the reference count to this geometry.
static EGS_BaseGeometry * getGeometry(const string &Name)
Get a pointer to the geometry named Name.
virtual void addBooleanProperty(int bit)
Add a boolean property for the entire geometry by setting the bit'th bit.
static int addMedium(const string &medname)
Add a medium or get the index of an existing medium.
EGS_Float rhoRef
Reference density for B field scaling.
static int getMediumIndex(const string &medname)
Get the index of a medium named medname.
virtual ~EGS_BaseGeometry()
Destructor.
EGS_BaseGeometry(const string &Name)
Construct a geometry named Name.
static const char * getMediumName(int ind)
Get the name of medium with index ind.
void setBoundaryTolerance(EGS_Input *inp)
Set the value of the boundary tolerance from the input inp.
vector< EGS_Label > labels
Labels.
virtual void getLabelRegions(const string &str, vector< int > &regs, bool sanitize=true)
Get the list of all regions labeled with str.
EGS_BPType * bp_array
An array of boolean properties on a region by region basis.
virtual void getNumberRegions(const string &str, vector< int > &regs)
Get a list of all the regions labeled with a number.
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
void print(int nind, ostream &)
Used for debugging purposes.
Definition: egs_input.cpp:1177
const char * name() const
Get the name of this property.
Definition: egs_input.cpp:274
int setContentFromString(string &input)
Definition: egs_input.cpp:209
static bool compare(const string &s1, const string &s2)
Definition: egs_input.cpp:1173
bool isA(const string &key) const
Definition: egs_input.cpp:281
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 class for dynamically loading shared libraries.
Definition: egs_library.h:52
const char * libraryName() const
Returns the name of the library object as given in the constructor.
bool isLoaded() const
Returns true if the library is loaded, false otherwise.
bool load()
Loads the library.
void * resolve(const char *func)
Returns the address of the exported symbol func.
A class representing 3D vectors.
Definition: egs_vector.h:57
EGS_Application class header file.
EGS_BaseGeometry class header file.
Global egspp functions header file.
vector< string > egsTokenize(const string &str)
Tokenize a string into individual tokens.
Definition: egs_input.cpp:1184
vector< int > egsParseIntegerRanges(vector< string >::const_iterator begin, vector< string >::const_iterator end)
Parse integers and integer ranges from string tokens.
Definition: egs_input.cpp:1207
EGS_Input class header file.
EGS_Library class header file.
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_Float distanceEpsilon
The distanceEpsilon constant for physical distance comparisons.
Definition: egs_functions.h:86
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.
const EGS_Float veryFar
A very large float.
EGS_I32 ireg
region index
EGS_Float t
distance to next region boundary
EGS_Float rhof
relative mass density in that region
EGS_I32 imed
medium index