EGS Brachy
An egs++ user code for rapid brachytherapy calculations
Loading...
Searching...
No Matches
/home/runner/work/egs_brachy/egs_brachy/egs_brachy/egs_brachy.cpp
Go to the documentation of this file.
1/*
2################################################################################
3#
4# egs_brachy egs_brachy.cpp
5# Copyright (C) 2016 Rowan Thomson, Dave Rogers, Randle Taylor, and Marc
6# Chamberland
7#
8# This file is part of egs_brachy
9#
10# egs_brachy is free software: you can redistribute it and/or modify it
11# under the terms of the GNU Affero General Public License as published
12# by the Free Software Foundation, either version 3 of the License, or
13# (at your option) any later version.
14#
15# egs_brachy is distributed in the hope that it will be useful, but
16# WITHOUT ANY WARRANTY; without even the implied warranty of
17# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18# Affero General Public License for more details:
19# <http://www.gnu.org/licenses/>.
20#
21################################################################################
22#
23# When egs_brachy is used for publications, please cite our paper:
24# M. J. P. Chamberland, R. E. P. Taylor, D. W. O. Rogers, and R. M. Thomson,
25# egs brachy: a versatile and fast Monte Carlo code for brachytherapy,
26# Phys. Med. Biol. 61, 8214-8231 (2016).
27#
28################################################################################
29#
30# Author: Randle Taylor, 2016
31#
32# Contributors: Marc Chamberland
33# Dave Rogers
34# Rowan Thomson
35#
36################################################################################
37*/
38
43
44#include <algorithm>
45#include <fstream>
46#include <string>
47#include <iomanip>
48#include <assert.h>
49#include <sys/stat.h>
50#include "gzstream.h"
51#include "zlib.h"
52
53#include "egs_brachy.h"
54#include "egs_ausgab_object.h"
55#include "egs_rndm.h"
56#include "egs_run_control.h"
57
58
59using namespace std;
60
61/* taken from egs_advance_application.cpp for outputData functions */
62#define egsGetRNGPointers F77_OBJ_(egs_get_rng_pointers,EGS_GET_RNG_POINTERS)
63extern __extc__ void egsGetRNGPointers(EGS_I32 *, EGS_I32 *);
64#define egsGetRNGArray F77_OBJ_(egs_get_rng_array,EGS_GET_RNG_ARRAY)
65extern __extc__ void egsGetRNGArray(EGS_Float *);
66#define egsSetRNGState F77_OBJ_(egs_set_rng_state,EGS_SET_RNG_STATE)
67extern __extc__ void egsSetRNGState(const EGS_I32 *, const EGS_Float *);
68#define egsGetSteps F77_OBJ_(egs_get_steps,EGS_GET_STEPS)
69extern __extc__ void egsGetSteps(double *, double *);
70#define egsSetSteps F77_OBJ_(egs_set_steps,EGS_SET_STEPS)
71extern __extc__ void egsSetSteps(const double *, const double *);
72#define egsOpenUnits F77_OBJ_(egs_open_units,EGS_OPEN_UNITS)
73extern __extc__ void egsOpenUnits(const EGS_I32 *);
74#define egsGetElectronData F77_OBJ_(egs_get_electron_data,EGS_GET_ELECTRON_DATA)
75extern __extc__ void egsGetElectronData(void (*func)(EGS_I32 *,EGS_Float *,
76 EGS_Float *,EGS_Float *,EGS_Float *),const EGS_I32 *,const EGS_I32 *);
77#define egsGetPhotonData F77_OBJ_(egs_get_photon_data,EGS_GET_PHOTON_DATA)
78extern __extc__ void egsGetPhotonData(void (*func)(EGS_I32 *,EGS_Float *,
79 EGS_Float *,EGS_Float *,EGS_Float *),const EGS_I32 *,const EGS_I32 *);
80/* end taken from egs_advance_application.cpp for outputData functions */
81
82extern "C" void F77_OBJ_(egs_scale_xcc,EGS_SCALE_XCC)(const int *,const EGS_Float *);
83extern "C" void F77_OBJ_(egs_scale_bc,EGS_SCALE_BC)(const int *,const EGS_Float *);
84extern "C" void F77_OBJ_(egs_bcse,EGS_BCSE)(const int *,const EGS_Float *);
85extern "C" void F77_OBJ_(egs_uniform_photons,EGS_UNIFORM_PHOTONS)(const int *,const EGS_Float *);
86
87void printParticleWithSpherical(EGS_Particle p) {
88 EGS_Float x,y,z, r, R, theta, phi;
89
90 x = p.x.x;
91 y = p.x.y;
92 z = p.x.z;
93
94 r = sqrt(x*x + y*y);
95 R = sqrt(x*x + y*y + z*z);
96 theta = acos(z/R)*180/M_PI;
97 phi = atan2(y, x)*180/M_PI;
98
100 cout << " R = " << R << "\n";
101 cout << " r = " << r << "\n";
102 cout << " z = " << z << "\n";
103 cout << " theta (deg) = " << theta << "\n";
104 cout << " phi (deg) = " << phi << "\n";
105
106}
107
108
109const EGS_Float EB_Application::DEFAULT_BCSE_FACTOR = 100;
110
111
113 egsInformation(
114 "\n ***************************************************"
115 "\n * *"
116 "\n * egs_brachy *"
117 "\n * *"
118 "\n ***************************************************"
119 "\n\n");
120}
121
123
124 if (!geometry && !source) {
125 return;
126 }
127
128 egsInformation("\n\negs_brachy Run Mode Information\n%s\n\n",string(80,'=').c_str());
129 egsInformation("Run mode = %s\n", run_mode_name.c_str());
130 egsInformation("Single generator (may be overriden later) = %s\n", single_generator ? "yes" :"no");
131 if (gcr_phantom) {
132 egsInformation(
133 "getCurrentResult phantom/reg = %s %d",
134 gcr_phantom->geometry->getName().c_str(),
136 );
137 }
138
139 egsInformation("\n\negs_brachy Geometry Information\n%s\n\n", string(80,'=').c_str());
140
141 ginfo.printInfo();
142
143 egsInformation("\n\negs_brachy Phantom Details\n%s\n\n", string(80,'=').c_str());
144 egsInformation(" | | | | Sph (Rmin, Rmax) | | \n");
145 egsInformation(" | | | Avg Vox Vol | RZ (Rmin, Rmax) | RZ (Zmin, Zmax) | \n");
146 egsInformation("Name | Type | Nreg | / cm^3 | XYZ (Xmin, Xmax) | XYZ (Ymin, Ymax) | XYZ (Zmin, Zmax)\n");
147 egsInformation("%s\n", string(145, '-').c_str());
148
149 for (size_t p=0; p < phantom_geoms.size(); p++) {
150
151 EB_Phantom *phant = phantom_geoms[p];
152 EGS_BaseGeometry *geom = phant->geometry;
153
154 string type = geom->getType();
155
156 if (type == "EGS_XYZGeometry") {
157 int nx, ny, nz;
158 nx = geom->getNRegDir(EB_Phantom::XDIR);
159 ny = geom->getNRegDir(EB_Phantom::YDIR);
160 nz = geom->getNRegDir(EB_Phantom::ZDIR);
161
162 EGS_Float xmin, xmax, ymin, ymax, zmin, zmax;
163 xmin = geom->getBound(EB_Phantom::XDIR, 0);
164 xmax = geom->getBound(EB_Phantom::XDIR, nx);
165 ymin = geom->getBound(EB_Phantom::YDIR, 0);
166 ymax = geom->getBound(EB_Phantom::YDIR, ny);
167 zmin = geom->getBound(EB_Phantom::ZDIR, 0);
168 zmax = geom->getBound(EB_Phantom::ZDIR, nz);
169
170 egsInformation(
171 "%-30s| %20s | %9d | %12.5G | (%8.3F, %8.3F) | (%8.3F, %8.3F) | (%8.3F, %8.3F)\n",
172 geom->getName().c_str(), type.c_str(), geom->regions(), phant->avgVoxelVol(),
173 xmin, xmax, ymin, ymax, zmin, zmax
174 );
175
176 } else if (type == "EGS_RZ") {
177 int nr, nz;
178 nr = geom->getNRegDir(EGS_RZGeometry::RDIR);
179 nz = geom->getNRegDir(EGS_RZGeometry::ZDIR);
180
181 EGS_Float rmin, rmax, zmin, zmax;
182 rmin = geom->getBound(EGS_RZGeometry::RDIR, 0);
183 rmax = geom->getBound(EGS_RZGeometry::RDIR, nr-1);
184 zmin = geom->getBound(EGS_RZGeometry::ZDIR, 0);
185 zmax = geom->getBound(EGS_RZGeometry::ZDIR, nz-1);
186
187 egsInformation(
188 "%-30s| %20s | %9d | %12.5G | (%8.3F, %8.3F) | (%8.3F, %8.3F) |\n",
189 geom->getName().c_str(), type.c_str(), geom->regions(), phant->avgVoxelVol(),
190 rmin, rmax, zmin, zmax
191 );
192 } else if (type == "EGS_cSphericalShell" || type == "EGS_cSpheres") {
193 type = (type == "EGS_cSphericalShell" ? "SphSh" : "Sph");
194
195 int nr = geom->getNRegDir(0);
196
197 EGS_Float rmin, rmax;
198 rmin = geom->getBound(EGS_cSpheres::RDIR, 0);
199 rmax = geom->getBound(EGS_cSpheres::RDIR, nr);
200
201 egsInformation(
202 "%-30s| %20s | %9d | %12.5G | (%8.3F, %8.3F) | | \n",
203 geom->getName().c_str(), type.c_str(), geom->regions(), phant->avgVoxelVol(),
204 rmin, rmax
205 );
206 } else {
207 egsInformation(
208 "%-30s| %20s | %9d | %12.5G | | | \n",
209 geom->getName().c_str(), type.c_str(), geom->regions(), phant->avgVoxelVol(),
210 -1, -1
211 );
212 }
213
214 if (type == "EGS_XYZGeometryT") {
215 egsWarning("\n***WARNING***\nPhantom of type transformed XYZ geometry used. The number of voxels in each direction and their bounds in the egslog, 3ddose, and egsphant files will be incorrect due to current limitations of the egs++ geometry library.\n***WARNING***\n");
216 }
217
218 }
219
220 egsInformation("\n\negs_brachy Volume correction details\n%s\n", string(80, '-').c_str());
221
222 egsInformation("\nSource specific volume correction details\n%s\n", string(80, '-').c_str());
223 source_vc_results.outputResults("Source");
224
225 egsInformation("\nExtra volume correction details\n%s\n", string(80, '-').c_str());
226 gen_vc_results.outputResults("Extra");
227
228 egsInformation("\nFile volume correction details\n%s\n", string(80, '-').c_str());
229 file_vc_results.outputResults();
230
231 egsInformation("\n\n");
232 if (geometry) {
233 geometry->printInfo();
234 }
235
236 if (source) {
237 egsInformation("\n\negs_brachy Source Information\n%s\n", string(80,'=').c_str());
238 egsInformation("%s\n\n", source->getSourceDescription());
240 egsInformation(
241 "Applied source coordinate transform to %d source location(s)\n",
242 (int)source_transforms.size()
243 );
244 }
245 egsInformation("Number of source locations = %d\n", source_transforms.size());
246 egsInformation("Single source generator = %s\n", (single_generator ? "yes" : "no"));
247 egsInformation("Source | Location (x cm, y cm, z cm) | Rotated | Weight\n%s\n", string(80,'-').c_str());
248 for (size_t tt =0; tt < source_transforms.size(); tt++) {
249 EGS_Vector trans = source_transforms[tt]->getTranslation();
250 egsInformation(
251 "%6d | ( % 7.3F, % 7.3F, % 7.3F) | %5s | % 7.2G\n",
252 tt+1, trans.x, trans.y, trans.z,
253 source_transforms[tt]->hasRotation() ? "true":"false",
255 );
256 }
257 }
258
259 if (rndm) {
260 egsInformation("\n\n");
261 rndm->describeRNG();
262 }
263
264 if (a_objects_list.size() > 0) {
265 egsInformation("The following ausgab objects are included in the simulation\n");
266 egsInformation("===========================================================\n\n");
267 for (size_t j=0; j<a_objects_list.size(); ++j) {
268 egsInformation("%s",a_objects_list[j]->getObjectDescription());
269 }
270 egsInformation("\n\n");
271 }
272
274
275 if (final_job) {
276 helpInit(0,false);
277 }
278}
279
280bool containsInclude(string str) {
281 string::iterator end_pos = std::remove(str.begin(), str.end(), ' ');
282 str.erase(end_pos, str.end());
283 size_t found = str.find("includefile");
284 return found != string::npos;
285}
286
288
289
290 string fname = constructIOFileName(".egsinp", false);
291 egsInformation("\n\nIncluded Files\n%s\n", string(80,'=').c_str());
292 egsInformation("Input file:\n\t%s\n", fname.c_str());
293 egsInformation("The following files were included in this simulation:\n");
294 ifstream inf(fname.c_str());
295
296 string line;
297 while (inf) {
298 getline(inf, line);
299 if (containsInclude(line)) {
300 egsInformation("\t%s\n", muen::trim(line).c_str());
301 }
302 };
303
304}
305
306
308 // override default initGeometry so we can manually create our own geometry
309 // which will allow us to track region numbers for each geometry object individually
310
311 timing_blocks.addTimer("egs_brachy::initGeometry");
312
313 EGS_Input *ginput = input->getInputItem("geometry definition");
314
315 if (!ginput) {
316 egsWarning("EB_Application::createGeometry: no geometry specification in this input\n");
317 egsFatal("Simulation stopped\n");
318 }
319
320 int err = ginfo.initializeFromInput(ginput);
321 if (err) {
322 egsWarning("EB_Application::createGeometry: incomplete or incorrect geometry specification\n");
323 delete ginput;
324 egsFatal("Simulation stopped\n");
325 }
326
327 err = EGS_AdvancedApplication::initGeometry();
328
329 if (err) {
330 egsWarning("Failed to create a geometry from input file\n");
331 delete ginput;
332 egsFatal("Simulation stopped\n");
333 }
334
335 geometry->ref();
336
337 ginfo.setGeometryIndexes(geometry);
338
339
340
341 if (run_mode == RM_SUPERPOSITION) {
342 if (ginfo.source_envelope_name == "") {
343 egsFatal("Missing 'source envelope geometry' input required for superposition mode\n");
344 }
345
346 source_envelope_geom = EGS_BaseGeometry::getGeometry(ginfo.source_envelope_name);
348 egsFatal("source envelope geometry '%s' can not be found\n", ginfo.source_envelope_name.c_str());
349 }
350
351 if (source_envelope_geom->getType() != "EGS_ASwitchedEnvelope") {
352 egsFatal("You must use an %s source envelope geometry type for superposition mode\n", "EGS_ASwitchedEnvelope");
353 }
354 superpos_geom = static_cast<EGS_ASwitchedEnvelope *>(source_envelope_geom);
355 }else{
356 for (int gg=0; gg < ginfo.ngeom; gg++) {
357 GeomRegionInfo gr = ginfo.ordered_geom_data[gg];
358 if (gr.type == "EGS_ASwitchedEnvelope"){
359 egsFatal("EGS_ASwitchedEnvelope should not be used when not using 'run mode = superposition\n");
360 }
361 }
362 }
363
364
365 err = initSourceTransforms();
366 if (err) {
367 egsFatal("Failed to initiate source locations\n");
368 }
369
370 delete ginput;
371
372 err = createPhantoms();
373 if (err) {
374 egsWarning("Failed to create phantom objects\n");
375 egsFatal("Simulation stopped\n");
376 }
377
378 err = correctVolumes();
379
380 timing_blocks.stopTimer();
381 return 0;
382
383}
384
385vector<EGS_AffineTransform *> EB_Application::createTransforms(EGS_Input *input) {
386
387 vector<EGS_AffineTransform *> transforms;
388 if (input) {
389 EGS_Input *trans_inp;
390
391 while ((trans_inp = input->takeInputItem("transformation"))) {
392 EGS_AffineTransform *transform = EGS_AffineTransform::getTransformation(trans_inp);
393 if (!transform) {
394 egsWarning("Invalid transform input given\n");
395
396 }
397 transforms.push_back(transform);
398 delete trans_inp;
399
400 }
401 }
402
403 return transforms;
404
405}
406
408
409 if (!input) {
410 return -1;
411 }
412
413 EGS_Input *source_inp = input->getInputItem("source definition");
414
415 if (!source_inp) {
416 return -1;
417 }
418
419
420 EGS_Input *source_loc_inp = source_inp->takeInputItem("transformations");
421
422 if (source_loc_inp) {
423 source_transforms = createTransforms(source_loc_inp);
424 delete source_loc_inp;
425 }
426
427 if (source_transforms.size() == 0) {
428 EGS_AffineTransform *unity_trans = new EGS_AffineTransform();
429 source_transforms.push_back(unity_trans);
430 egsWarning("EB_Application:: missing or invalid source `transformations` input item. Assuming single source at origin\n");
431 }
432
433 EGS_Input *coord_inp = source_inp->takeInputItem("source coordinate transform");
434 if (coord_inp) {
435 EGS_AffineTransform *coord_transform = EGS_AffineTransform::getTransformation(coord_inp);
436 if (coord_inp->getInputItem("transformation")) {
437 delete coord_inp;
438 egsFatal("EB_Application:: `source coordinate transform` must contain exactly one transformation\n");
439 }
440 delete coord_inp;
441 if (!coord_transform) {
442 egsFatal("EB_Application:: invalid `source coordinate transform` input\n");
443 }
444 for (size_t i = 0; i < source_transforms.size(); i++) {
445 EGS_AffineTransform *composed = new EGS_AffineTransform(
446 (*coord_transform) * (*source_transforms[i]));
447 delete source_transforms[i];
448 source_transforms[i] = composed;
449 }
450 delete coord_transform;
452 }
453
454 nsources = (int)source_transforms.size();
456 base_transform_inv = new EGS_AffineTransform(base_transform->inverse());
457
458 EGS_Input *source_overlap_inp = source_inp->takeInputItem("source overlap check");
459 if (source_overlap_inp){
460 int err = checkSourceOverlaps(source_overlap_inp);
461 if (err){
462 egsFatal("EB_Application:: checkSourceOverlaps detected an error.");
463 }
464 }
465
466 return 0;
467
468}
469
471
472 timing_blocks.addTimer("egs_brachy::checkSourceOverlaps");
473
474 vector<string> yn_choices;
475 yn_choices.push_back("no");
476 yn_choices.push_back("yes");
477 bool check_source_overlap = (bool)inp->getInput("check source overlaps", yn_choices, 0);
478
479 if (!check_source_overlap || source_transforms.size() <= 1){
480 /* not requested or only 1 source so no need to check for overlap */
481 timing_blocks.stopTimer();
482 return 0;
483 }
484
485 vector<string> mode_choices;
486 mode_choices.push_back("warning");
487 mode_choices.push_back("fatal");
488
489 bool fatal = (bool)inp->getInput("warning mode", mode_choices, 1);
490
491 EGS_Input *shape_inp = inp->takeInputItem("shape");
492
493 EGS_BaseShape *bounds = EGS_BaseShape::createShape(shape_inp);
494
495 if (!shape_inp) {
496 egsWarning("egs_brachy::checkSourceOverlaps - no `shape` input found.\n");
497 return 1;
498 }
499
500 EGS_Float bounds_volume = ebvolcor::getShapeVolume(shape_inp);
501 if (bounds_volume < 0){
502 egsWarning("egs_brachy::checkSourceOverlaps - Unable to get shape volume.");
503 return 1;
504 }
505
506 vector<string> excluded;
507 inp->getInput("excluded geometries", excluded);
508
509 EGS_Float density;
510 int err = inp->getInput("density of random points (cm^-3)", density);
511 if (err) {
512 egsWarning("egs_brachy::checkSourceOverlaps - The volume correction 'density of random points (cm^-3)' input was not found. Using 1E6/cm^3\n");
513 density = 1E6;
514 }
515 EGS_I64 npoints = (EGS_I64)floor(max(1., density*bounds_volume));
516
517
518 EGS_RandomGenerator *rng = EGS_RandomGenerator::defaultRNG();
519 EGS_Vector point;
520
521 /* find first source geometry defined */
522 EGS_BaseGeometry *base_source = 0;
523 string base_source_name;
524 for (int gg=0; gg < ginfo.ngeom; gg++) {
525 GeomRegionInfo gr = ginfo.ordered_geom_data[gg];
526 if (find(ginfo.source_names.begin(), ginfo.source_names.end(), gr.name) != ginfo.source_names.end()){
527 base_source = EGS_BaseGeometry::getGeometry(gr.name);
528 base_source_name = gr.name;
529 break;
530 }
531 }
532 if (!base_source){
533 egsFatal("egs_brachy::checkSourceOverlaps - did not find base source geometry");
534 }
535
536 /* now lets see if our base source is in an autoenvelope */
537 EGS_AffineTransform base_transform;
538 EGS_AffineTransform inv_base_transform;
539 for (int gg=0; gg < ginfo.ngeom; gg++) {
540 GeomRegionInfo gr = ginfo.ordered_geom_data[gg];
541 if (find(gr.children.begin(), gr.children.end(), base_source_name) != gr.children.end()){
542 /* base source is child of this geometry */
543 if (gr.type != "EGS_AEnvelope" && gr.type != "EGS_ASwitchedEnvelope"){
545 inv_base_transform = base_transform.inverse();
546 }
547 break;
548 }
549 }
550
551 vector<int> overlaps;
552
553 for (EGS_I64 i=0; i < npoints; i++) {
554
555 /* Generate a point and check if its contained within base source. If
556 * it's not actually in a source, go back and generate a new point. */
557 point = bounds->getRandomPoint(rng);
558 base_transform.transform(point);
559 if (base_source->isWhere(point) < 0) {
560 continue;
561 }
562 inv_base_transform.transform(point);
563
564 for (size_t sa_idx = 0; sa_idx < source_transforms.size(); sa_idx++){
565
566 overlaps.clear();
567
568 EGS_Vector transformed(point);
569
570 // transform from point relative to origin to point
571 // relative to source A we are checking against other sources (B)
572 source_transforms[sa_idx]->transform(transformed);
573
574 for (size_t sb_idx = sa_idx + 1; sb_idx < source_transforms.size(); sb_idx++){
575
576 EGS_Vector inner_transformed(transformed);
577
578 // use current source we are checking transform to back relative to origin
579 source_transforms[sb_idx]->inverse().transform(inner_transformed);
580 base_transform.transform(inner_transformed);
581 if (base_source->isWhere(inner_transformed) >= 0) {
582 /* point falls within Source A & B so they must be overlapping */
583 overlaps.push_back(sa_idx);
584 overlaps.push_back(sb_idx);
585 goto overlap_found;
586 }
587 }
588 }
589 }
590
591overlap_found:
592
593 if (rng){
594 delete rng;
595 }
596 if (shape_inp){
597 delete shape_inp;
598 }
599 timing_blocks.stopTimer();
600
601 if (overlaps.size() > 1){
602 string msg = "Possible overlap of sources: ";
603 for (int i=0; i < overlaps.size(); i++){
604 msg += to_string(overlaps[i]);
605 if (i != overlaps.size() -1 ){
606 msg += ", ";
607 }
608 }
609 egsInformation((msg+"\n").c_str());
610 }
611
612 if (overlaps.size() > 1){
613 return fatal ? 1 : 0;
614 }
615
616 return 0;
617}
618
620
621
622 timing_blocks.addTimer("egs_brachy::correctVolumes");
623 EGS_Input *vol_cor_inp = input->takeInputItem("volume correction");
624 if (!vol_cor_inp) {
625 egsWarning("Input item `volume correction` was not found\n");
626 return 1;
627 }
628
629 if (run_mode == RM_SUPERPOSITION) {
630 for (int i=0; i < nsources; i++) {
631 superpos_geom->activateByIndex(i);
632 }
633 }
635
637
639
641
642
643 // automatic volumes now done, now get any manually specified volumes
644 EGS_Input *ij;
645 vector<string> user_vols;
646
647 while ((ij = vol_cor_inp->takeInputItem("phantom region volumes")) != 0) {
648
649 string phant_name;
650 ij->getInput("phantom name", phant_name);
651 EB_Phantom *phant = getPhantomByName(phant_name);
652 if (!phant) {
653 egsFatal("`phanton region volume` specified for phantom `%s` which does not exist.", phant_name.c_str());
654 }else{
655 user_vols.push_back(phant_name);
656 }
657
658 vector<int> phantom_regs;
659 ij->getInput("region numbers", phantom_regs);
660
661 vector<EGS_Float> phantom_vols;
662 ij->getInput("region volumes", phantom_vols);
663
664 if (phantom_regs.size() != phantom_vols.size()){
665 egsFatal(
666 "Mismatched number of inputs for `region numbers` and `region volumes` for phantom `%s`",
667 phant_name.c_str()
668 );
669 }else if (phantom_regs.size() == 0){
670 egsFatal(
671 "Missing `region numbers` or `region volumes` input for `phantom region volumes` block for phantom `%s`",
672 phant_name.c_str()
673 );
674 }
675
676 for (size_t r = 0; r < phantom_regs.size(); r++){
677 phant->setCorrectedVolume(phantom_regs[r], phantom_vols[r]);
678 }
679
680
681 delete ij;
682 }
683
684 /* now we check to ensure that user has specified volumes for any phantoms
685 * which require it */
686 for (size_t p=0; p < phantom_geoms.size(); p++){
687 EB_Phantom *phant = phantom_geoms[p];
688 string name = phant->geometry->getName();
689 string type = phant->geometry->getType();
690 if (phant->needs_user_geoms && find(user_vols.begin(), user_vols.end(), name) == user_vols.end()){
691 egsFatal(
692 "Missing `phantom region volume` block for phantom `%s`."
693 "Phantoms of type `%s` can not calculate volumes automatically.",
694 name.c_str(),
695 type.c_str()
696 );
697 }
698 }
699
700 delete vol_cor_inp;
701
702 timing_blocks.stopTimer();
703
704 return 0;
705
706}
707
708
709// set up Phantom objects for any geometries that user has requested scoring for
711
712 for (size_t idx=0; idx < ginfo.phantom_names.size(); idx++) {
713 string name = ginfo.phantom_names[idx];
714
715 EGS_BaseGeometry *phant_geom = EGS_BaseGeometry::getGeometry(name);
716 if (!phant_geom) {
717 egsInformation("\n\nUnable to find phantom geometry `%s`.\n\n This is a fatal error\n\n", name.c_str());
718 return 1;
719 }
720
721
722 set<int> global_regions;
723
724 for (int reg=0; reg < ginfo.nreg_total; reg++) {
725 if (ginfo.phantomFromRegion(reg) == (int)idx) {
726 global_regions.insert(reg);
727 }
728 }
729
730 if (global_regions.size()==0) {
731 egsFatal(
732 "EB_Application::createPhantoms - No phantom regions detected for geometry '%s'.\n"
733 "Are you sure your phantom was included in the final simulation geometry?\n",
734 (phant_geom->getName()).c_str()
735 );
736 }
737 EB_Phantom *phantom = new EB_Phantom(this, phant_geom, global_regions, nsources, &pevent_pub);
738 phantom_geoms.push_back(phantom);
739
740 }
741
742 return 0;
743
744}
745
746
748
749
750 EGS_Input *source_inp = input->getInputItem("source definition");
751
752 if (!source_inp) {
753 return -1;
754 }
755
756
757 /* check if user has defined source weighting */
758 source_inp->getInput("source weights", source_weights);
759
760 // fill up source_weights so it always has length==nsources
761 while ((int)source_weights.size() < nsources) {
762 source_weights.push_back(1);
763 }
764
765 // normalize weights
766 double max_wt = *max_element(source_weights.begin(), source_weights.end());
767 vector<EGS_Float>::iterator it =source_weights.begin();
768 for (; it != source_weights.end(); ++it) {
769 *it /= max_wt;
770 }
771
772 int err = EGS_AdvancedApplication::initSource();
773 if (err) {
774 egsFatal("Failed to initialize source\n");
775 }
776
777 string stype = source->getObjectType();
778 is_phsp_source = stype == "EGS_PhspSource" || stype == "EB_IAEAPHSPSource";
779
781 single_generator = true;
782 egsInformation("Phase space being used. Overriding requested 'single generator = no' parameter. Setting to 'yes'\n");
783 }
784
785
786 return err;
787
788}
789
791
792 timing_blocks.addTimer("egs_brachy::initSimulation");
793 initRunMode();
794
795 int res = EGS_AdvancedApplication::initSimulation();
796
797 if (run_mode == RM_VC_ONLY) {
798 output_3ddose_files = false;
800 finishSimulation();
801 timing_blocks.stopTimer();
802 return 1;
803 }
804
805 timing_blocks.stopTimer();
806 return res;
807
808}
809
811
812 vector<string> format_choices;
813 format_choices.push_back("text");
814 format_choices.push_back("gzip");
815 EGS_Input *run_control = input->getInputItem("run control");
816 int format = run_control->getInput("egsdat file format", format_choices, 0);
817 output_egsdat_format = format == 0 ? "text" : "gzip";
818
819 if (run) {
820 delete run;
821 }
822 if (simple_run) {
823 run = new EGS_RunControl(this);
824 }
825 else if (uniform_run) {
827 }
828 else {
829 run = EGS_RunControl::getRunControlObject(this);
830 }
831 if (!run) {
832 return 1;
833 }
834 return 0;
835}
836
838 timing_blocks.addTimer("egs_brachy::initRunMode");
839
840 string run_mode_inp;
841 EGS_Input *rm = input->takeInputItem("run mode");
842 if (!rm) {
843 timing_blocks.stopTimer();
844 return 1;
845 }
846
847 vector<string> choices;
848 choices.push_back("normal"); // RM_NORMAL
849 choices.push_back("superposition"); //RM_SUPERPOSITION
850 choices.push_back("volume correction only"); //RM_VC_ONLY
851
852 run_mode = (RunMode)rm->getInput("run mode", choices, (int)RM_NORMAL);
853 run_mode_name = choices[run_mode];
854
855
856 vector<string> yn_choices;
857 yn_choices.push_back("no");
858 yn_choices.push_back("yes");
859
860 single_generator = (bool)rm->getInput("single generator", yn_choices, 1);
861
862 delete rm;
863
864 timing_blocks.stopTimer();
865
866 return 0;
867
868}
869
871 timing_blocks.addTimer("egs_brachy::initCrossSections");
872 EGS_Input *transportp = input->getInputItem("MC transport parameter");
873 if (!transportp) {
874 transportp = input->getInputItem("transport parameter");
875 }
876
877 if (!transportp) {
878 egsFatal("Missing `MC transport parameter` input item\n");
879 return 1;
880 }
881
882 int err = transportp->getInput("fluorescent photon cutoff", flu_cutoff);
883 if (err) {
884 flu_cutoff = 0.001;
885 }
886
887 int ret = EGS_AdvancedApplication::initCrossSections();
888
889 global_ecut = the_bounds->ecut;
890 global_pcut = the_bounds->pcut;
891
892 err = transportp->getInput("source ecut", source_ecut);
893 if (err) {
895 }
896
897 err = transportp->getInput("source pcut", source_pcut);
898 if (err) {
900 }
901
902 egsInformation("\negs_brachy transport parameter options:\n%s\n",string(80,'-').c_str());
903 egsInformation("Fluorescent photon cutoff %.3G\n", flu_cutoff);
904 egsInformation("Source PCUT %.3G\n", source_pcut);
905 egsInformation("Source ECUT %.3G\n", source_ecut);
906
907 timing_blocks.stopTimer();
908 return ret;
909}
910
911
913
914 timing_blocks.addTimer("egs_brachy::initScoring");
915
916 EGS_Input *options = input->takeInputItem("scoring options");
917
918 if (options) {
919
920 initGCRScoring(options);
922 initTrackLengthScoring(options);
923 initEDepScoring(options);
924 initScatScoring(options);
925 initXCCScaling(options);
926 initDoseScaling(options);
927 initSpectrumScoring(options);
928
930
931 initPHSPScoring(options);
932 initOutputFiles(options);
933
934
935 delete options;
936 } else {
937 egsFatal("\n\nMissing input section 'scoring options'\n\n");
938 }
939
941
942 timing_blocks.stopTimer();
943 return 0;
944}
945
946void EB_Application::initGCRScoring(EGS_Input *inp) {
947
948 gcr_phantom = 0;
949 gcr_phantom_reg = 0;
950
951 vector<string> gcr_inp;
952 int err = inp->getInput("current result phantom region", gcr_inp);
953 if (err || gcr_inp.size()==0) {
955 gcr_phantom_reg = 0;
956 return;
957 }
958
959
960 // user requested a phantom, find it
961 if (gcr_inp.size() >= 1) {
962 for (size_t idx=0; idx < ginfo.phantom_names.size(); idx++) {
963 if (ginfo.phantom_names[idx] == gcr_inp[0]) {
965 }
966 }
967 }
968
969 // couldn't find requested phantom
970 if (!gcr_phantom) {
971 egsWarning(
972 "Did not find '%s' phantom for getCurrentResult. Using phantom %s\n",
973 gcr_inp[0].c_str(), ginfo.phantom_names[0].c_str()
974 );
976 gcr_phantom_reg = 0;
977 return;
978 }
979
980 // user has also requested a region
981 if (gcr_inp.size() > 1) {
982 int ireg = atol(gcr_inp[1].c_str());
983 if (ireg > 0 && ireg < gcr_phantom->geometry->regions()) {
984 gcr_phantom_reg = ireg;
985 }
986 }
987
988}
989
991 for (size_t idx=0; idx < ginfo.phantom_names.size(); idx++) {
992 if (ginfo.phantom_names[idx] == name) {
993 return phantom_geoms[idx];
994 }
995 }
996
997 return 0;
998}
999
1000
1002
1003 vector<string> yn_choices;
1004 yn_choices.push_back("no");
1005 yn_choices.push_back("yes");
1006 output_egsphant = (bool)inp->getInput("output egsphant files", yn_choices, 0);
1007 output_voxinfo = (bool)inp->getInput("output voxel info files", yn_choices, 0);
1008 inp->getInput("output volume correction files for phantoms", output_volcor_phantoms);
1009
1010 vector<string> format_choices;
1011 format_choices.push_back("text");
1012 format_choices.push_back("gzip");
1013
1014 int format = inp->getInput("dose file format", format_choices, 0);
1015 output_dose_format = format == 0 ? "text" : "gzip";
1016
1017 format = inp->getInput("egsphant file format", format_choices, 0);
1018 output_egsphant_format = format == 0 ? "text" : "gzip";
1019
1020 format = inp->getInput("voxel info file format", format_choices, 0);
1021 output_voxinfo_format = format == 0 ? "text" : "gzip";
1022
1023 format = inp->getInput("volume correction file format", format_choices, 0);
1024 output_volcor_format = format == 0 ? "text" : "gzip";
1025
1026 inp->getInput("record initial particle positions", record_n_init);
1027
1028}
1029
1031
1032 EGS_Input *phsp_inp = inp->takeInputItem("phsp scoring");
1033
1034 if (phsp_inp) {
1035 phsp = new PHSPControl(phsp_inp, base_transform_inv, this, &pevent_pub);
1036 }
1037
1038}
1039
1040
1042
1043 timing_blocks.addTimer("egs_brachy::initVarianceReduction");
1044
1045 egsInformation("\n\negs_brachy Variance Reduction Information\n%s\n\n",string(80,'=').c_str());
1046
1047 EGS_Input *vr = input->takeInputItem("variance reduction");
1048
1049 /* Range rejection on by default in non source objects
1050 * and off in any source objects */
1051 global_i_do_rr = true;
1052 global_e_max_rr = 2.511;
1053
1054 source_i_do_rr = false;
1055 source_e_max_rr = 0.512;
1056
1057 the_egsvr->i_do_rr = (int)source_i_do_rr;
1058 the_egsvr->e_max_rr = source_e_max_rr;
1059
1060 if (!vr) {
1061 egsInformation("Global Range Rejection = %s\n", global_i_do_rr ? "Yes" : "No");
1062 egsInformation("Global Range Rejection Maximum Energy = %.3G MeV\n", global_e_max_rr);
1063 egsInformation("Source Range Rejection = %s\n", source_i_do_rr ? "Yes" : "No");
1064 egsInformation("Source Range Rejection Maximum Energy = %.3G MeV\n", source_e_max_rr);
1065 timing_blocks.stopTimer();
1066 return 1;
1067 }
1068
1069
1070 EGS_Input *ri = vr->takeInputItem("particle recycling");
1071 if (ri) {
1072 if (score_scat) {
1073 egsFatal("Primary-scatter dose scoring is not available with recycling. Please turn off recycling or disable scatter dose scoring.\n");
1074 }
1075 egsInformation("Particle Recycling\n");
1076 recycle_opts = new RecycleOpts(ri);
1077 recycle_opts->printInfo();
1078 if (!single_generator) {
1079 single_generator = true;
1080 egsInformation(" Overriding requested 'single generator = no' parameter. Setting to 'yes'\n");
1081 }
1082 egsInformation("\n");
1083
1084 delete ri;
1085 }
1086
1087 /* Range rejection */
1088 vector<string> yn_choices;
1089 yn_choices.push_back("no");
1090 yn_choices.push_back("yes");
1091
1092 string old_rr_setting;
1093 int err = vr->getInput("range rejection", old_rr_setting);
1094 if (!err) {
1095 egsFatal(
1096 "'range rejection' is not a valid setting for egs_brachy.\n"
1097 "Please use 'global range rejection' and 'source range rejection' settings instead.\n"
1098 );
1099 }
1100
1101 EGS_Float old_rr_max_e;
1102 err = vr->getInput("range rejection max energy", old_rr_max_e);
1103 if (!err) {
1104 egsFatal(
1105 "'range rejection max energy' is not a valid setting for egs_brachy.\n"
1106 "Please use 'global range rejection max energy' and 'source range rejection max energy' settings instead.\n"
1107 );
1108 }
1109
1110
1111 global_i_do_rr = vr->getInput("global range rejection", yn_choices, 1);
1112 egsInformation("Global Range Rejection = %s\n", global_i_do_rr ? "Yes" : "No");
1113 if (global_i_do_rr) {
1114 int err = vr->getInput("global range rejection max energy", global_e_max_rr);
1115 if (err) {
1116 global_e_max_rr = 2.511;
1117 }
1118 if (global_e_max_rr < 0.512) {
1119 egsFatal("Global Range Rejection max energy must be at least 0.512MeV\n");
1120 } else {
1121 egsInformation("Global Range Rejection Maximum Energy = %.3G MeV\n", global_e_max_rr);
1122 }
1123 }
1124
1125 source_i_do_rr = vr->getInput("source range rejection", yn_choices, 0);
1126 egsInformation("Source Range Rejection = %s\n", source_i_do_rr ? "Yes" : "No");
1127 if (source_i_do_rr) {
1128 int err = vr->getInput("source range rejection max energy", source_e_max_rr);
1129 if (err) {
1130 source_e_max_rr = 2.511;
1131 }
1132 if (source_e_max_rr < 0.512) {
1133 egsFatal("Source Range Rejection max energy must be at least 0.512MeV\n");
1134 } else {
1135 egsInformation("Source Range Rejection Maximum Energy = %.3G MeV\n", source_e_max_rr);
1136 }
1137 }
1138
1139 the_egsvr->i_do_rr = source_i_do_rr;
1140 the_egsvr->e_max_rr = source_e_max_rr;
1141
1142
1143 /* Brem Cross Section Enhancement*/
1144 err = initBCSE(vr);
1145 egsInformation("BCSE = %s\n", do_bcse ? "Yes" : "No");
1146 if (!err) {
1147 egsInformation(
1148 " Brem Cross Section Enhancement medium = %s (%d)\n",
1149 EGS_BaseGeometry::getMediumName(bcse_med_num), bcse_med_num
1150 );
1151 egsInformation(" Brem Cross Section Enhancement factor = %.3G\n", bcse_factor);
1152 }
1153
1154
1155 /* Brem Splitting */
1156 err = vr->getInput("split brem photons", nbr_split);
1157 egsInformation("Brem Splitting = %s\n", nbr_split > 1? "Yes" : "No");
1158 if (!err && nbr_split > 1) {
1159 do_brem_split = true;
1160 egsInformation(" Splitting brem photons N times = %d\n", nbr_split);
1161 the_egsvr->nbr_split = nbr_split;
1162 }
1163
1164
1165 /* Charged Particle Russian Roulette*/
1166 err = initRussianRoulette(vr);
1167 egsInformation("Charged Particle Russian Roulette = %s\n", the_egsvr->i_play_RR ? "Yes" : "No");
1168 if (!err || the_egsvr->i_play_RR) {
1169
1170 if (bcse_factor > 1) {
1171 the_egsvr->prob_RR = 1./(nbr_split*bcse_factor);
1172 egsInformation(
1173 " Survival probability (1/nbrsplt*bcse) = 1/(%d*%.3G) (%.3G%%)\n",
1174 nbr_split, bcse_factor, the_egsvr->prob_RR*100
1175 );
1176 } else {
1177 the_egsvr->prob_RR = 1./nbr_split;
1178 egsInformation(
1179 " Survival probability (1/nbrsplt) = 1/%d (%.3G%%)\n",
1180 nbr_split, the_egsvr->prob_RR*100
1181 );
1182 }
1183 }
1184
1185
1186 delete vr;
1187 timing_blocks.stopTimer();
1188 return 0;
1189
1190}
1191
1192int EB_Application::initRussianRoulette(EGS_Input *scoring_options) {
1193
1194 vector<string> yn_choices;
1195 yn_choices.push_back("no");
1196 yn_choices.push_back("yes");
1197
1198 int play_rr = scoring_options->getInput("russian roulette", yn_choices, 0);
1199 if (play_rr == 0) {
1200 return 1;
1201 }
1202
1203 the_egsvr->i_play_RR = 1;
1204
1205 AusgabCall rr_calls[] = {
1206 BeforeBrems, AfterBrems,
1207 BeforeAnnihFlight, AfterAnnihFlight,
1208 BeforeAnnihRest, AfterAnnihRest,
1209 FluorescentEvent
1210 };
1211
1212 int ncalls = sizeof(rr_calls)/sizeof(rr_calls[0]);
1213 enableAusgabCalls(ncalls, rr_calls);
1214
1215 return 0;
1216}
1217
1218int EB_Application::initBCSE(EGS_Input *inp) {
1219
1220 vector<string> bcse_inp;
1221 int err = inp->getInput("bcse medium", bcse_inp);
1222 if (err || bcse_inp.size()==0) {
1223 return 1;
1224 }
1225
1226 bcse_med_num = EGS_BaseGeometry::getMediumIndex(bcse_inp[0]);
1227 if (bcse_med_num < 0) {
1228 egsWarning("Requested an unknown medium `%s` for BCSE\n",bcse_inp[0].c_str());
1229 return 1;
1230 }
1231
1232
1233 if (bcse_inp.size() == 1) {
1235 } else {
1236 bcse_factor = atof(bcse_inp[1].c_str());
1237 }
1238
1239 do_bcse = bcse_factor > 1;
1240 if (!do_bcse) {
1241 return 1;
1242 }
1243
1244 the_egsvr->i_play_RR = 1;
1245
1246 AusgabCall bcse_calls[] = {BeforeBrems, AfterBrems, FluorescentEvent};
1247 enableAusgabCalls(3, bcse_calls);
1248
1249 int egs_med_num = bcse_med_num+1;
1250 F77_OBJ_(egs_bcse, EGS_BCSE)(&egs_med_num, &bcse_factor);
1251
1252 return 0;
1253}
1254
1255void EB_Application::initSpectrumScoring(EGS_Input *scoring_input) {
1256
1257 bool header_printed = false;
1258
1259 while (EGS_Input *spec_inp=scoring_input->takeInputItem("spectrum scoring")) {
1260
1261 if (!header_printed) {
1262 egsInformation("\n\negs_brachy Spectrum Scoring Information\n%s\n\n",string(80,'=').c_str());
1263 header_printed = true;
1264 }
1265
1267
1268 if (scorer) {
1269 spectrum_scorers.push_back(scorer);
1270 egsInformation("Added scorer with title: %s\n", scorer->getInfo().c_str());
1271 }
1272 delete spec_inp;
1273 }
1274}
1275
1277 for (size_t call=BeforeTransport; call <= UnknownCall; call++) {
1278 setAusgabCall((AusgabCall)call, false);
1279 }
1280
1281}
1282
1284
1285
1287
1288 AusgabCall always_call[] = {BeforeTransport, AfterTransport, FluorescentEvent};
1289 enableAusgabCalls(3, always_call);
1290
1291}
1292
1293
1294
1295void EB_Application::initTrackLengthScoring(EGS_Input *scoring_options) {
1296
1297 vector<string> choices;
1298 choices.push_back("no");
1299 choices.push_back("yes");
1300
1301 score_tlen = scoring_options->getInput("score tracklength dose", choices, 1);
1302
1303 if (score_tlen) {
1304 for (size_t p=0; p < phantom_geoms.size(); p++) {
1305 phantom_geoms[p]->enableTLenScoring();
1306 }
1307 initMuenData(scoring_options);
1308 }
1309
1310}
1311
1312map<string, string> getMuenForMedia(EGS_Input *scoring_options) {
1313
1314 map<string, string> muen_for_med;
1315
1316 vector<string> muen_meds;
1317 scoring_options->getInput("muen for media", muen_meds);
1318
1319 for (size_t i=0; i < muen_meds.size(); i++) {
1320 string med_name = muen_meds[i];
1321 muen_for_med[med_name] = med_name;
1322 };
1323
1324 EGS_Input *muen_inp;
1325 while ((muen_inp = scoring_options->takeInputItem("muen for medium"))) {
1326 string scoring, transport;
1327 int err = muen_inp->getInput("transport medium", transport);
1328 if (err) {
1329 egsFatal("Missing 'transport medium' key in 'muen for medium' block\n");
1330 delete muen_inp;
1331 }
1332 err = muen_inp->getInput("scoring medium", scoring);
1333 if (err) {
1334 egsFatal("Missing 'scoring medium' key in 'muen for medium' block\n");
1335 delete muen_inp;
1336 }
1337
1338 muen_for_med[transport] = scoring;
1339
1340 delete muen_inp;
1341 }
1342
1343 return muen_for_med;
1344
1345}
1346
1347void EB_Application::initMuenData(EGS_Input *scoring_options) {
1348
1349 egsInformation("\n\negs_brachy Muen Data Information\n%s\n\n",string(80,'=').c_str());
1350
1351 string muen_file;
1352 bool missing_muen = scoring_options->getInput("muen file", muen_file) != 0;
1353 if (missing_muen) {
1354 egsFatal("\n\nMissing input scoring options: muen file\n\n This is a fatal error\n\n");
1355 }
1356 muen_file = egsExpandPath(muen_file);
1357
1358 // transport med name -> scoring med name
1359 media_muen_names = getMuenForMedia(scoring_options);
1360
1361 if (media_muen_names.size()==0) {
1362 egsWarning(
1363 "EB_Application:: missing or invalid 'muen for media' input item or 'muen substitution' block(s).\n"
1364 " No muen data has been read.\n"
1365 );
1366 }
1367
1368 // read muen data file and set media_muen for all media requested
1370 int err = dp.setMuenFile(muen_file);
1371 if (err) {
1372 egsFatal("Failed to read muen data from %s\n",muen_file.c_str());
1373 }
1374
1375 egsInformation("Read muen data from %s\n", muen_file.c_str());
1376
1377 map<string, string>::iterator mit = media_muen_names.begin();
1378 for (; mit != media_muen_names.end(); mit++) {
1379
1380 string transport_med = mit->first;
1381 string scoring_med = mit->second;
1382 EGS_Interpolator *tmp_muen = dp.getMuenInterpolator(scoring_med);
1383 if (!tmp_muen) {
1384 egsFatal("EB_Application::Failed to get muen interpolator for %s\n", scoring_med.c_str());
1385 }
1386
1387 int med_idx = EGS_BaseGeometry::getMediumIndex(transport_med);
1388 if (med_idx < 0) {
1389 egsFatal(
1390 "EB_Application:: You requested scoring medium %s for transport medium %s but %s"
1391 " is not present in the geometry\n", scoring_med.c_str(), transport_med.c_str(), transport_med.c_str()
1392 );
1393 }
1394
1395 media_muen[med_idx] = tmp_muen;
1396 egsInformation(
1397 "Set medium %d (%s) to use muen data: %s\n",
1398 med_idx, transport_med.c_str(), scoring_med.c_str()
1399 );
1400 }
1401
1402
1403}
1404
1405void EB_Application::enableAusgabCalls(int ncalls, AusgabCall calls[]) {
1406 for (int i= 0; i < ncalls; i++) {
1407 setAusgabCall(calls[i], true);
1408 }
1409
1410}
1411
1412void EB_Application::initEDepScoring(EGS_Input *scoring_options) {
1413 // Set up energy deposition scoring if requested by user
1414
1415 vector<string> choices;
1416 choices.push_back("no");
1417 choices.push_back("yes");
1418
1419 score_edep = scoring_options->getInput("score energy deposition", choices, 0);
1420
1421 if (score_edep) {
1422 for (size_t p=0; p < phantom_geoms.size(); p++) {
1423 phantom_geoms[p]->enableInteractionScoring();
1424 }
1425
1426 AusgabCall edep_calls[] = {ExtraEnergy, UserDiscard, PegsCut, EgsCut};
1427 enableAusgabCalls(4, edep_calls);
1428 }
1429}
1430
1431void EB_Application::initScatScoring(EGS_Input *scoring_options) {
1432 // Set up energy deposition scoring if requested by user
1433
1434 vector<string> choices;
1435 choices.push_back("no");
1436 choices.push_back("yes");
1437
1438 score_scat = scoring_options->getInput("score scatter dose", choices, 0);
1439 if (score_scat && !score_tlen) {
1440 egsFatal("\nPrimary-scatter dose scoring requires tracklength scoring. Please enable tracklength scoring or disable scatter dose scoring.\n");
1441 }
1442
1443 if (score_scat && (source_transforms.size() > 1)) {
1444 egsFatal("\nPrimary-scatter dose scoring is only available in simulations with a single source. Please simulate a single source or disable scatter dose scoring.\n");
1445 }
1446
1447 if (score_scat && is_phsp_source) {
1448 egsFatal("\nPrimary-scatter dose scoring is not available with phase-space sources. Please do not use a phase-space source or disable scatter dose scoring.\n");
1449 }
1450
1451 if (score_scat) {
1452
1453 for (size_t p=0; p < phantom_geoms.size(); p++) {
1454 phantom_geoms[p]->enableScatterScoring();
1455 }
1456
1457 AusgabCall photon_scat_calls[] = {
1458 AfterAnnihFlight, AfterAnnihRest,
1459 AfterPair, AfterCompton, AfterPhoto, AfterRayleigh,
1460 FluorescentEvent
1461 };
1462
1463 int ncalls = sizeof(photon_scat_calls)/sizeof(photon_scat_calls[0]);
1464 enableAusgabCalls(ncalls, photon_scat_calls);
1465 }
1466}
1467
1468void EB_Application::initDoseScaling(EGS_Input *scoring_options) {
1469
1470 EGS_Float scale = 1.;
1471
1472 int err = scoring_options->getInput("dose scaling factor", scale);
1473
1474 if (!err && scale > 0) {
1475 for (size_t p=0; p < phantom_geoms.size(); p++) {
1476 phantom_geoms[p]->setDoseScale(scale);
1477 }
1478 }
1479}
1480
1481void EB_Application::initXCCScaling(EGS_Input *scoring_options) {
1482
1483 EGS_Input *scale;
1484
1485 while ((scale = scoring_options->takeInputItem("scale xcc"))) {
1486 vector<string> tmp;
1487 int err = scale->getInput("scale xcc",tmp);
1488 //egsInformation("Found 'scale xcc', err=%d tmp.size()=%d\n",err,tmp.size());
1489 if (!err && tmp.size() == 2) {
1490 int imed = EGS_BaseGeometry::getMediumIndex(tmp[0]) + 1;
1491 if (imed > 0) {
1492 EGS_Float fac = atof(tmp[1].c_str());
1493 egsInformation("\n ***** Scaling xcc of medium %d with %G\n",imed,fac);
1494 F77_OBJ_(egs_scale_xcc,EGS_SCALE_XCC)(&imed,&fac);
1495 }
1496 }
1497 delete scale;
1498 }
1499
1500 while ((scale = scoring_options->takeInputItem("scale bc"))) {
1501 vector<string> tmp;
1502 int err = scale->getInput("scale bc",tmp);
1503 //egsInformation("Found 'scale xcc', err=%d tmp.size()=%d\n",err,tmp.size());
1504 if (!err && tmp.size() == 2) {
1505 int imed = EGS_BaseGeometry::getMediumIndex(tmp[0]) + 1;
1506 if (imed > 0) {
1507 EGS_Float fac = atof(tmp[1].c_str());
1508 egsInformation("\n ***** Scaling bc of medium %d with %G\n",imed,fac);
1509 F77_OBJ_(egs_scale_bc,EGS_SCALE_BC)(&imed,&fac);
1510 }
1511 }
1512 delete scale;
1513 }
1514}
1515
1516
1517void EB_Application::copyParticleToSourceLoc(EGS_Particle *p, int source, bool kill_orig, bool rotate,
1518 EGS_Float new_wt) {
1519
1520 // copy current location of particle
1521 EGS_Vector new_loc(p->x);
1522 EGS_Vector new_dir(p->u);
1523
1524 // first move back to non transformed location
1525 base_transform_inv->transform(new_loc);
1526 base_transform_inv->rotate(new_dir);
1527
1528 if (rotate) {
1529 double angle = 2*M_PI*rndm->getUniform();
1530 EGS_RotationMatrix rot = EGS_RotationMatrix::rotZ(angle);
1531 new_loc *= rot;
1532 new_dir *= rot;
1533 }
1534
1535 // now transform particle to position of requested source
1536 source_transforms[source]->transform(new_loc);
1537 source_transforms[source]->rotate(new_dir);
1538
1539 // where is new particle
1540 int new_reg = geometry->isWhere(new_loc);
1541 int new_med = geometry->medium(new_reg);
1542
1543 // add a new particle to top of stack
1544
1545 int cur_np = the_stack->np;
1546 int new_np = the_stack->np+1;
1547 int np_idx = new_np-1;
1548
1549 the_stack->ir[np_idx] = new_reg + 2;
1550 the_stack->latch[np_idx] = p->latch;
1551 the_stack->E[np_idx] = p->E;
1552 the_stack->wt[np_idx] = new_wt;;
1553 the_stack->iq[np_idx] = p->q;
1554 the_stack->x[np_idx] = new_loc.x;
1555 the_stack->y[np_idx] = new_loc.y;
1556 the_stack->z[np_idx] = new_loc.z;
1557 the_stack->u[np_idx] = new_dir.x;
1558 the_stack->v[np_idx] = new_dir.y;
1559 the_stack->w[np_idx] = new_dir.z;
1560 the_stack->dnear[np_idx] = 0; // set to 0 because this move happens at boundary
1561
1562 the_stack->np += 1;
1563 the_stack->npold = cur_np;
1564
1565 the_epcont->irnew = new_reg+2;
1566 the_useful->medium_new = new_med+1;
1567
1569
1570 if (kill_orig) {
1571 the_stack->wt[np_idx-1] = 0;
1572 p->wt = 0;
1573 }
1574}
1575
1577
1578 EGS_AdvancedApplication::startNewParticle();
1579
1580 int ireg = the_stack->ir[the_stack->np-1] - 2;
1581 if (ginfo.isSource(ireg)) {
1582 the_bounds->ecut = source_ecut;
1583 the_bounds->pcut = source_pcut;
1584 } else {
1585 the_bounds->ecut = global_ecut;
1586 the_bounds->pcut = global_pcut;
1587 }
1588
1589}
1590
1592
1593 EGS_AdvancedApplication::enterNewRegion();
1594
1595 int ireg = the_epcont->irnew-2;
1596 if (ginfo.isSource(ireg)) {
1597 the_bounds->ecut_new = source_ecut;
1598 the_bounds->pcut_new = source_pcut;
1599 the_egsvr->i_do_rr = source_i_do_rr;
1600 the_egsvr->e_max_rr = source_e_max_rr;
1601 } else {
1602 the_bounds->ecut_new = global_ecut;
1603 the_bounds->pcut_new = global_pcut;
1604 the_egsvr->i_do_rr = global_i_do_rr;
1605 the_egsvr->e_max_rr = global_e_max_rr;
1606 }
1607
1608}
1609
1611
1612 top_p.wt = 0;
1613 the_stack->wt[the_stack->np-1] = 0;
1614 the_epcont->idisc = idisc;
1615
1616}
1617
1618void EB_Application::addRecycledParticlesToStack(EGS_Particle *p, bool new_hist) {
1619
1620 if (!recycle_opts) {
1621 return;
1622 }
1623
1624 EGS_Float wt = p->wt/source_weights[active_source];
1625
1626 for (int recycle_idx=0; recycle_idx < recycle_opts->nrecycle; recycle_idx++) {
1627
1628 int start_loc, stop_loc;
1629
1630 if (run_mode == RM_SUPERPOSITION) {
1631 start_loc = active_source;
1632 stop_loc = start_loc + 1;
1633 } else {
1634 start_loc = 0;
1635 stop_loc = nsources;
1636 }
1637
1638 for (int source_loc = start_loc; source_loc < stop_loc; source_loc++) {
1639 // we only want to kill the original particle if this is not
1640 // new history from phsp
1641 bool kill = source_loc == start_loc && recycle_idx == 0 && !new_hist;
1642 EGS_Float new_wt = wt*source_weights[source_loc];
1643 copyParticleToSourceLoc(p, source_loc, kill, recycle_opts->rotate, new_wt);
1644 }
1645 }
1646
1647
1648}
1649
1651
1652 /* if particle number has changed, reset the stuck particle counter so that
1653 * particles generated from splitting don't trigger same position error */
1654 bool same_particle = the_stack->npold == the_stack->np;
1655 if (!same_particle){
1657 return false;
1658 }
1659
1660 cur_R = top_p.x.length2();
1661 bool in_same_pos = fabs(cur_R - last_R) < SAME_POSITION_TOLERANCE;
1662 if (in_same_pos) {
1664 }
1665 last_R = cur_R;
1666
1668 //PRINT_PARTICLE(top_p);
1669 egsWarning("Particle hasn't moved in %d steps. Discarding particle\n", NUM_STUCK_STEPS);
1671 n_stuck++;
1673
1674 return true;
1675 }
1676 return false;
1677
1678}
1679
1681
1682 bool is_photon = top_p.q == 0;
1683 bool is_before_transport = iarg == BeforeTransport;
1684 bool is_after_transport = iarg == AfterTransport;
1685
1686 if (is_after_transport && isStuck()) {
1687 the_stack->latch[the_stack->np - 1] = top_p.latch;
1688 return 1;
1689 }
1690
1691 int global_ir = top_p.ir;
1692 int irnew = the_epcont->irnew-2;
1693 int irold = the_epcont->irold-2;
1694
1695 bool in_phantom = ginfo.isPhantom(global_ir);
1696 bool in_source = ginfo.isSource(global_ir);
1697
1698 bool is_extra_scoring_reg = false;
1699 string local_geom_name = "";
1700 int local_geom_ir = -1;
1701 int extra_reg_dose_index = -1;
1702
1703 if (extra_scoring_reg.size() > 0 && global_ir >= 0){
1704
1705 // local geom object info
1706 GeomRegT local = ginfo.globalToLocal(global_ir);
1707 local_geom_ir = local.second;
1708 local_geom_name = local.first->getName();
1709
1710 // check if the current geometry has extra scoring regions
1711 map<string, vector<int> >::iterator i = extra_scoring_reg.find(local_geom_name);
1712 if (i != extra_scoring_reg.end()){
1713 vector<int>::iterator it = find(i->second.begin(), i->second.end(), local_geom_ir);
1714 if (it != i->second.end()){
1715 is_extra_scoring_reg = true;
1716 extra_reg_dose_index = distance(i->second.begin(), it);
1717 }
1718 }
1719 }
1720
1721 /* track number of steps */
1722 if (is_before_transport) {
1723 if (in_source) {
1724 steps_in_sources[top_p.q]++;
1725 } else if (in_phantom) {
1726 steps_in_phantoms[top_p.q]++;
1727 } else {
1728 steps_in_other[top_p.q]++;
1729 }
1730 }
1731
1732 /* Fluorescent photon cutoff */
1733 bool discard_fluorescent = iarg == FluorescentEvent && top_p.E <= flu_cutoff;
1734 if (discard_fluorescent) {
1736 the_stack->latch[the_stack->np - 1] = top_p.latch;
1737 return 0;
1738 }
1739
1740 /* track scattering with latch bits if required */
1741 if (score_scat && (iarg > AfterTransport) && !in_source) {
1742 latch_control.addScatter(&top_p);
1743 for (int ip=the_stack->npold-1; ip < the_stack->np; ip++) {
1744 latch_control.addScatter(the_stack->latch[ip]);
1745 }
1746 }
1747
1748 bool next_is_source = ginfo.isSource(irnew);
1749 bool last_was_source = ginfo.isSource(irold);
1750
1751 /* note a particle leaving source could be a particle that has re-entered a
1752 * source. escaping_source will only be true on first time leaving source*/
1753 bool leaving_source = is_before_transport && in_source && !next_is_source;
1754 bool escaping_source = leaving_source && !latch_control.hasEscaped(&top_p);
1755
1756 /* same as leaving/escaping but for after transport rather than before*/
1757 bool left_source = is_after_transport && !in_source && last_was_source;
1758 bool escaped_source = left_source && !latch_control.hasEscaped(&top_p);
1759
1760 bool escaping_geom = is_before_transport && irnew < 0;
1761 bool escaped_geom = global_ir < 0;
1762
1763
1764 /* these notifications may be used by subscribers like spectrum
1765 * scoring objects, latch control etc */
1766 EBSendMessage send_messages[] = {
1767 EBSendMessage(is_before_transport, PARTICLE_TAKING_STEP),
1768 EBSendMessage(is_after_transport, PARTICLE_TOOK_STEP),
1769 EBSendMessage(escaping_source, PARTICLE_ESCAPING_SOURCE),
1770 EBSendMessage(escaped_source, PARTICLE_ESCAPED_SOURCE),
1771 EBSendMessage(escaping_geom, PARTICLE_ESCAPING_GEOM),
1773 };
1774 int nmesg = sizeof(send_messages)/sizeof(send_messages[0]);
1775 for (int m=0; m < nmesg; m++) {
1776 if (send_messages[m].first) {
1777 pevent_pub.notify(send_messages[m].second, &top_p);
1778 }
1779 }
1780
1781 /* copy the top_p.latch bit to the stack before returning from ausgab.
1782 * Since top_p.latch gets reset every step */
1783 the_stack->latch[the_stack->np - 1] = top_p.latch;
1784
1785 if (escaped_geom) {
1786 return 0;
1787 }
1788
1789 /* move particles to new locations if single generator or recycling */
1790 if (escaped_source && is_after_transport) {
1791
1792 EGS_Float wt = top_p.wt;
1793
1794 if (run_mode == RM_SUPERPOSITION) {
1795 superpos_geom->setActiveByIndex(active_source);
1796 }
1797
1798 if (recycle_opts) {
1800 } else if (single_generator && active_source > 0) {
1801 copyParticleToSourceLoc(&top_p, active_source, true, false, wt);
1802 }
1803
1804 return 0;
1805
1806 }
1807
1808 /* handle bcse and splitting */
1809 doPhotonSplitting(iarg);
1810
1811
1812 /* And finally below here we handle dose scoring */
1813 bool in_vaccuum = the_useful->medium <= 0;
1814 bool score_tracklength = score_tlen && is_photon && is_before_transport;
1815 bool score_interaction = score_edep && iarg <= ExtraEnergy;
1816 bool dose_scoring_not_needed = !is_extra_scoring_reg && (!in_phantom || in_vaccuum || !(score_tracklength || score_interaction));
1817
1818 if (dose_scoring_not_needed) {
1819 return 0;
1820 }
1821
1822
1823 // which phantom/region are we in
1824 int phant_idx = ginfo.phantomFromRegion(global_ir);
1825 int phant_ir = ginfo.globalToLocalReg(global_ir);
1826
1827 EB_Phantom *phant = phantom_geoms[phant_idx];
1828
1829 bool needs_vol_cor = run_mode == RM_SUPERPOSITION && superpos_geom->hasInactiveGeom(global_ir);
1830
1831
1832 if (score_tracklength) {
1833
1834 EGS_Interpolator *interp = media_muen[the_useful->medium-1];
1835 EGS_Float muen_val = interp ? interp->interpolateFast(the_epcont->gle) : 0;
1836 EGS_Float tracklength_edep = the_epcont->tvstep*top_p.E*muen_val*top_p.wt;
1837
1838 EGS_Float vol;
1839
1840 if (in_phantom){
1841 if (needs_vol_cor) {
1842 vol = phant->getUncorrectedVolume(phant_ir);
1843 } else {
1844 vol = phant->getCorrectedVolume(phant_ir);
1845 }
1846
1847 if (vol > 0) {
1848 phant->scoreTlen(phant_ir, tracklength_edep / vol, &top_p);
1849 }
1850 }
1851
1852 if (is_extra_scoring_reg){
1853 vol = extra_scoring_vols[local_geom_name][extra_reg_dose_index];
1854 extra_scoring_doses[local_geom_name]->score(extra_reg_dose_index, tracklength_edep / vol);
1855 }
1856 }
1857
1858 if (score_interaction) {
1859
1860 EGS_Float mass;
1861
1862 EGS_Float edep = getEdep()*top_p.wt;
1863
1864 if (in_phantom){
1865
1866 if(needs_vol_cor) {
1867 mass = phant->getUncorrectedMass(phant_ir);
1868 } else {
1869 mass = phant->getRealMass(phant_ir);
1870 }
1871
1872 if (mass > 0) {
1873 phant->scoreEdep(phant_ir, edep / mass);
1874 }
1875 }
1876
1877 if (is_extra_scoring_reg){
1878 mass = extra_scoring_mass[local_geom_name][extra_reg_dose_index];
1879 extra_scoring_doses[local_geom_name]->score(extra_reg_dose_index, edep / mass);
1880 }
1881 }
1882
1883 return 0;
1884}
1885
1887
1888 bool is_phat = fabs(top_p.wt - 1.) < EB_EPSILON;
1889
1890 if (do_bcse) {
1891
1892 bool in_bcse_med = the_useful->medium - 1 == bcse_med_num;
1893
1894 if (iarg == BeforeBrems) {
1895 the_egsvr->nbr_split = do_brem_split ? nbr_split : 1;
1896 if (!in_bcse_med) {
1897 /* standard UBS for brem photons OUTSIDE MED_BCSE */
1898 the_egsvr->nbr_split *= (int)bcse_factor;
1899 }
1900 } else if (iarg == AfterBrems) {
1901 if (in_bcse_med) {
1902 /* Just came back from a brem event in MED_BCSE, reduce photon weight
1903 and play Russian Roulette to whether or not reduce electron energy */
1904 for (int ip=the_stack->npold; ip < the_stack->np; ip++) {
1905 the_stack->wt[ip] /= bcse_factor;
1906 }
1907 EGS_Float rnd = rndm->getUniform();
1908 if (rnd > 1./bcse_factor) {
1909 the_stack->E[the_stack->npold-1] += top_p.E;
1910 }
1911 } else {
1912 /* Turn off UBS after splitting that one fat brem photons outside MED_BCSE */
1913 the_egsvr->nbr_split = 1;
1914 }
1915
1916 } else if (iarg == FluorescentEvent && is_phat) {
1917
1918 /* Uniformly splits fat relaxation photons that are descendents of either:
1919 1. eii in MED_BCSE (usually MED_BCSE is the target) or, 2.
1920 back-scattered fat electrons that escaped target and interacted
1921 elsewhere (eii and photo) This is done using UNIFORM_PHOTONS */
1922
1923 int nsplit = do_brem_split ? (int)(bcse_factor*nbr_split) : (int)(bcse_factor);
1924 the_stack->npold = the_stack->np;
1925 F77_OBJ_(egs_uniform_photons, EGS_UNIFORM_PHOTONS)(&nsplit, &top_p.E);
1926
1927 }
1928
1929 } else if (do_brem_split && iarg == FluorescentEvent && is_phat) {
1930
1931 /* a fluorescent photon has just been put on the stack - split it */
1932 the_stack->npold = the_stack->np;
1933 F77_OBJ_(egs_uniform_photons, EGS_UNIFORM_PHOTONS)(&nbr_split, &top_p.E);
1934 }
1935
1936}
1937
1939
1940 if (is_phsp_source) {
1941 effective_histories = source->getFluence();
1942 } else {
1943 effective_histories = last_case;
1944 }
1945
1946 if (recycle_opts) {
1947 if (run_mode == RM_SUPERPOSITION) {
1948 // only recycle at 1 source location in superposition mode
1949 effective_histories *= recycle_opts->nrecycle;
1950 } else {
1952 }
1953 }
1954}
1955
1956
1958 timing_blocks.addTimer("egs_brachy::outputResults");
1959
1961
1962 string sep(80, '=');
1963 egsInformation(
1964 "\n\nResults for egs_brachy run\n%s\n",
1965 string(80, '-').c_str()
1966 );
1967
1968
1969 egsInformation("\n\nHistory Information\n%s\n",sep.c_str());
1970 egsInformation("Last case = %llu\n", last_case);
1971 egsInformation("current case = %llu\n", current_case);
1972 egsInformation("run->getNcase() = %llu\n", run->getNcase());
1973 egsInformation("source->getFluence() = %f\n", source->getFluence());
1974 if (recycle_opts) {
1975 egsInformation("Particles recycled = %d\n", recycle_opts->nrecycle);
1976 }
1977 egsInformation("Effective histories = %.5G\n", effective_histories);
1978
1979
1980 egsInformation("\n\nGeometry Errors\n%s\n", sep.c_str());
1981 egsInformation("Number of geometry errors (/max allowed) = %d / %d\n", run->geomErrorCount, run->geomErrorMax);
1982 egsInformation("Number of 'stuck' particles discarded = %llu\n", n_stuck);
1983
1984
1985 // tell scoring objects how many histories were actually run
1986 // (needed for parallel run normalization)
1987 EGS_I64 hist_norm = run->getNdone();
1988 pevent_pub.notify(NEW_HISTORY, &hist_norm);
1989
1990 if (!single_generator) {
1991 egsInformation(
1992 "Warning: Stats about energy escaping source may not be accurate when "
1993 "not using a single source generator\n"
1994 );
1995 }
1996
1997 if (phsp) {
1998 phsp->finish(current_case);
1999 phsp->outputResults();
2000 phsp->destroySource();
2001 }
2002
2003 if (escoring) {
2004 escoring->outputResults();
2005 }
2006
2007 if (spectrum_scorers.size() > 0) {
2008 egsInformation("\nSpectrum scoring results\n%s\n",sep.c_str());
2009 string root = constructIOFileName("", true);
2010 vector<BaseSpectrumScorer *>::iterator it = spectrum_scorers.begin();
2011 for (; it != spectrum_scorers.end(); it++) {
2012 (*it)->setEffectiveHistories(effective_histories);
2013 (*it)->outputResults(root);
2014 }
2015 }
2016
2017 if (record_n_init > 0) {
2018
2019 string fname = constructIOFileName("", true)+".pinit";
2020 ofstream out;
2021 out.open(fname.c_str());
2022 out << std::fixed << std::showpoint << std::setprecision(6);
2023 for (vector<EGS_Vector>::iterator it = p_init_locs.begin(); it != p_init_locs.end(); ++it) {
2024 out << (*it).x << "\t" << (*it).y << "\t" << (*it).z << "\n";
2025 }
2026 out.close();
2027 egsInformation("\nInitial Particle Positions\n%s\n",sep.c_str());
2028 egsInformation("%d Initial particle positions written to .pinit file\n", p_init_locs.size());
2029 }
2030
2031 timing_blocks.addTimer("egs_brachy::outputPhantomResults");
2032 for (vector<EB_Phantom *>::iterator p = phantom_geoms.begin(); p != phantom_geoms.end(); p++) {
2033 (*p)->setEffectiveHistories(effective_histories);
2034 bool output_vc = find(output_volcor_phantoms.begin(), output_volcor_phantoms.end(),
2035 (*p)->geometry->getName()) != output_volcor_phantoms.end();
2036 string dd_format = output_3ddose_files ? output_dose_format : "";
2037 string vc_format = output_vc ? output_volcor_format : "";
2038 string ep_format = output_egsphant ? output_egsphant_format : "";
2039 string vi_format = output_voxinfo ? output_voxinfo_format : "";
2040 (*p)->outputResults(20, dd_format, ep_format, vi_format, vc_format);
2041 }
2042
2043 timing_blocks.stopTimer();
2044
2045 egsInformation("\nStep Counts\n%s\n", sep.c_str());
2046 EGS_Float total_steps = 0;
2047
2048 for (int i=-1; i < 2; i++) {
2049 total_steps += steps_in_sources[i];
2050 total_steps += steps_in_phantoms[i];
2051 total_steps += steps_in_other[i];
2052 }
2053
2054 egsInformation("Total particle steps : %20llu\n", (EGS_I64)total_steps);
2055 for (int i=-1; i < 2; i++) {
2056 if (steps_in_sources[i] > 0) {
2057 egsInformation("q=%2d Steps taken in sources : %20llu (%.2f%%)\n", i, steps_in_sources[i],
2058 100*steps_in_sources[i]/total_steps);
2059 }
2060 if (steps_in_phantoms[i] > 0) {
2061 egsInformation("q=%2d Steps taken in phantoms : %20llu (%.2f%%)\n", i, steps_in_phantoms[i],
2062 100*steps_in_phantoms[i]/total_steps);
2063 }
2064 if (steps_in_other[i] > 0) {
2065 egsInformation("q=%2d Steps taken in other objects : %20llu (%.2f%%)\n", i, steps_in_other[i],
2066 100*steps_in_other[i]/total_steps);
2067 }
2068 }
2069
2070 timing_blocks.stopTimer();
2071 timing_blocks.outputInfo();
2072
2073
2074}
2075
2076
2077void EB_Application::getCurrentResult(double &sum, double &sum2, double &norm, double &count) {
2078
2079 count = current_case;
2081 gcr_phantom->setEffectiveHistories(effective_histories);
2082 gcr_phantom->getCurrentScore(gcr_phantom_reg, sum, sum2);
2083 norm=gcr_phantom->getTlenNorm(gcr_phantom_reg);
2084
2085}
2086
2088 timing_blocks.addTimer("egs_brachy::runSimulation");
2089 int result = EGS_Application::runSimulation();
2090 timing_blocks.stopTimer();
2091 return result;
2092}
2093
2094/* \brief initialize a particle from source and then transform to next source */
2096
2097 last_case = current_case;
2098
2099 current_case = source->getNextParticle(rndm, p.q, p.latch, p.E, p.wt, p.x, p.u);
2100
2101 int initial_source;
2103 initial_source = active_source;
2104 } else {
2105 initial_source = 0;
2106 }
2107
2109
2110 if (run_mode == RM_SUPERPOSITION) {
2111 superpos_geom->setActiveByIndex(initial_source);
2112 }
2113
2114 // transform particle to position of next source
2115 source_transforms[initial_source]->transform(p.x);
2116 source_transforms[initial_source]->rotate(p.u);
2117
2118 p.ir = geometry->isWhere(p.x);
2119
2120 if (p.ir < 0) {
2121 egsWarning("EB_Application::simulateSingleShower() - particle initiated at (x, y, z) = (%.2g, %.2g, %.2g)\n", p.x.x, p.x.y, p.x.z);
2122 egsFatal("EB_Application::simulateSingleShower() - Particle initiated outside "
2123 "the geometry! Please check your source locations.\n");
2124 }
2125
2126 if (is_phsp_source) {
2127 // we assume phase space particles are outside the source
2129
2130 // set up stack with particles if recyling and phsp source
2131 if (recycle_opts) {
2133 }
2134 } else if (!ginfo.isSource(p.ir)) {
2135
2136 GeomRegT r = ginfo.globalToLocal(p.ir);
2137
2139 egsFatal(
2140 "Particle started in region %d (%s reg %d) which is outside a source geometry. Please check your geometry\n",
2141 p.ir,
2142 r.first->getName().c_str(),
2143 r.second
2144 );
2145
2146 }
2147
2148 if (record_n_init > 0 && (int)p_init_locs.size() < record_n_init) {
2149 p_init_locs.push_back(p.x);
2150 }
2151
2152 cur_R = p.x.length2();
2153 last_R = cur_R;
2155
2156 int err = startNewShower();
2157 if (err) {
2158 return err;
2159 }
2160
2161 // shower() just resets the stack before calling egsShower() but when using
2162 // a phsp source with recycling, we've already set up stack so go straight
2163 // to egsShower() in that case;
2165 err = 0;
2166 egsShower();
2167 } else {
2168 err = shower();
2169 }
2170
2171 active_source++;
2172 if (active_source == nsources) {
2173 active_source =0;
2174 }
2175
2176 return err || finishShower();
2177}
2178
2179
2181
2182
2183 // notify subscribers a valid particle has been initialized
2184 pevent_pub.notify(PARTICLE_INITIALIZED, &p);
2185
2186 // sets current case in ausgab objects
2187 int err = EGS_Application::startNewShower();
2188
2189 if (err) {
2190 return err;
2191 }
2192
2193 // now set current case in all phantom objects
2194 if (current_case != last_case) {
2195
2196 pevent_pub.notify(NEW_HISTORY, &current_case);
2197
2198 last_case = current_case;
2199 }
2200
2201 return 0;
2202}
2203
2204
2205/* start of stop/restart functionality ****************************************/
2207 /* adapted from egs_application.cpp::outputData */
2208 if (!run->storeState(*out)) {
2209 return 2;
2210 }
2211 if (!egsStoreI64(*out,current_case)) {
2212 return 3;
2213 }
2214 (*out) << "\n";
2215 if (!rndm->storeState(*out)) {
2216 return 4;
2217 }
2218 if (!source->storeState(*out)) {
2219 return 5;
2220 }
2221 for (size_t j=0; j<a_objects_list.size(); ++j) {
2222 if (!a_objects_list[j]->storeState(*out)) {
2223 return 6;
2224 }
2225 }
2226
2227 return 0;
2228}
2229
2231 /* adapted from egs_advanced_application.cpp::outputData */
2232 EGS_I32 np, ip;
2233 egsGetRNGPointers(&np,&ip);
2234 if (np < 1) {
2235 return 11;
2236 }
2237 if (np > 10000000) {
2238 egsWarning("EGS_AdvancedApplication::outputData(): egsGetRNGPointers"
2239 " returns a huge number? (%d)\n",np);
2240 return 12;
2241 }
2242 EGS_Float *array = new EGS_Float [np];
2243 egsGetRNGArray(array);
2244 (*out) << " " << np << " " << ip << "\n";
2245 for (int j=0; j<np; j++) {
2246 (*out) << array[j] << " ";
2247 }
2248 (*out) << "\n";
2249 double ch_steps, all_steps;
2250 egsGetSteps(&ch_steps,&all_steps);
2251 (*out) << ch_steps << " " << all_steps << "\n";
2252 delete [] array;
2253 return out->good() ? 0 : 13;
2254
2255}
2256
2258
2259 int err;
2260
2261 (*out) << std::setprecision(9);
2262
2263 for (int i=-1; i < 2; i++) {
2264 (*out) << steps_in_sources[i] << " ";
2265 (*out) << steps_in_phantoms[i] << " ";
2266 (*out) << steps_in_other[i] << "\n";
2267 }
2268
2269 if (escoring) {
2270 err= escoring->outputData(out);
2271 if (err) {
2272 return err;
2273 }
2274 }
2275
2276 vector<BaseSpectrumScorer *>::iterator spec_it = spectrum_scorers.begin();
2277 for (; spec_it != spectrum_scorers.end(); ++spec_it) {
2278 err = (*spec_it)->outputData(out);
2279 if (err) {
2280 return err;
2281 }
2282 }
2283
2284 vector<EB_Phantom *>::iterator phant_it = phantom_geoms.begin();
2285 for (; phant_it != phantom_geoms.end(); phant_it++) {
2286 err = (*phant_it)->outputData(out);
2287 if (err) {
2288 return err;
2289 }
2290 }
2291
2292 return 0;
2293
2294}
2295
2297
2298 int err = egsApplicationOutputData(out);
2299 if (err) {
2300 return err;
2301 }
2302 err = egsAdvApplicationOutputData(out);
2303 if (err) {
2304 return err;
2305 }
2306
2307 return egsBrachyOutputData(out);
2308}
2309
2311
2312 timing_blocks.addTimer("egs_brachy::outputData");
2313
2314 bool use_gz = output_egsdat_format == "gzip";
2315 string extension(".egsdat");
2316 extension += (use_gz ? ".gz" : "");
2317 string ofile = constructIOFileName(extension.c_str(), true);
2318
2319 int err;
2320 if (use_gz) {
2321 if (gz_data_out) {
2322 delete gz_data_out;
2323 }
2324 gz_data_out = new ogzstream(ofile.c_str());
2325
2326 if (!(gz_data_out)) {
2327 egsWarning("EGS_Application::outputData: failed to open %s for writing\n",ofile.c_str());
2328 timing_blocks.stopTimer();
2329 return 1;
2330 }
2332 gz_data_out->close();
2333 } else {
2334
2335 if (data_out) {
2336 delete data_out;
2337 }
2338 data_out = new ofstream(ofile.c_str());
2339 if (!(*data_out)) {
2340 egsWarning("EGS_Application::outputData: failed to open %s for writing\n",ofile.c_str());
2341 timing_blocks.stopTimer();
2342 return 1;
2343 }
2344 err = outputDataHelper(data_out);
2345 }
2346
2347 timing_blocks.stopTimer();
2348 return err;
2349
2350}
2351
2353 /* adapted from egs_application.cpp::readData */
2354 if (!run->setState(*in)) {
2355 return 2;
2356 }
2357 if (!egsGetI64(*in,current_case)) {
2358 return 3;
2359 }
2360 last_case = current_case;
2361 if (!rndm->setState(*in)) {
2362 return 4;
2363 }
2364 if (!source->setState(*in)) {
2365 return 5;
2366 }
2367 for (int j=0; j<a_objects_list.size(); ++j) {
2368 if (!a_objects_list[j]->setState(*in)) {
2369 return 6;
2370 }
2371 }
2372 return 0;
2373}
2374
2376 /* adapted from egs_advanced_application.cpp::readData */
2377 int np, ip;
2378 (*in) >> np >> ip;
2379 if (np < 1) {
2380 return 11;
2381 }
2382 if (np > 10000000) {
2383 egsWarning("EB_Application::egsAdvApplicationReadData(): got huge size "
2384 "for the mortran random array? (%d)\n",np);
2385 return 12;
2386 }
2387 EGS_Float *array = new EGS_Float [np];
2388 for (int j=0; j<np; j++) {
2389 (*in) >> array[j];
2390 }
2391 if (!in->good()) {
2392 return 13;
2393 }
2394 egsSetRNGState(&ip,array);
2395 delete [] array;
2396 double ch_steps, all_steps;
2397 (*in) >> ch_steps >> all_steps;
2398 egsSetSteps(&ch_steps,&all_steps);
2399 return in->good() ? 0 : 13;
2400
2401}
2402
2404 int err;
2405
2406 for (int i=-1; i < 2; i++) {
2407 (*in) >> steps_in_sources[i];
2408 (*in) >> steps_in_phantoms[i];
2409 (*in) >> steps_in_other[i];
2410 }
2411
2412 if (escoring) {
2413 err= escoring->readData(in);
2414 if (err) {
2415 return err;
2416 }
2417 }
2418
2419 vector<BaseSpectrumScorer *>::iterator spec_it = spectrum_scorers.begin();
2420 for (; spec_it != spectrum_scorers.end(); ++spec_it) {
2421 err = (*spec_it)->readData(in);
2422 if (err) {
2423 return err;
2424 }
2425 }
2426
2427 vector<EB_Phantom *>::iterator phant_it = phantom_geoms.begin();
2428 for (; phant_it != phantom_geoms.end(); phant_it++) {
2429 err = (*phant_it)->readData(in);
2430 if (err) {
2431 return err;
2432 }
2433 }
2434 return 0;
2435
2436}
2437
2439
2440 int err = egsApplicationReadData(in);
2441 if (err) {
2442 return err;
2443 }
2444 err = egsAdvApplicationReadData(in);
2445 if (err) {
2446 return err;
2447 }
2448
2449 return egsBrachyReadData(in);
2450}
2451
2452/* start of stop/restart functionality ****************************************/
2454
2455 timing_blocks.addTimer("egs_brachy::readData");
2456
2457 bool use_gz = output_egsdat_format == "gzip";
2458 string extension(".egsdat");
2459 extension += (use_gz ? ".gz" : "");
2460 string ifile = constructIOFileName(extension.c_str(), false);
2461
2462 int err;
2463 if (use_gz) {
2464 if (gz_data_in) {
2465 delete gz_data_in;
2466 }
2467 gz_data_in = new igzstream(ifile.c_str());
2468
2469 if (!(gz_data_in)) {
2470 egsWarning("EGS_Application::readData: failed to open %s for reading\n", ifile.c_str());
2471 timing_blocks.stopTimer();
2472 return 1;
2473 }
2475 } else {
2476
2477 if (data_in) {
2478 delete data_in;
2479 }
2480 data_in = new ifstream(ifile.c_str());
2481 if (!(*data_in)) {
2482 egsWarning("EGS_Application::readData: failed to open %s for writing\n",ifile.c_str());
2483 timing_blocks.stopTimer();
2484 return 1;
2485 }
2486 err = readDataHelper(data_in);
2487 }
2488
2489 timing_blocks.stopTimer();
2490 return err;
2491
2492}
2493
2494
2496 /* Adapted from egs_application.cpp::combineResults */
2497 egsInformation(
2498 "\n Suming the following .egsdat files:\n"
2499 "=======================================================================\n");
2500 char buf[512];
2501 resetCounter();
2502 EGS_Float last_cpu = 0;
2503 EGS_I64 last_ncase = 0;
2504 int ndat = 0;
2505 bool ok = true;
2506 for (int j=1; j<500; j++) {
2507
2508 bool use_gz = output_egsdat_format == "gzip";
2509 string name("%s_w%d.egsdat");
2510 name += (use_gz ? ".gz" : "");
2511
2512 sprintf(buf, name.c_str(), output_file.c_str(), j);
2513 string dfile = egsJoinPath(app_dir,buf);
2514 istream *data;
2515 ifstream in;
2516 igzstream gzin;
2517 bool opened = false;
2518 if (use_gz) {
2519 gzin.open(dfile.c_str());
2520 opened = gzin.rdbuf()->is_open();
2521 data = &gzin;
2522 } else {
2523 in.open(dfile.c_str());
2524 opened = in.is_open();
2525 data = &in;
2526 }
2527
2528 if (opened) {
2529 int err = addState(*data);
2530 ++ndat;
2531 if (!err) {
2532 EGS_I64 ncase = run->getNdone();
2533 EGS_Float cpu = run->getCPUTime();
2534 egsInformation("%2d %-30s ncase=%-14lld cpu=%-11.2f\n",
2535 ndat,buf,ncase-last_ncase,cpu-last_cpu);
2536 last_ncase = ncase;
2537 last_cpu = cpu;
2538 } else {
2539 ok = false;
2540 egsWarning("%2d %-30s error %d\n",ndat,buf,err);
2541 }
2542 }
2543 }
2544 if (ndat > 0) {
2545 egsInformation(
2546 "=======================================================================\n");
2547 egsInformation("%40s%-14lld cpu=%-11.2f\n\n","Total ncase=",last_ncase,
2548 last_cpu);
2549 }
2550 if (ndat > 0) {
2551 return ok ? 0 : -1;
2552 } else {
2553 return 1;
2554 }
2555}
2556
2558 // Reset everything in the base class
2559 EGS_AdvancedApplication::resetCounter();
2560 // Reset our own data to zero.
2561
2562 for (int i=-1; i < 2; i++) {
2563 steps_in_sources[i] = 0;
2564 steps_in_phantoms[i] = 0;
2565 steps_in_other[i] = 0;
2566 }
2567
2568 if (escoring) {
2569 escoring->resetCounter();
2570 }
2571
2572 vector<BaseSpectrumScorer *>::iterator spec_it = spectrum_scorers.begin();
2573 for (; spec_it != spectrum_scorers.end(); ++spec_it) {
2574 (*spec_it)->resetCounter();
2575 }
2576
2577 vector<EB_Phantom *>::iterator phant_it = phantom_geoms.begin();
2578 for (; phant_it != phantom_geoms.end(); phant_it++) {
2579 (*phant_it)->resetCounter();
2580 }
2581
2582}
2583
2584int EB_Application::addState(istream &data) {
2585 // Call first the base class addState() function to read and add
2586 // all data related to source, RNG, CPU time, etc.
2587 int err = EGS_AdvancedApplication::addState(data);
2588 if (err) {
2589 return err;
2590 }
2591
2592 for (int i=-1; i < 2; i++) {
2593 EGS_I64 steps_in_sources_tmp;
2594 EGS_I64 steps_in_phantoms_tmp;
2595 EGS_I64 steps_in_other_tmp;
2596
2597 data >> steps_in_sources_tmp;
2598 data >> steps_in_phantoms_tmp;
2599 data >> steps_in_other_tmp;
2600
2601 steps_in_sources[i] += steps_in_sources_tmp;
2602 steps_in_phantoms[i] += steps_in_phantoms_tmp;
2603 steps_in_other[i] += steps_in_other_tmp;
2604 }
2605
2606 if (escoring) {
2607 err = escoring->addState(data);
2608 if (err) {
2609 return err;
2610 }
2611 }
2612
2613 vector<BaseSpectrumScorer *>::iterator spec_it = spectrum_scorers.begin();
2614 for (; spec_it != spectrum_scorers.end(); ++spec_it) {
2615 err = (*spec_it)->addState(data);
2616 if (err) {
2617 return err;
2618 }
2619 }
2620
2621 vector<EB_Phantom *>::iterator phant_it = phantom_geoms.begin();
2622 for (; phant_it != phantom_geoms.end(); phant_it++) {
2623 err = (*phant_it)->addState(data);
2624 if (err) {
2625 return err;
2626 }
2627 }
2628
2629 return 0;
2630
2631}
2632/* end of stop/restart functionality ****************************************/
2633
2634bool fileExists(const string &name) {
2635 struct stat buffer;
2636 return (stat(name.c_str(), &buffer) == 0);
2637}
2638
2640
2641 char buf[512];
2642 int n_of_egsdat = 0;
2643
2644 bool use_gz = output_egsdat_format == "gzip";
2645 string name("%s_w%d.egsdat");
2646 name += (use_gz ? ".gz" : "");
2647
2648 for (int i = first_parallel; i < first_parallel + n_parallel; i++) {
2649 sprintf(buf,name.c_str(),final_output_file.c_str(),i);
2650 string dfile = egsJoinPath(app_dir,buf);
2651 if (fileExists(dfile)) {
2652 n_of_egsdat++;
2653 }
2654 }
2655
2656 return n_of_egsdat;
2657}
2658
2660 EGS_RunControl(a), app(a), output_egsdat_format(egsdat_format), milliseconds(1000), check_intervals(5),
2661 njob(0), npar(app->getNparallel()), ipar(app->getIparallel()), ifirst(app->getFirstParallel()),
2662 check_egsdat(true), watcher_job(false) {
2663
2664 rco_type = uniform;
2665
2666 if (input) {
2667
2668 /*Change waiting time to check for parallel run completion*/
2669 int dummy;
2670 int err = input->getInput("interval wait time", dummy);
2671 if (!err) {
2672 milliseconds = dummy;
2673 }
2674
2675 /*Change how many times to check for parallel run completion*/
2676 err = input->getInput("number of intervals", dummy);
2677 if (!err) {
2678 check_intervals = dummy;
2679 }
2680
2681 /* Define watcher jobs to check for parallel run completion*/
2682 vector<int> w_jobs;
2683 err = input->getInput("watcher jobs", w_jobs);
2684 if (!err) {
2685 for (int i = 0; i < w_jobs.size(); i++) {
2686 if (ipar == w_jobs[i]) {
2687 watcher_job = true;
2688 break;
2689 }
2690 }
2691 }
2692 else { // use defaults
2693 /* last job is watcher job */
2694 if (ipar == ifirst + npar - 1) {
2695 watcher_job = true;
2696 }
2697 else {
2698 watcher_job = false;
2699 }
2700 }
2701
2702 /* Request checking parallel run completion */
2703 vector<string> check_options;
2704 check_options.push_back("yes");
2705 check_options.push_back("no");
2706 int ichk = input->getInput("check jobs completed",check_options,0);
2707 if (ichk != 0) {
2708 check_egsdat = false; // true by default
2709 }
2710
2711 }
2712 else { // use defaults if no RCO input found
2713 /* last job is watcher job */
2714 if (ipar == ifirst + npar - 1) {
2715 watcher_job = true;
2716 }
2717 }
2718}
2719
2721
2722
2723 /* Check run completion based on *egsdat files requires erasing
2724 existing files from previous runs.
2725 */
2726 bool use_gz = output_egsdat_format == "gzip";
2727 string name("%s_w%d.egsdat");
2728 name += (use_gz ? ".gz" : "");
2729
2730 if (check_egsdat) {
2731 char buf[512];
2732 sprintf(buf,name.c_str(),app->getFinalOutputFile().c_str(), ipar);
2733 string datFile = egsJoinPath(app->getOutputDir(),buf);
2734 if (remove(datFile.c_str()) == 0) {
2735 egsWarning("EB_UniformRunControl: %s deleted\n",
2736 datFile.c_str());
2737 }
2738 }
2739
2740 return EGS_RunControl::startSimulation();
2741}
2742
2744
2745 EGS_RunControl::describeRCO();
2746
2747 if (watcher_job) {
2748 if (check_egsdat) {
2749 egsInformation(
2750 " Watcher job: remains running after completion checking\n"
2751 " for other jobs finishing every %d s for %d s!\n",
2753 }
2754 else {
2755 egsInformation(
2756 " Option to check for finishing jobs is OFF!\n\n");
2757 }
2758 }
2759
2760}
2761
2762void rco_sleep(const int &mscnds) {
2763#ifdef WIN32
2764 Sleep(mscnds);
2765#else
2766 usleep(mscnds * 1000);
2767#endif
2768}
2769
2771 int err = EGS_RunControl::finishSimulation();
2772 if (err < 0) {
2773 return err;
2774 }
2775 /* Check and wait for all jobs to finish */
2776 if (watcher_job) {
2777 int interval = 0, njobs_done = 0, njobs_done_old= 0;
2778 while (interval < check_intervals) {
2780 if (check_egsdat) {
2781 njobs_done = app->howManyJobsDone();
2782 //egsInformation("\n-> Finished %d jobs...\n",njobs_done);
2783 if (njobs_done == npar - 1) {
2784 watcher_job=false;//don't enter this after all jobs done!
2785 break;
2786 }
2787 // Only combine if new jobs finished
2788 if (njobs_done_old < njobs_done) {
2789 egsInformation("=> Combining %d jobs ...\n",njobs_done);
2790 app->combinePartialResults();
2791 }
2792 njobs_done_old = njobs_done;
2793 }
2794 interval++;
2795 }
2796 return 1;
2797 }
2798 /*I am not a watcher job, do not combine results yet!*/
2799 return 0;
2800}
2801
2802#ifdef BUILD_APP_LIB
2803APP_LIB(EB_Application);
2804#else
2806#endif
abstract base class for scoring spectrum information
static BaseSpectrumScorer * getSpectrumScorer(EGS_Input *inp, EGS_BaseSource *source, GeomInfo *ginfo, Publisher *publisher)
factory method for creating one of the derived spectrum scoring classes
virtual string getInfo() const
The main egs_brachy application class. See the Main Page for full documentation.
Definition egs_brachy.h:91
vector< BaseSpectrumScorer * > spectrum_scorers
Definition egs_brachy.h:104
map< string, vector< EGS_Float > > extra_scoring_mass
Definition egs_brachy.h:183
int initRunControl()
egs_brachy specific run control initialization
void initPHSPScoring(EGS_Input *)
set up phsp scoring
int checkSourceOverlaps(EGS_Input *)
EnergyScoringStats * escoring
Energy related scoring/stats.
Definition egs_brachy.h:103
int initSimulation()
set the run mode and then call EGS_AdvancedApplication::initSimulation
void initEDepScoring(EGS_Input *)
energy deposition scoring initialization
void copyParticleToSourceLoc(EGS_Particle *p, int source, bool kill_orig, bool rotate, EGS_Float new_wt)
void doPhotonSplitting(int)
int outputData()
Output intermediate results. The egs_brachy version outputs the standard egs++ data along with egs_br...
vector< EGS_AffineTransform * > source_transforms
transforms to locations of all sources
Definition egs_brachy.h:147
map< string, vector< int > > extra_scoring_reg
Definition egs_brachy.h:181
void initDoseScaling(EGS_Input *)
Initialize dose scaling factor if requested.
map< int, EGS_I64 > steps_in_phantoms
Definition egs_brachy.h:196
int initSourceTransforms()
read in the location of all particle sources and optionally apply a source coordinate transform mappi...
EGS_I64 n_stuck
Definition egs_brachy.h:140
int outputDataHelper(ostream *)
helper function for outputData
EB_TimingTree timing_blocks
Track CPU times of various functions.
Definition egs_brachy.h:193
int initRussianRoulette(EGS_Input *)
Initialize Russian roulette variance reduction if requested.
map< string, EGS_ScoringArray * > extra_scoring_doses
Definition egs_brachy.h:184
string output_volcor_format
text or gzip
Definition egs_brachy.h:131
int createPhantoms()
set up Phantom objects for any geometries that user has requested scoring for
Publisher pevent_pub
Particle event publisher.
Definition egs_brachy.h:191
virtual void startNewParticle()
Set source ecut/pcut if different from global ecut/pcut.
void describeUserCode() const
Print information about the egs_brachy user code.
int initRunMode()
Get run mode from the input file.
void describeSimulation()
Describe the simulation.
void enableAusgabCalls(int ncalls, AusgabCall calls[])
enable an array of ausgab calls
void initAusgabCalls()
setup any required ausgab calls
void initMuenData(EGS_Input *)
load muen data for requested media
string output_egsdat_format
text or gzip
Definition egs_brachy.h:120
string run_mode_name
Definition egs_brachy.h:101
vector< string > output_volcor_phantoms
vector of phantom names to output volume correctino files for
Definition egs_brachy.h:130
string output_voxinfo_format
text or gzip
Definition egs_brachy.h:128
igzstream * gz_data_in
GZip file for outputing egsdat.
Definition egs_brachy.h:200
EGS_Float last_R
Definition egs_brachy.h:137
EGS_Float global_e_max_rr
max range rejection energy globally
Definition egs_brachy.h:171
int egsAdvApplicationOutputData(ostream *)
helper function for outputData
void discardTopParticle(int idisc=1)
int gcr_phantom_reg
region of phantom to use for getCurrentResult (default to 0)
Definition egs_brachy.h:179
EGS_Float effective_histories
Definition egs_brachy.h:368
int initBCSE(EGS_Input *)
Initialize BCSE variance reduction if requested.
bool source_i_do_rr
enable range rejection in sources
Definition egs_brachy.h:173
bool output_egsphant
true if user requests egsphant ouput
Definition egs_brachy.h:124
Latch latch_control
Definition egs_brachy.h:370
void printIncludedFiles()
bool global_i_do_rr
enable range rejection outside of sources
Definition egs_brachy.h:170
EGS_Float source_pcut
pcut for source objects
Definition egs_brachy.h:166
EGS_Float bcse_factor
Definition egs_brachy.h:161
int egsBrachyReadData(istream *)
helper function for outputData
void initTrackLengthScoring(EGS_Input *)
track length scoring initialization
EGS_Float global_pcut
pcut for source objects
Definition egs_brachy.h:168
void getCurrentResult(double &sum, double &sum2, double &norm, double &count)
Reports the current results for this batch of the simulation.
int correctVolumes()
run the volume correction routines
bool output_3ddose_files
false if run mode is 'volume correction only'
Definition egs_brachy.h:122
void initSpectrumScoring(EGS_Input *)
Initialize all spectrum scoring objects.
EB_Phantom * gcr_phantom
phantom object to use in getCurrentResult (defaults to 1st phantom)
Definition egs_brachy.h:178
EB_Phantom * getPhantomByName(string name)
takes a phantom geometry name and returns the EB_Phantom object
void addRecycledParticlesToStack(EGS_Particle *p, bool new_hist=false)
static const EGS_Float DEFAULT_BCSE_FACTOR
Definition egs_brachy.h:162
map< string, string > media_muen_names
Definition egs_brachy.h:153
int readDataHelper(istream *)
helper function for outputData
void initScatScoring(EGS_Input *)
energy deposition scoring initialization
EGS_ASwitchedEnvelope * superpos_geom
an ASwitchedEnv cast of simulation geometry.
Definition egs_brachy.h:143
string output_dose_format
text or gzip
Definition egs_brachy.h:123
vector< EGS_Float > source_weights
Definition egs_brachy.h:111
vector< EGS_AffineTransform * > createTransforms(EGS_Input *input)
virtual void enterNewRegion()
map< string, vector< EGS_Float > > extra_scoring_vols
Definition egs_brachy.h:182
void resetCounter()
Reset the application to a 'pristine' state. Adapted from egs_application.cpp to allow combining in t...
EGS_AffineTransform * base_transform
same as source_transforms[0]
Definition egs_brachy.h:148
EGS_BaseGeometry * source_envelope_geom
geometry that the sources are embedded in
Definition egs_brachy.h:142
vector< EB_Phantom * > phantom_geoms
pointers to all of the phantom objects
Definition egs_brachy.h:145
void calcEffectiveHistories()
bool score_scat
true when scatter scoring is enabled
Definition egs_brachy.h:118
string output_egsphant_format
text or gzip
Definition egs_brachy.h:125
int egsBrachyOutputData(ostream *)
helper function for outputData
ogzstream * gz_data_out
GZip file for outputing egsdat.
Definition egs_brachy.h:199
int initCrossSections()
int nbr_split
Number of times to split bremstrahlung phtons.
Definition egs_brachy.h:157
map< int, EGS_Interpolator * > media_muen
Map from medium index to muen interpolator for that medium.
Definition egs_brachy.h:152
ebvolcor::Results gen_vc_results
results from general volume correction
Definition egs_brachy.h:188
EGS_AffineTransform * base_transform_inv
same as source_transforms[0].inverse()
Definition egs_brachy.h:149
map< int, EGS_I64 > steps_in_sources
Definition egs_brachy.h:195
bool output_voxinfo
true if user requests voxel info file
Definition egs_brachy.h:127
bool applied_source_coord_transform
true if a source coordinate transform was composed in
Definition egs_brachy.h:150
map< int, EGS_I64 > steps_in_other
Definition egs_brachy.h:197
PHSPControl * phsp
Definition egs_brachy.h:114
int ausgab(int iarg)
user scoring of dose, spectra etc
int readData()
Read data required for restarting simulations.
int egsApplicationReadData(istream *)
helper function for outputData
int nsources
total number of particle sources in current simulation
Definition egs_brachy.h:366
EGS_Float flu_cutoff
fluorescent photon cutoff energy
Definition egs_brachy.h:164
EGS_Float cur_R
Definition egs_brachy.h:138
@ RM_VC_ONLY
Run volume correction routines then quit.
Definition egs_brachy.h:96
@ RM_SUPERPOSITION
Superposition mode for intersource effects.
Definition egs_brachy.h:95
@ RM_NORMAL
Standard running mode.
Definition egs_brachy.h:94
int egsAdvApplicationReadData(istream *)
helper function for outputData
int egsApplicationOutputData(ostream *)
helper function for outputData
GeomInfo ginfo
meta data about the geometries
Definition egs_brachy.h:176
void clearAusgabCalls()
disable all ausgab calls
ebvolcor::Results source_vc_results
results from source volume correctio box phantom
Definition egs_brachy.h:187
void initXCCScaling(EGS_Input *)
Initialize cross section scaling if requested.
int simulateSingleShower()
EGS_Float source_ecut
ecut for source objects
Definition egs_brachy.h:165
bool score_edep
true when energy deposition is enabled
Definition egs_brachy.h:117
void initGCRScoring(EGS_Input *)
setup which phantom/region will be used for getCurrentResult
EGS_Float source_e_max_rr
max range rejection energy for source objects
Definition egs_brachy.h:174
int initScoring()
initialze all scoring and variance reduction parameters
int addState(istream &data)
Add data from a parallel job. Add standard egs++ data as well as egs_brachy specific scoring informat...
EGS_Float global_ecut
ecut for source objects
Definition egs_brachy.h:167
int initGeometry()
override default initGeometry so we can manually create our own geometry.
void initOutputFiles(EGS_Input *)
set up whether to output extra info files
int initVarianceReduction()
initialze all variance reduction parameters
vector< EGS_Vector > p_init_locs
Definition egs_brachy.h:134
bool score_tlen
true when tracklength estimator is enabled
Definition egs_brachy.h:116
RunMode run_mode
Which run mode are we using (RM_NORMAL, RM_SUPERPOSITION or RM_VC_ONLY *‍/.
Definition egs_brachy.h:100
RecycleOpts * recycle_opts
Definition egs_brachy.h:107
bool single_generator
Definition egs_brachy.h:108
int record_n_init
if > 0 write initial pos of record_n_init particles to {input_file}.pinit
Definition egs_brachy.h:133
ebvolcor::FileResults file_vc_results
results from precomputed volume correction
Definition egs_brachy.h:189
virtual int runSimulation()
A class to represent a single phantom for scoring dose in egs_brachy.
Definition phantom.h:71
@ YDIR
YDIR=1 y dir for rectilinear, r dir for cylindrical.
Definition phantom.h:137
@ XDIR
XDIR=0 x dir for rectilinear, r dir for spherical, z dir for cylindrical.
Definition phantom.h:136
@ ZDIR
ZDIR=2 z dir for rectilinear.
Definition phantom.h:138
void scoreTlen(int ir, EGS_Float dose, EGS_Particle *p)
add tracklength dose to region ir
Definition phantom.cpp:133
EGS_Float getUncorrectedVolume(int ireg)
get corrected volume for a given region
Definition phantom.cpp:302
EGS_BaseGeometry * geometry
the phantom geometry object
Definition phantom.h:284
bool needs_user_geoms
this phantom requires user specified geometries
Definition phantom.h:296
void scoreEdep(int ir, EGS_Float dose)
add energy deposition dose to region ir
Definition phantom.cpp:155
EGS_Float getRealMass(int ireg)
return (corrected) real mass for region
Definition phantom.cpp:291
void setCorrectedVolume(int ir, double fraction, double unc=0)
Allow user to tell phantom what the actual volume of a region is.
Definition phantom.cpp:202
EGS_Float getCorrectedVolume(int ireg)
get uncorrected volume for a given region
Definition phantom.cpp:314
EGS_Float getUncorrectedMass(int ireg)
return uncorrected for region
Definition phantom.cpp:298
EGS_Float avgVoxelVol()
return average voxel volume
Definition phantom.cpp:855
EB_UniformRunControl(EB_Application *app, string egsdat_format)
EB_Application * app
Definition egs_brachy.h:543
string output_egsdat_format
text or gzip
Definition egs_brachy.h:545
int finishSimulation()
Uses 'watcher' jobs to determine if the simulation has finished.
a class to use for scoring information about total energy initialzed, escaping sources etc
An object for controlling the volume correction routine.
Definition eb_volcor.h:316
Results runSourceCorrection(EB_TimingTree &timer)
Definition eb_volcor.h:371
Results runGeneralCorrection(EB_TimingTree &timer)
Definition eb_volcor.h:399
FileResults runFileCorrection(EB_TimingTree &timer)
Definition eb_volcor.h:427
int is_open()
Definition gzstream.h:64
void open(const char *name, int open_mode=std::ios::in)
Definition gzstream.h:108
gzstreambuf * rdbuf()
Definition gzstream.h:105
class for parsing muen data from a file.
Definition muen.h:131
int setMuenFile(string filename)
Definition muen.h:207
EGS_Interpolator * getMuenInterpolator(string med_name)
Create a new EGS_Interpolator of muen data for the requested medium and return pointer to it....
Definition muen.h:228
#define egsOpenUnits
#define egsGetRNGArray
#define egsGetSteps
void F77_OBJ_(egs_scale_xcc, EGS_SCALE_XCC)(const int *
#define egsGetPhotonData
map< string, string > getMuenForMedia(EGS_Input *scoring_options)
void rco_sleep(const int &mscnds)
bool fileExists(const string &name)
#define egsSetRNGState
bool containsInclude(string str)
#define egsGetRNGPointers
void const EGS_Float *void const EGS_Float *void const EGS_Float *void const EGS_Float *void printParticleWithSpherical(EGS_Particle p)
#define egsSetSteps
APP_MAIN(EB_Application)
#define egsGetElectronData
the main egs_brachy application header file
#define PRINT_PARTICLE_WITH_DIR(P)
Definition egs_brachy.h:82
#define EB_EPSILON
Definition egs_brachy.h:85
#define NUM_STUCK_STEPS
Definition egs_brachy.h:83
#define SAME_POSITION_TOLERANCE
Definition egs_brachy.h:84
pair< EGS_BaseGeometry *, int > GeomRegT
pair of geometry and local region number
Definition ginfo.h:79
EGS_Float getShapeVolume(EGS_Input *shape_inp)
get shape volume from a shape input item
Definition eb_volcor.cpp:77
pair< bool, EB_Message > EBSendMessage
Definition pubsub.h:69
@ PARTICLE_ESCAPING_SOURCE
Definition pubsub.h:60
@ NEW_HISTORY
Definition pubsub.h:56
@ PARTICLE_ESCAPED_SOURCE
Definition pubsub.h:61
@ PARTICLE_TAKING_STEP
Definition pubsub.h:58
@ PARTICLE_ESCAPED_GEOM
Definition pubsub.h:63
@ PARTICLE_TOOK_STEP
Definition pubsub.h:59
@ PARTICLE_INITIALIZED
Definition pubsub.h:57
@ PARTICLE_ESCAPING_GEOM
Definition pubsub.h:62
a struct to contain elementary information aboud a geometry
Definition ginfo.h:83
vector< string > children
Definition ginfo.h:87
string type
Definition ginfo.h:86
string name
Definition ginfo.h:85