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