EGSnrc C++ class library  Report PIRS-898 (2021)
Iwan Kawrakow, Ernesto Mainegra-Hing, Frederic Tessier, Reid Townson and Blake Walters
egs_autoenvelope.cpp
Go to the documentation of this file.
1 /*
2 ###############################################################################
3 #
4 # EGSnrc egs++ auto envelope geometry
5 # Copyright (C) 2016 Randle E. P. Taylor, Rowan M. Thomson,
6 # Marc J. P. Chamberland, D. W. O. Rogers
7 #
8 # This file is part of EGSnrc.
9 #
10 # EGSnrc is free software: you can redistribute it and/or modify it under
11 # the terms of the GNU Affero General Public License as published by the
12 # Free Software Foundation, either version 3 of the License, or (at your
13 # option) any later version.
14 #
15 # EGSnrc is distributed in the hope that it will be useful, but WITHOUT ANY
16 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17 # FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
18 # more details.
19 #
20 # You should have received a copy of the GNU Affero General Public License
21 # along with EGSnrc. If not, see <http://www.gnu.org/licenses/>.
22 #
23 ###############################################################################
24 #
25 # Author: Randle Taylor, 2016
26 #
27 # Contributors: Marc Chamberland
28 # Rowan Thomson
29 # Dave Rogers
30 # Martin Martinov
31 # Alexandre Demelo
32 #
33 ###############################################################################
34 #
35 # egs_autoenvelope was developed for the Carleton Laboratory for
36 # Radiotherapy Physics.
37 #
38 ###############################################################################
39 */
40 
41 
47 #include "egs_input.h"
48 #include "egs_autoenvelope.h"
49 #include "../egs_gtransformed/egs_gtransformed.h"
50 
51 #include <cstdlib>
52 #include <algorithm>
53 #include <numeric>
54 #include <iostream>
55 #include <fstream>
56 
57 #ifdef HAS_SOBOL
58  #include "sobol.h"
59 #endif
60 
61 
62 string EGS_AENVELOPE_LOCAL EGS_AEnvelope::type = "EGS_AEnvelope";
63 string EGS_AENVELOPE_LOCAL EGS_ASwitchedEnvelope::type = "EGS_ASwitchedEnvelope";
64 /* only geometries that support getting regional volume can be used as phantoms */
65 const string EGS_AENVELOPE_LOCAL EGS_AEnvelope::allowed_base_geom_types[] = {"EGS_cSpheres", "EGS_cSphericalShell", "EGS_XYZGeometry", "EGS_RZ"};
66 
67 static char EGS_AENVELOPE_LOCAL geom_class_msg[] = "createGeometry(AEnvelope): %s\n";
68 static char EGS_AENVELOPE_LOCAL base_geom_keyword[] = "base geometry";
69 static char EGS_AENVELOPE_LOCAL inscribed_geom_keyword[] = "inscribed geometry";
70 static char EGS_AENVELOPE_LOCAL inscribed_geom_name_keyword[] = "inscribed geometry name";
71 static char EGS_AENVELOPE_LOCAL transformations_keyword[] = "transformations";
72 static char EGS_AENVELOPE_LOCAL type_keyword[] = "type";
73 static char EGS_AENVELOPE_LOCAL transformation_keyword[] = "transformation";
74 
75 
76 EGS_AEnvelope::EGS_AEnvelope(EGS_BaseGeometry *base_geom,
77  const vector<AEnvelopeAux> inscribed, const string &Name, bool debug, string output_vc_file) :
78  EGS_BaseGeometry(Name), base_geom(base_geom), debug_info(debug), output_vc(output_vc_file) {
79 
80  bool volcor_available = allowedBaseGeomType(base_geom->getType());
81  bool volcor_requested = inscribed.size() > 0 && inscribed[0].vcopts->mode == CORRECT_VOLUME;
82 
83  if (!volcor_available && volcor_requested) {
84 
85  string msg(
86  "EGS_AEnvelope:: Volume correction is not available for geometry type '%s (%s)'. "
87  "Geometry types must implement getVolume. Valid choices are:\n\t"
88  );
89 
90  int end = (int)(sizeof(allowed_base_geom_types)/sizeof(string));
91  for (int i=0; i < end; i++) {
92  msg += allowed_base_geom_types[i] + " ";
93  }
94  msg += "\nPlease set `action = discover -or- correct and zero volume` or use a different base geometry type.\n";
95  egsFatal(msg.c_str(), base_geom->getType().c_str(), base_geom->getName().c_str());
96  }
97 
98 
99  base_geom->ref();
100  nregbase = base_geom->regions();
101  is_convex = base_geom->isConvex();
102  has_rho_scaling = getHasRhoScaling();
103 
104  ninscribed = inscribed.size();
105  if (ninscribed == 0) {
106  egsFatal("EGS_AEnvelope: no inscribed geometries!\n");
107  }
108 
109  // nreg is total regions in geometry = nregbase + sum(nreginscribed_j)
110  nreg = nregbase;
111 
112  // create a transformed copy of the inscribed geometry
113  int global = nreg;
114  for (int geom_idx=0; geom_idx < ninscribed; geom_idx++) {
115 
116  EGS_BaseGeometry *inscribed_geom = inscribed[geom_idx].geom;
117  EGS_AffineTransform *transform = inscribed[geom_idx].transform;
118  VCOptions *vcopt = inscribed[geom_idx].vcopts;
119  EGS_TransformedGeometry *transformed = new EGS_TransformedGeometry(inscribed_geom, *transform);
120 
121  inscribed_geoms.push_back(transformed);
122  transforms.push_back(transform);
123  opts.push_back(vcopt);
124 
125  int ninscribed_reg= transformed->regions();
126  nreg += ninscribed_reg;
127 
128  for (int lreg = 0; lreg < ninscribed_reg; lreg++) {
129  GeomRegPairT local(transformed, lreg);
130  local_to_global_reg[local] = global;
131  global_reg_to_local[global] = local;
132  global++;
133  }
134  }
135 
136  geoms_in_region = new vector<EGS_BaseGeometry *>[nregbase];
137 
138  if (inscribed[0].vcopts->vc_file != "") {
139  vc_results = loadFileResults(inscribed[0].vcopts, base_geom, inscribed_geoms, transforms);
140  egsInformation("loaded from %s\n", inscribed[0].vcopts->vc_file.c_str());
141  }
142  else {
143  // now run volume correction and figure out which regions have inscribed geometries
144  vc_results = findRegionsWithInscribed(inscribed[0].vcopts, base_geom, inscribed_geoms, transforms);
145  }
146 
147 
148  nreg_with_inscribed = 0;
149  for (volcor::RegionGeomSetT::iterator it=vc_results.regions_with_inscribed.begin();
150  it!=vc_results.regions_with_inscribed.end(); it++) {
151  nreg_with_inscribed++;
152  copy(it->second.begin(), it->second.end(), back_inserter(geoms_in_region[it->first]));
153  }
154 
155  if (getNRegWithInscribed() == 0) {
156  egsFatal("EGS_AEnvelope:: Failed to find any regions with inscribed geometries\n");
157  }
158 
159  if (output_vc=="yes" || output_vc=="text" || output_vc=="gzip") {
160  writeVolumeCorrection();
161  }
162 
163  if (debug_info) {
164  printInfo();
165  }
166 
167 }
168 
169 
170 EGS_AEnvelope::~EGS_AEnvelope() {
171  if (!base_geom->deref()) {
172  delete base_geom;
173  }
174 }
175 
176 bool EGS_AEnvelope::allowedBaseGeomType(const string &geom_type) {
177  // Check if the input geometry is one that aenvelope can handle
178 
179  int end = (int)(sizeof(allowed_base_geom_types)/sizeof(string));
180 
181  for (int i=0; i<end; i++) {
182  if (allowed_base_geom_types[i] == geom_type) {
183  return true;
184  }
185  }
186 
187  return false;
188 }
189 
190 int EGS_AEnvelope::getGlobalRegFromLocalReg(EGS_BaseGeometry *g, int local_reg) {
191  return getGlobalRegFromLocal(volcor::GeomRegPairT(g, local_reg));
192 }
193 
194 int EGS_AEnvelope::getGlobalRegFromLocal(const volcor::GeomRegPairT local) const {
195 
196  map<volcor::GeomRegPairT, int>::const_iterator glob_it = local_to_global_reg.find(local);
197  if (glob_it != local_to_global_reg.end()) {
198  return (*glob_it).second;
199  }
200  return -1;
201 }
202 
203 volcor::GeomRegPairT EGS_AEnvelope::getLocalFromGlobalReg(int ireg) const {
204 
205  map<int, volcor::GeomRegPairT>::const_iterator glob_it = global_reg_to_local.find(ireg);
206  if (glob_it != global_reg_to_local.end()) {
207  return (*glob_it).second;
208  }
209  return volcor::GeomRegPairT();
210 }
211 
212 int EGS_AEnvelope::getNRegWithInscribed() const {
213  return nreg_with_inscribed;
214 }
215 
216 bool EGS_AEnvelope::isRealRegion(int ireg) const {
217 
218  bool is_outside = ireg < 0 || ireg >= nreg;
219  if (is_outside) {
220  return false;
221  }
222 
223  bool in_base_geom = ireg < nregbase;
224  if (in_base_geom) {
225  return base_geom->isRealRegion(ireg);
226  }
227 
228  volcor::GeomRegPairT local;
229  local = getLocalFromGlobalReg(ireg);
230  return local.first->isRealRegion(local.second);
231 
232 };
233 
234 
235 bool EGS_AEnvelope::isInside(const EGS_Vector &x) {
236  return base_geom->isInside(x);
237 };
238 
239 
240 int EGS_AEnvelope::isWhere(const EGS_Vector &x) {
241 
242  int base_reg = base_geom->isWhere(x);
243 
244  // which inscribed geometries are in this region
245  vector<EGS_BaseGeometry *> geoms_in_reg = getGeomsInRegion(base_reg);
246 
247  if (base_reg < 0 || geoms_in_reg.size()==0) {
248  return base_reg;
249  }
250 
251  // loop over all inscribed geometries in this region and check
252  // if position is inside any of them
253  for (vector<EGS_BaseGeometry *>::iterator geom=geoms_in_reg.begin(); geom!= geoms_in_reg.end(); ++geom) {
254  int inscribed_reg = (*geom)->isWhere(x);
255  if (inscribed_reg >= 0) {
256  return getGlobalRegFromLocalReg(*geom, inscribed_reg);
257  }
258  }
259 
260  // not in any of the inscribed geometries so must be in envelope region
261  return base_reg;
262 };
263 
264 int EGS_AEnvelope::inside(const EGS_Vector &x) {
265  return isWhere(x);
266 };
267 
268 int EGS_AEnvelope::medium(int ireg) const {
269 
270  if (ireg < nregbase) {
271  return base_geom->medium(ireg);
272  }
273 
274  volcor::GeomRegPairT local = getLocalFromGlobalReg(ireg);
275 
276  return local.first->medium(local.second);
277 };
278 
279 vector<EGS_BaseGeometry *> EGS_AEnvelope::getGeomsInRegion(int ireg) {
280  if (ireg < 0 || ireg >= nregbase) {
281  vector<EGS_BaseGeometry *> empty;
282  return empty;
283  }
284  return geoms_in_region[ireg];
285 };
286 
287 int EGS_AEnvelope::computeIntersections(int ireg, int n, const EGS_Vector &X,
288  const EGS_Vector &u, EGS_GeometryIntersections *isections) {
289 
290  // For a given position x, direction u and region number ireg, this
291  // method returns the number of intersections with the geometry and
292  // distances, medium indeces and relative mass densities for all
293  // intersections, or, if this number is larger than the size n of
294  // isections, -1 (but the n intersections are still put in isections).
295  // If the position is outside, the method checks if the trajectory
296  // intersects the geometry and if yes, puts in the first element of
297  // isections the distance to the entry point and then finds all other
298  // intersections as in the case of x inside.
299 
300  if (n < 1) {
301  return -1;
302  }
303 
304  int isec_idx = 0; // current intersection index
305  EGS_Float t; // distance to next boundary
306  EGS_Float ttot = 0; // total distance along path
307  EGS_Vector x(X); // current position
308 
309  int imed;
310 
311  bool outside_envelope = ireg < 0;
312  bool in_base_geom = ireg >= 0 && ireg < nregbase;
313 
314  if (outside_envelope) {
315  t = 1e30;
316 
317  // region we would hit
318  ireg = howfar(ireg,x,u,t,&imed);
319  bool would_not_intersect = ireg < 0;
320 
321  if (would_not_intersect) {
322  return 0;
323  }
324 
325  isections[0].t = t; // distance to entry point
326  isections[0].rhof = 1;
327  isections[0].ireg = -1;
328  isections[0].imed = -1;
329  ttot = t;
330 
331  x += u*t;
332 
333  isec_idx = 1;
334  }
335  else {
336  // we're already inside the envelope
337  imed = medium(ireg);
338  }
339 
340  // keep looping until we exit the geometry!
341  while (1) {
342  //egsInformation("in loop: j=%d ireg=%d imed=%d x=(%g,%g,%g)\n",
343  // j,ireg,imed,x.x,x.y,x.z);
344  //
345 
346  // why are we setting these here?
347  // on first pass if we were outside envelope then:
348  // ireg is set to entry region
349  // imed is set to med of entry region (set in howfar above)
350  // else
351  // ireg is region of input ireg (current region?)
352  // imed is medium of input ireg (current region?)
353  isections[isec_idx].imed = imed; //
354  isections[isec_idx].ireg = ireg;
355  isections[isec_idx].rhof = getRelativeRho(ireg);
356 
357  if (in_base_geom) { // in one of the regions of the base geometry
358 
359  t = 1e30;
360 
361  // next region will be in base geom by default
362  ireg = base_geom->howfar(ireg,x,u,t,&imed);
363 
364  // if there's inscribed geoms in this region see if we will be intersecting one
365  vector<EGS_BaseGeometry *> geoms_in_reg = getGeomsInRegion(ireg);
366  for (vector<EGS_BaseGeometry *>::iterator geom=geoms_in_reg.begin(); geom!= geoms_in_reg.end(); ++geom) {
367 
368  int inscribed_reg = (*geom)->howfar(-1, x, u, t, &imed);
369 
370  bool hits_inscribed = inscribed_reg >= 0;
371 
372  if (hits_inscribed) {
373  ireg = getGlobalRegFromLocalReg(*geom, inscribed_reg);
374  }
375  }
376 
377  ttot += t;
378  isections[isec_idx++].t = ttot;
379 
380  // left the geometry (implies that no inscribed geoms hit
381  if (ireg < 0) {
382  return isec_idx;
383  }
384 
385 
386  // over limit of number of intersections
387  if (isec_idx >= n) {
388  return -1;
389  }
390 
391  // move to next boundary
392  x += u*t;
393 
394  }
395  else {
396 
397  // in inscribed geometry
398  volcor::GeomRegPairT local = getLocalFromGlobalReg(ireg);
399 
400  int max_isec = n - isec_idx;
401 
402  int ninter_sec = local.first->computeIntersections(local.second, max_isec,
403  x, u, &isections[isec_idx]);
404 
405  // convert intersection region indexes to global indexex
406  int nmax = ninter_sec >= 0 ? ninter_sec + isec_idx : n;
407  for (int i=isec_idx; i < nmax; i++) {
408  isections[i].ireg = getGlobalRegFromLocalReg(local.first, isections[i].ireg);
409  isections[i].t += ttot;
410  }
411 
412  //egsInformation("last intersection: %g\n",isections[nm-1].t);
413  if (ninter_sec < 0) {
414  return ninter_sec;
415  }
416 
417  isec_idx += ninter_sec;
418 
419  if (isec_idx >= n) {
420  return -1;
421  }
422 
423  t = isections[isec_idx-1].t - ttot;
424  x += u*t;
425  ttot = isections[isec_idx-1].t;
426  ireg = base_geom->isWhere(x);
427  //egsInformation("new region: %d\n",ireg);
428 
429  if (ireg < 0) {
430  return isec_idx;
431  }
432 
433  imed = base_geom->medium(ireg);
434  }
435  }
436  return -1;
437 }
438 
439 EGS_Float EGS_AEnvelope::howfarToOutside(int ireg, const EGS_Vector &x, const EGS_Vector &u) {
440 
441  if (ireg < 0) {
442  return 0;
443  }
444 
445  EGS_Float d;
446 
447  bool in_base_geom = ireg < nregbase;
448  if (in_base_geom) {
449  d = base_geom->howfarToOutside(ireg, x, u);
450  }
451  else if (base_geom->regions() == 1) {
452  d = base_geom->howfarToOutside(0, x, u);
453  }
454  else {
455  int ir = base_geom->isWhere(x);
456  d = base_geom->howfarToOutside(ir,x,u);
457  }
458  return d;
459 };
460 
461 
462 int EGS_AEnvelope::howfar(int ireg, const EGS_Vector &x, const EGS_Vector &u,
463  EGS_Float &t, int *newmed, EGS_Vector *normal) {
464 
465  bool inside_geom = ireg >= 0;
466  if (inside_geom) {
467 
468  bool inside_base_geom = ireg < nregbase;
469 
470  if (inside_base_geom) {
471 
472  int base_reg = base_geom->howfar(ireg,x,u,t,newmed,normal);
473  vector<EGS_BaseGeometry *> geoms_in_reg = getGeomsInRegion(ireg);
474 
475  bool no_inscribed_in_reg = geoms_in_reg.size() == 0;
476  if (no_inscribed_in_reg) {
477  return base_reg;
478  }
479 
480  int inscribed_global = -1;
481  for (vector<EGS_BaseGeometry *>::iterator geom=geoms_in_reg.begin(); geom!= geoms_in_reg.end(); ++geom) {
482  int local_reg = (*geom)->howfar(-1, x, u, t, newmed, normal);
483  bool hits_inscribed = local_reg >= 0;
484  if (hits_inscribed) {
485  inscribed_global = getGlobalRegFromLocalReg(*geom, local_reg);
486  }
487  }
488 
489  bool hit_inscribed_first = inscribed_global >= 0;
490 
491  if (hit_inscribed_first) {
492  return inscribed_global;
493  }
494 
495  return base_reg;
496  }
497  else {
498 
499  // if here, we are in an inscribed geometry.
500  volcor::GeomRegPairT local = getLocalFromGlobalReg(ireg);
501 
502  // and then check if we will hit a boundary in this geometry.
503  int new_local = local.first->howfar(local.second, x, u, t, newmed, normal);
504  bool hit_boundary_in_inscribed = new_local >=0;
505  if (hit_boundary_in_inscribed) {
506  return getGlobalRegFromLocalReg(local.first, new_local);
507  }
508 
509  // new_local < 0 implies that we have exited the inscribed geometry
510  // => check to see in which base geometry region we are.
511  int inew = base_geom->isWhere(x + u*t);
512  if (inew >= 0 && newmed) {
513  *newmed = base_geom->medium(inew);
514  }
515  return inew;
516  }
517  }
518 
519  // if here, we are outside the base geometry.
520  // check to see if we will enter.
521  int new_base_reg = base_geom->howfar(ireg,x,u,t,newmed,normal);
522  vector<EGS_BaseGeometry *> geoms_in_reg = getGeomsInRegion(new_base_reg);
523  bool has_geoms_in_reg = geoms_in_reg.size() > 0;
524 
525  //cout << "new reg "<<new_base_reg << " has geoms " << has_geoms_in_reg << " t "<<t<<endl;
526  if (new_base_reg >= 0 && has_geoms_in_reg) {
527 
528  // check if we will be inside an inscribed geometry when we enter
529  for (vector<EGS_BaseGeometry *>::iterator geom=geoms_in_reg.begin(); geom!= geoms_in_reg.end(); ++geom) {
530  int new_local_reg = (*geom)->isWhere(x+u*t);
531  bool landed_in_inscribed = new_local_reg >= 0;
532  if (landed_in_inscribed) {
533  if (newmed) {
534  *newmed = (*geom)->medium(new_local_reg);
535  }
536  return getGlobalRegFromLocalReg(*geom, new_local_reg);
537  }
538 
539  }
540  }
541 
542  return new_base_reg;
543 };
544 
545 
546 EGS_Float EGS_AEnvelope::hownear(int ireg, const EGS_Vector &x) {
547  bool inside_envelope = ireg >= 0;
548 
549  if (!inside_envelope) {
550  return base_geom->hownear(ireg, x);
551  }
552 
553  bool in_base_geom = ireg < nregbase ;
554  if (!in_base_geom) {
555  volcor::GeomRegPairT local = getLocalFromGlobalReg(ireg);
556  return local.first->hownear(local.second, x);
557  }
558 
559  EGS_Float tmin = base_geom->hownear(ireg, x);
560  if (tmin <= 0) {
561  return tmin;
562  }
563  vector<EGS_BaseGeometry *> geoms_in_reg = getGeomsInRegion(ireg);
564  for (vector<EGS_BaseGeometry *>::iterator geom=geoms_in_reg.begin(); geom!= geoms_in_reg.end(); ++geom) {
565  EGS_Float local_t = (*geom)->hownear(-1, x);
566  if (local_t < tmin) {
567  tmin = local_t;
568  if (tmin < 0) {
569  return tmin;
570  }
571  }
572  }
573  return tmin;
574 };
575 
576 bool EGS_AEnvelope::hasBooleanProperty(int ireg, EGS_BPType prop) const {
577  if (ireg >= 0 && ireg < nreg) {
578  if (ireg < nregbase) {
579  return base_geom->hasBooleanProperty(ireg,prop);
580  }
581  volcor::GeomRegPairT local = getLocalFromGlobalReg(ireg);
582  return local.first->hasBooleanProperty(local.second, prop);
583  }
584  return false;
585 };
586 
587 void EGS_AEnvelope::setBooleanProperty(EGS_BPType prop) {
588  setPropertyError("setBooleanProperty()");
589 };
590 
591 void EGS_AEnvelope::addBooleanProperty(int bit) {
592  setPropertyError("addBooleanProperty()");
593 };
594 
595 void EGS_AEnvelope::setBooleanProperty(EGS_BPType prop, int start, int end,int step) {
596  setPropertyError("setBooleanProperty()");
597 };
598 
599 void EGS_AEnvelope::addBooleanProperty(int bit,int start,int end,int step) {
600  setPropertyError("addBooleanProperty()");
601 };
602 
603 int EGS_AEnvelope::getMaxStep() const {
604  int nstep = base_geom->getMaxStep();
605  for (size_t j=0; j< inscribed_geoms.size(); ++j) {
606  nstep += inscribed_geoms[j]->getMaxStep();
607  }
608  return nstep + inscribed_geoms.size();
609 };
610 
611 void EGS_AEnvelope::getNextGeom(EGS_RandomGenerator *rndm) {
612  // calls getNextGeom on its component geometries to update dynamic
613  // geometries in the simulation
614  for (int j=0; j< inscribed_geoms.size(); ++j) {
615  inscribed_geoms[j]->getNextGeom(rndm);
616  }
617  base_geom->getNextGeom(rndm);
618 };
619 
620 void EGS_AEnvelope::updatePosition(EGS_Float time) {
621  // calls updatePosition on its component geometries to update dynamic
622  // geometries in the simulation
623  for (int j=0; j< inscribed_geoms.size(); j++) {
624  inscribed_geoms[j]->updatePosition(time);
625  }
626  base_geom->updatePosition(time);
627 };
628 
629 void EGS_AEnvelope::containsDynamic(bool &hasdynamic) {
630  // calls containsDynamic on its component geometries (only calls if
631  // hasDynamic is false, as if it is true we already found one)
632  for (int j=0; j< inscribed_geoms.size(); j++) {
633  if (!hasdynamic) {
634  inscribed_geoms[j]->containsDynamic(hasdynamic);
635  }
636  }
637  if (!hasdynamic) {
638  base_geom->containsDynamic(hasdynamic);
639  }
640 };
641 
642 
643 EGS_Float EGS_AEnvelope::getVolume(int ireg) {
644 
645  if (ireg < 0) {
646  return -1;
647  }
648  else if (ireg < nregbase) {
649  return vc_results.corrected_volumes[ireg];
650  }
651 
652  volcor::GeomRegPairT local = global_reg_to_local[ireg];
653 
654  return local.first->getVolume(local.second);
655 };
656 
657 EGS_Float EGS_AEnvelope::getCorrectionRatio(int ireg) {
658 
659  if (0 <= ireg && ireg < nregbase) {
660  return vc_results.corrected_volumes[ireg]/vc_results.uncorrected_volumes[ireg];
661  }
662 
663  return 1;
664 };
665 
666 
667 /* Print information about the geometry. If `print debug info = yes` is present
668  * in the geometry, extra information about which regions of the base geometry
669  * contain inscribed geometries and how their volumes were corrected.
670 */
671 void EGS_AEnvelope::printInfo() const {
672 
674 
675  if (debug_info) {
676 
677  for (int ir=0; ir < nregbase; ir++) {
678  if (fabs(vc_results.uncorrected_volumes[ir] - vc_results.corrected_volumes[ir]) > 1E-8) {
679  egsInformation(" volume of region %d was corrected from %.5E g to %.5E g\n",
680  ir, vc_results.uncorrected_volumes[ir], vc_results.corrected_volumes[ir]);
681  }
682  }
683 
684  for (int ir=0; ir < nregbase; ir++) {
685  if (geoms_in_region[ir].size() > 0) {
686  egsInformation(" region %d has %d inscribed geometries\n", ir, geoms_in_region[ir].size());
687  }
688  }
689  }
690 
691  vc_results.outputResults();
692 
693  egsInformation(" base geometry = %s (type %s) nreg=%d\n",base_geom->getName().c_str(),
694  base_geom->getType().c_str(), nregbase, base_geom->regions());
695  egsInformation(" # of inscribed geometries= %d in %d regions\n",inscribed_geoms.size(), getNRegWithInscribed());
696 
697 
698  egsInformation("=======================================================\n");
699 }
700 
701 void EGS_AEnvelope::writeVCToFile(ostream &out) {
702 
703  vector<int> to_write;
704 
705  for (int i=0; i < base_geom->regions(); i++) {
706  EGS_Float cor = vc_results.corrected_volumes[i];
707  EGS_Float uncor = vc_results.uncorrected_volumes[i];
708  bool has_correction = fabs(cor-uncor) > 1E-8;
709  if (has_correction) {
710  to_write.push_back(i);
711  }
712  }
713 
714  size_t nrecords = to_write.size();
715  out << nrecords << endl;
716 
717  for (size_t i=0; i<to_write.size(); i++) {
718  int ir = to_write[i];
719  EGS_Float cor = vc_results.corrected_volumes[ir];
720 
721  // find out the indexes of geometries inscribed in this region (if any)
722  vector<EGS_BaseGeometry *> geoms_in_reg = getGeomsInRegion(ir);
723  vector<int> geom_idxs_in_reg;
724  for (size_t i=0; i<geoms_in_reg.size(); i++) {
725  size_t pos = find(inscribed_geoms.begin(), inscribed_geoms.end(), geoms_in_reg[i]) - inscribed_geoms.begin();
726  if (pos < inscribed_geoms.size()) {
727  geom_idxs_in_reg.push_back(pos);
728  }
729  }
730 
731  int ninscribed = (int)geom_idxs_in_reg.size();
732 
733  out << ir << " " << cor;
734  // write number of and indexes of geometries inscribed in this region
735  out << " " << ninscribed;
736  for (size_t gidx = 0; gidx < geom_idxs_in_reg.size(); gidx++) {
737  out << " " <<geom_idxs_in_reg[gidx];
738  }
739  out << endl;
740  }
741 
742 }
743 
744 void EGS_AEnvelope::writeVolumeCorrection() {
745 
746  egsInformation("\nVolume Correction Output File \n%s\n", string(80,'=').c_str());
747 
748  string gname = base_geom->getName();
749  string fname = gname+".autoenv.volcor";
750  fname += (output_vc == "gzip" ? ".gz" : "");
751  string mode = (output_vc == "gzip" ? "gzip" : "text");
752 
754  "Writing volume correction file for %s to %s file %s\n",
755  gname.c_str(), mode.c_str(), fname.c_str());
756 
757  if (output_vc == "gzip") {
758 #ifdef HAS_GZSTREAM
759  ogzstream outgz(fname.c_str());
760  writeVCToFile(outgz);
761  outgz.close();
762 #endif
763  }
764  else {
765  ofstream out(fname.c_str());
766  writeVCToFile(out);
767  out.close();
768  }
769 
770 }
771 
772 
773 /* check if the base or any of inscribed geometries have density scaling on */
774 bool EGS_AEnvelope::getHasRhoScaling() {
775 
777  if (has_rho_scaling) {
778  return true;
779  }
780 
781  for (size_t geom_idx=0; geom_idx < inscribed_geoms.size(); geom_idx++) {
782  if (inscribed_geoms[geom_idx]->hasRhoScaling()) {
783  return true;
784  }
785  }
786  return false;
787 
788 }
789 
790 
791 void EGS_AEnvelope::setMedia(EGS_Input *,int,const int *) {
792  egsWarning("EGS_AEnvelope::setMedia: don't use this method. Use the\n"
793  " setMedia() methods of the geometry objects that make up this geometry\n");
794 }
795 
796 
797 void EGS_AEnvelope::setRelativeRho(int start, int end, EGS_Float rho) {
798  setRelativeRho(0);
799 }
800 
801 
802 void EGS_AEnvelope::setRelativeRho(EGS_Input *) {
803  egsWarning("EGS_AEnvelope::setRelativeRho(): don't use this method."
804  " Use the\n setRelativeRho methods of the geometry objects that make up"
805  " this geometry\n");
806 }
807 
808 
809 EGS_Float EGS_AEnvelope::getRelativeRho(int ireg) const {
810  if (ireg < 0 || ireg >= nreg) {
811  return 1;
812  }
813  if (ireg < nregbase) {
814  EGS_Float v = base_geom->getRelativeRho(ireg);
815  return v;
816  }
817  volcor::GeomRegPairT local = getLocalFromGlobalReg(ireg);
818  if (local.first) {
819  return local.first->getRelativeRho(local.second);
820  }
821  return 1;
822 };
823 
824 
825 /*************************************************************************/
826 /* Switched envelope *****************************************************/
827 /*************************************************************************/
828 
829 EGS_ASwitchedEnvelope::EGS_ASwitchedEnvelope(EGS_BaseGeometry *base_geom,
830  const vector<AEnvelopeAux> inscribed, const string &Name, bool debug, string output_vc_file):
831  EGS_AEnvelope(base_geom, inscribed, Name, debug, output_vc_file) {
832 
833  // activate a single geometry
834  cur_ptr = 0;
835  active_inscribed.push_back(inscribed_geoms[cur_ptr]);
836 
837 };
838 
839 
840 //TODO: this gets called a lot and is probably quite slow. Instead fo doing a
841 //set intersection on every call we can probably do it once when activated
842 //geometries change and cache it
843 vector<EGS_BaseGeometry *> EGS_ASwitchedEnvelope::getGeomsInRegion(int ireg) {
844  // find which geometries are present AND active in this region
845  vector<EGS_BaseGeometry *> active_in_reg;
846  if ((0 <= ireg) && (ireg < nregbase)) {
847  set_intersection(
848  geoms_in_region[ireg].begin(), geoms_in_region[ireg].end(),
849  active_inscribed.begin(), active_inscribed.end(),
850  back_inserter(active_in_reg)
851  );
852  }
853 
854  return active_in_reg;
855 
856 }
857 
858 
859 void EGS_ASwitchedEnvelope::setActiveGeometries(vector<EGS_BaseGeometry *> geoms) {
860  active_inscribed.clear();
861  active_inscribed = geoms;
862  cur_ptr = -1;
863  if (geoms.size() <= 0) {
864  return;
865  }
866 
867  for (size_t i=0; i < inscribed_geoms.size(); i++) {
868  if (inscribed_geoms[i] == geoms[0]) {
869  cur_ptr = i;
870  return;
871  }
872  }
873 }
874 
875 
876 void EGS_ASwitchedEnvelope::setActiveGeometries(vector<int> geom_indexes) {
877 
878  active_inscribed.clear();
879 
880  for (size_t i = 0; i < geom_indexes.size(); i++) {
881  int idx = geom_indexes[i];
882  if (idx < 0 || idx >= ninscribed) {
883  egsFatal("EGS_ASwitchedEnvelope:: %d is not a valid geometry index\n", idx);
884  }
885  active_inscribed.push_back(inscribed_geoms[i]);
886  }
887 
888  cur_ptr = geom_indexes[0];
889 
890 }
891 
892 
894 
895  if ((0 <= ireg) && (ireg < nregbase)) {
896  size_t nactive = getGeomsInRegion(ireg).size();
897  return nactive > 0;
898  }
899 
900  return false;
901 }
902 
903 
905 
906  if ((0 <= ireg) && (ireg < nregbase)) {
907  size_t nactive = getGeomsInRegion(ireg).size();
908  size_t ntotal = EGS_AEnvelope::getGeomsInRegion(ireg).size();
909  return nactive < ntotal;
910  }
911 
912  return false;
913 
914 }
915 
916 void EGS_ASwitchedEnvelope::setActiveByIndex(int inscribed_index) {
917  vector<EGS_BaseGeometry *> to_activate;
918  to_activate.push_back(inscribed_geoms[inscribed_index]);
919  setActiveGeometries(to_activate);
920  cur_ptr = inscribed_index;
921 }
922 
923 void EGS_ASwitchedEnvelope::activateByIndex(int inscribed_index) {
924  active_inscribed.push_back(inscribed_geoms[inscribed_index]);
925 }
926 
927 void EGS_ASwitchedEnvelope::deactivateByIndex(int inscribed_index) {
928  vector<EGS_BaseGeometry *>::iterator loc = find(
929  active_inscribed.begin(), active_inscribed.end(),
930  inscribed_geoms[inscribed_index]
931  );
932  if (loc != active_inscribed.end()) {
933  active_inscribed.erase(loc);
934  }
935 }
936 
938  cur_ptr = cur_ptr == ninscribed -1 ? 0 : cur_ptr + 1;
939  vector<EGS_BaseGeometry *> to_activate;
940  to_activate.push_back(inscribed_geoms[cur_ptr]);
941  setActiveGeometries(to_activate);
942 }
943 
944 
945 vector<EGS_AffineTransform *> EGS_AEnvelope::createTransforms(EGS_Input *input) {
946 
947  vector<EGS_AffineTransform *> transforms;
948  if (input) {
949  EGS_Input *i;
950 
951  while ((i = input->takeInputItem(transformation_keyword))) {
953  if (!transform) {
954  egsWarning("Invalid transform input given\n");
955 
956  }
957  transforms.push_back(transform);
958  delete i;
959 
960  }
961  }
962 
963  return transforms;
964 
965 }
966 
967 
968 extern "C" {
969 
970  EGS_AENVELOPE_EXPORT EGS_BaseGeometry *createGeometry(EGS_Input *input) {
971 
972  if (!input) {
973  egsWarning(geom_class_msg, "null input");
974  return 0;
975  }
976 
977  bool debug;
978  vector<string> debug_choices;
979  debug_choices.push_back("no");
980  debug_choices.push_back("yes");
981  debug = input->getInput("print debug info", debug_choices, 0);
982 
983  int output_vc_file_choice;
984  vector<string> vc_file_choices;
985  vc_file_choices.push_back("no");
986  vc_file_choices.push_back("yes");
987  vc_file_choices.push_back("text");
988  vc_file_choices.push_back("gzip");
989  output_vc_file_choice = input->getInput("output volume correction file", vc_file_choices, 0);
990  string output_vc_file = vc_file_choices[output_vc_file_choice];
991 
992 #ifndef HAS_GZSTREAM
993  if (output_vc_file == "gzip") {
994  egsWarning(
995  "GZip file output requested but not compiled with gzstream.\n"
996  "Please recompile with gzstream support.\n"
997  );
998  return 0;
999  }
1000 #endif
1001 
1002 
1003 
1004  string base_geom_name;
1005  int err = input->getInput(base_geom_keyword, base_geom_name);
1006  if (err) {
1007  egsWarning(geom_class_msg, ("'"+string(base_geom_keyword)+"' input not found").c_str());
1008  return 0;
1009  }
1010 
1011  string type;
1012  err = input->getInput(type_keyword, type);
1013  if (err) {
1014  type = "AEnvelope";
1015  }
1016 
1017  EGS_BaseGeometry *base_geom = EGS_BaseGeometry::getGeometry(base_geom_name);
1018  if (!base_geom) {
1019  egsWarning(geom_class_msg, ("Unable to find geometry '"+base_geom_name+"'").c_str());
1020  return 0;
1021  }
1022 
1023  EGS_Input *inscribed_input = input->takeInputItem(inscribed_geom_keyword);
1024  if (!inscribed_input) {
1025  egsWarning(geom_class_msg, ("Missing '"+string(inscribed_geom_keyword)+"' input item").c_str());
1026  return 0;
1027  }
1028 
1029  string inscribed_geom_name;
1030  err = inscribed_input->getInput(inscribed_geom_name_keyword, inscribed_geom_name);
1031  if (err) {
1032  egsWarning(geom_class_msg, ("'"+string(inscribed_geom_name_keyword)+"' input not found").c_str());
1033  return 0;
1034  }
1035 
1036  EGS_BaseGeometry *inscribed_geom = EGS_BaseGeometry::getGeometry(inscribed_geom_name);
1037  if (!inscribed_geom) {
1038  egsWarning(geom_class_msg, ("Unable to find geometry '"+inscribed_geom_name+"'").c_str());
1039  return 0;
1040  }
1041 
1042  vector<EGS_AffineTransform *> transforms;
1043  EGS_Input *trans_input = inscribed_input->takeInputItem(transformations_keyword);
1044  if (trans_input) {
1045  transforms = EGS_AEnvelope::createTransforms(trans_input);
1046  }
1047 
1048  delete trans_input;
1049 
1050  EGS_Input *volcor_input = inscribed_input->takeInputItem("region discovery");
1051  VCOptions *vcopts = new VCOptions(volcor_input);
1052  if (!vcopts->valid) {
1053  egsWarning(geom_class_msg, "Missing or invalid 'region discovery' input item");
1054  return 0;
1055  }
1056 
1057  delete inscribed_input;
1058 
1059 
1060  vector<AEnvelopeAux> inscribed;
1061  if (transforms.size()>0) {
1062  for (size_t i=0; i < transforms.size(); i++) {
1063  inscribed.push_back(AEnvelopeAux(inscribed_geom, transforms[i], vcopts));
1064  }
1065  }
1066  else {
1067  EGS_AffineTransform *unityt = new EGS_AffineTransform();
1068  inscribed.push_back(AEnvelopeAux(inscribed_geom, unityt, vcopts));
1069  }
1070 
1071  EGS_BaseGeometry *result;
1072  if (type == "EGS_ASwitchedEnvelope") {
1073  result = new EGS_ASwitchedEnvelope(base_geom, inscribed, "", (bool)debug, output_vc_file);
1074  }
1075  else {
1076  result = new EGS_AEnvelope(base_geom, inscribed, "", (bool)debug, output_vc_file);
1077  }
1078 
1079  result->setName(input);
1080  return result;
1081  }
1082 
1083 }
A fast envelope geometry with automatic region detection.
vector< EGS_BaseGeometry * > inscribed_geoms
The inscribed geometries.
static string type
Geometry type.
vector< EGS_AffineTransform * > transforms
The inscribed geometries.
EGS_BaseGeometry * base_geom
The envelope geometry.
static vector< EGS_AffineTransform * > createTransforms(EGS_Input *inpt)
Take a block of transformations and return vector of EGS_AffineTransforms.
static bool allowedBaseGeomType(const string &geom_type)
function for checking whether a given geometry type is allowed to be used as a base geometry
int nregbase
Number of regions in the base geometry.
void setMedia(EGS_Input *, int, const int *)
Don't set media for an envelope geometry.
int ninscribed
Number of regions in the base geometry.
This geometry type allows you to activate and deactivate inscribed geometries in custom egspp user co...
void deactivateByIndex(int inscribed_index)
bool hasInactiveGeom(int ireg)
void activateByIndex(int inscribed_index)
void setActiveGeometries(vector< EGS_BaseGeometry * > geoms)
void setActiveByIndex(int inscribed_index)
static string type
Geometry type.
bool hasActiveGeom(int ireg)
A class providing affine transformations.
static EGS_AffineTransform * getTransformation(EGS_Input *inp)
Constructs an affine transformation object from the input pointed to by inp and returns a pointer to ...
void transform(EGS_Vector &v) const
Transforms the vector v.
Base geometry class. Every geometry class must be derived from EGS_BaseGeometry.
virtual EGS_Float hownear(int ireg, const EGS_Vector &x)=0
Calculate the distance to a boundary for position x in any direction.
int deref()
Decrease the reference count to this geometry.
virtual bool hasBooleanProperty(int ireg, EGS_BPType prop) const
Is the boolean property prop set for region ireg ?
virtual EGS_Float howfarToOutside(int ireg, const EGS_Vector &x, const EGS_Vector &u)
virtual const string & getType() const =0
Get the geometry type.
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_rho_scaling
Does this geometry have relative mass density scvaling?
virtual bool isRealRegion(int ireg) const
Returnes true if ireg is a real region, false otherwise.
void setName(EGS_Input *inp)
Set the name of the geometry from the input inp.
virtual bool isInside(const EGS_Vector &x)=0
Is the position x inside the geometry?
const string & getName() const
Get the name of this geometry.
virtual EGS_Float getRelativeRho(int ireg) const
Get the relative mass density in region ireg.
bool isConvex() const
Is the geometry convex?
virtual int getMaxStep() const
Returns the maximum number of steps through the geometry.
bool hasRhoScaling() const
Does this geometry object have a mass density scaling feature?
virtual int medium(int ireg) const
Returns the medium index in region ireg.
int regions() const
Returns the number of local regions in this geometry.
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 int isWhere(const EGS_Vector &x)=0
In which region is poisition x?
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:226
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
Base random number generator class. All random number generators should be derived from this class.
Definition: egs_rndm.h:67
A transformed geometry.
A class representing 3D vectors.
Definition: egs_vector.h:57
Volume correction initialization helper class.
Definition: volcor.h:242
An envelope geometry with automatic inscribed region detection (inspired by EGS_FastEnvelope)
EGS_GLIB_EXPORT EGS_BaseGeometry * createGeometry(EGS_Input *input)
Definition: egs_glib.cpp:57
EGS_Input 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.
EGS_InfoFunction EGS_EXPORT egsWarning
Always use this function for reporting warnings.
VCResults findRegionsWithInscribed(VCOptions *opts, EGS_BaseGeometry *base, vector< EGS_BaseGeometry * > inscribed, vector< EGS_AffineTransform * > transforms)
Run the MC simulation.
Definition: volcor.h:558
VCResults loadFileResults(VCOptions *opts, EGS_BaseGeometry *base, vector< EGS_BaseGeometry * > inscribed, vector< EGS_AffineTransform * > transforms)
Load volume corrections from external file.
Definition: volcor.h:678
pair< EGS_BaseGeometry *, int > GeomRegPairT
Definition: volcor.h:89
@ CORRECT_VOLUME
Definition: volcor.h:85
A helper class for initializing auto envelopes.
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
vector< EGS_Float > corrected_volumes
Definition: volcor.h:441
void outputResults() const
Definition: volcor.h:476
vector< EGS_Float > uncorrected_volumes
Definition: volcor.h:440