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