EGSnrc C++ class library  Report PIRS-898 (2021)
Iwan Kawrakow, Ernesto Mainegra-Hing, Frederic Tessier, Reid Townson and Blake Walters
egs_application.cpp
Go to the documentation of this file.
1 /*
2 ###############################################################################
3 #
4 # EGSnrc egs++ application
5 # Copyright (C) 2015 National Research Council Canada
6 #
7 # This file is part of EGSnrc.
8 #
9 # EGSnrc is free software: you can redistribute it and/or modify it under
10 # the terms of the GNU Affero General Public License as published by the
11 # Free Software Foundation, either version 3 of the License, or (at your
12 # option) any later version.
13 #
14 # EGSnrc is distributed in the hope that it will be useful, but WITHOUT ANY
15 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16 # FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
17 # more details.
18 #
19 # You should have received a copy of the GNU Affero General Public License
20 # along with EGSnrc. If not, see <http://www.gnu.org/licenses/>.
21 #
22 ###############################################################################
23 #
24 # Author: Iwan Kawrakow, 2005
25 #
26 # Contributors: Frederic Tessier
27 # Ernesto Mainegra-Hing
28 # Blake Walters
29 # Reid Townson
30 # Hubert Ho
31 # Max Orok
32 # Alexandre Demelo
33 #
34 ###############################################################################
35 */
36 
37 
43 #include "egs_application.h"
44 #include "egs_functions.h"
45 #include "egs_input.h"
46 #include "egs_base_source.h"
47 #include "egs_rndm.h"
48 #include "egs_base_source.h"
49 #include "egs_simple_container.h"
50 #include "egs_ausgab_object.h"
51 #include "egs_base_geometry.h"
52 
53 #include <cstring>
54 #include <cstdio>
55 #include <cstdlib>
56 #include <vector>
57 #include <fstream>
58 #include <sys/types.h>
59 #include <sys/stat.h>
60 #include <unistd.h>
61 
62 using namespace std;
63 
64 #ifdef WIN32
65  const char fs = 92;
66  #define F_OK 0
67  #define W_OK 2
68  #define R_OK 4
69  #include <io.h>
70  #define EGS_ACCESS ::_access
71 #else
72  const char fs = '/';
73  #include <unistd.h>
74  #define EGS_ACCESS ::access
75  #include <sys/statvfs.h>
76 #endif
77 
78 #define MAXIMUM_JOB_NUMBER 8192 // GPSC1: 256 nodes with 16 cores (32 threads)
79 //#define MAXIMUM_JOB_NUMBER 1024
80 
81 static char __egs_app_msg1[] = "EGS_Application::EGS_Application(int,char**):";
82 static char __egs_app_msg2[] = "EGS_Application::initSimulation():";
83 static char __egs_app_msg3[] = "EGS_Application::runSimulation():";
84 
85 static EGS_LOCAL bool __egs_find_pegsfile(const vector<string> &paths,
86  const string &pegs_file, string &abs_pegs_file) {
87  string pfile = pegs_file;
88  if (pfile.find(".pegs4dat") == string::npos) {
89  pfile += ".pegs4dat";
90  }
91  for (unsigned int j=0; j<paths.size(); j++) {
92  string this_pegs =!paths[j].empty() ? egsJoinPath(paths[j],pfile) : pfile;
93  if (!EGS_ACCESS(this_pegs.c_str(),R_OK)) {
94  abs_pegs_file = this_pegs;
95  return true;
96  }
97  }
98  return false;
99 }
100 
101 static EGS_LOCAL EGS_Application *active_egs_application = 0;
102 
103 int EGS_Application::n_apps = 0;
104 
105 unique_ptr<EGS_InputStruct> EGS_Application::inputStructure = unique_ptr<EGS_InputStruct>();
106 
108  return active_egs_application;
109 }
110 
112  active_egs_application = a;
113 };
114 
115 int EGS_Application::userScoring(int iarg, int ir) {
116  if (a_objects) {
117  int early_return = 0;
118  for (int j=0; j<a_objects[iarg].size(); ++j) {
119  int res;
120  if (ir > -1) {
121  res = a_objects[iarg][j]->processEvent((AusgabCall)iarg, ir);
122  }
123  else {
124  res = a_objects[iarg][j]->processEvent((AusgabCall)iarg);
125  }
126  if (res < 0) {
127  return res;
128  }
129  if (res > 0) {
130  early_return = res;
131  }
132  }
133  if (early_return > 0) {
134  return early_return;
135  }
136  }
137  if (ir > -1) {
138  return 0;
139  }
140  else {
141  return ausgab(iarg);
142  }
143 }
144 
145 void EGS_Application::checkEnvironmentVar(int &argc, char **argv,
146  const char *n1, const char *n2, const char *env, string &var) {
147  char *aux = getenv(env);
148  if (aux) {
149  var = aux;
150  }
151  else {
152  var = "";
153  }
154  getArgument(argc,argv,n1,n2,var);
155  if (!var.size()) egsFatal("%s\n the environment variable %s is not set"
156  " and it was not passed as argument\n",__egs_app_msg1,env);
157  int n = var.size()-1;
158  if (var[n] != '/' && var[n] != fs) {
159  var += fs;
160  }
161 }
162 
163 class EGS_LOCAL EGS_GeometryHistory {
164 public:
165  struct Step {
166  EGS_Vector x, u;
167  EGS_Float twant, t;
168  int ireg, inew;
169  Step() {};
170  Step(int Ireg, int Inew, const EGS_Vector &X, const EGS_Vector &U,
171  EGS_Float Twant, EGS_Float T) : x(X), u(U), twant(Twant), t(T),
172  ireg(Ireg), inew(Inew) {};
173  void show() const {
174  egsWarning("old region=%d, position=(%g,%g,%g), "
175  "direction=(%g,%g,%g) intended step=%g, new region=%d, "
176  "step=%g\n",ireg,x.x,x.y,x.z,u.x,u.y,u.z,twant,inew,t);
177  };
178  };
179 
180  EGS_GeometryHistory(int N=2) : steps(new Step [N]), nsize(N), ns(0),
181  wrap(false) {};
183  delete [] steps;
184  };
185  void addStep(int ireg, int inew, const EGS_Vector &x,
186  const EGS_Vector &u, EGS_Float twant, EGS_Float t) {
187  steps[ns++] = Step(ireg,inew,x,u,twant,t);
188  if (ns >= nsize) {
189  ns = 0;
190  wrap = true;
191  }
192  };
193  void reportHistory() const {
194  int nhave = wrap ? nsize : ns;
195  egsWarning("\n************** Last %d geometry steps:\n",nhave);
196  if (wrap) {
197  for (int j=ns; j<nsize; j++) {
198  steps[j].show();
199  }
200  }
201  for (int j=0; j<ns; j++) {
202  steps[j].show();
203  }
204  };
205 
206  Step *steps;
207  int nsize;
208  int ns;
209  bool wrap;
210 };
211 
212 void EGS_Application::reportGeometryError() {
213  ghistory->reportHistory();
214 
215  // check if we are over the tolerated limit for geometry errors
216  run->geomErrorCount++;
217  if (run->geomErrorCount > run->geomErrorMax) {
218  egsFatal("\n\n******** Encountered %d geometry errors (maximum allowed is %d). \n \
219  You can change this limit with the 'geometry error limit' run control input key. \n \
220  Quitting now.\n", run->geomErrorCount, run->geomErrorMax);
221  }
222 }
223 
224 void EGS_Application::storeGeometryStep(int ireg, int inew,
225  const EGS_Vector &x, const EGS_Vector &u, EGS_Float twant, EGS_Float t) {
226  ghistory->addStep(ireg,inew,x,u,twant,t);
227 }
228 
229 EGS_Application::EGS_Application(int argc, char **argv) : input(0), geometry(0),
230  source(0), rndm(0), run(0), simple_run(false), uniform_run(false), current_case(0),
231  last_case(0), data_out(0), data_in(0), a_objects(0),
232  ghistory(new EGS_GeometryHistory) {
233 
234  app_index = n_apps++;
235 
236  if (!active_egs_application) {
237  active_egs_application = this;
238  }
239  {
240  for (int call=BeforeTransport; call<AfterTransport; call++) {
241  ausgab_flag[call] = true;
242  }
243  }
244  {
245  for (int call=AfterTransport; call<UnknownCall; call++) {
246  ausgab_flag[call] = false;
247  }
248  }
249 
250  //
251  // *** get the name of this application
252  //
253  if (!getArgument(argc,argv,"-a","--application",app_name)) {
254  app_name = egsStripPath(argv[0]);
255 
256  // In Windows PowerShell, we need to remove a .exe extension
257  size_t exePos = app_name.rfind(".exe");
258  if (exePos != string::npos) {
259  app_name = app_name.substr(0, exePos);
260  }
261  }
262  if (!app_name.size()) egsFatal("%s\n failed to determine application "
263  "name from %s or command line arguments\n",__egs_app_msg1,argv[0]);
264  //
265  // *** make sure EGS_HOME is set.
266  //
267  checkEnvironmentVar(argc,argv,"-e","--egs-home","EGS_HOME",egs_home);
269  //
270  // *** make sure HEN_HOUSE is set.
271  //
272  checkEnvironmentVar(argc,argv,"-H","--hen-house","HEN_HOUSE",hen_house);
273  //
274  // *** check if there is an input file specified on the command line
275  //
276  getArgument(argc,argv,"-i","--input",input_file);
277  //egsFatal("%s\n no input file specified\n",__egs_app_msg1);
278  //
279  // *** create the name of the working directory
280  //
281  char buf[512];
282  sprintf(buf,"egsrun_%d_",egsGetPid());
283  run_dir = buf;
284  if (input_file.size() > 0) {
285 
286  // Remove the .egsinp extension if it was included
287  size_t ext = input_file.rfind(".egsinp");
288  if (ext != std::string::npos) {
289  input_file = input_file.substr(0,ext);
290  }
291 
292  run_dir += input_file;
293  run_dir += '_';
294  }
295  else {
296  run_dir += "_noinput_";
297  }
298  run_dir += egsHostName();
299 
300  //
301  // *** check if there is a PEGS file specified on the command line
302  //
303  is_pegsless= false;
304  if (!getArgument(argc,argv,"-p","--pegs-file",pegs_file)) {
305  is_pegsless= true;
306  }
307  //gsFatal("%s\n no PEGS file specified\n",__egs_app_msg1);
308 
309  //
310  // *** check if the pegs file exists.
311  //
312  if (pegs_file.size() > 0) {
313  string pdirs = egsJoinPath("pegs4","data");
314  vector<string> pegs_paths;
315  pegs_paths.push_back("");
316  pegs_paths.push_back(egsJoinPath(egs_home,pdirs));
317  pegs_paths.push_back(egsJoinPath(hen_house,pdirs));
318  if (!__egs_find_pegsfile(pegs_paths,pegs_file,abs_pegs_file))
319  egsFatal("%s\n the pegs file %s does not exist or is not "
320  "readable\n",__egs_app_msg1,pegs_file.c_str());
321  }
322 
323  //
324  // *** check if the input file exists.
325  //
326  string ifile;
327  if (input_file.size() > 0) {
328  ifile = egsJoinPath(app_dir,input_file);
329  if (ifile.find(".egsinp") == string::npos) {
330  ifile += ".egsinp";
331  }
332  if (EGS_ACCESS(ifile.c_str(),R_OK))
333  egsFatal("%s\n the input file %s does not exist or is not "
334  "readable\n",__egs_app_msg1,ifile.c_str());
335  }
336 
337  //
338  // *** set the output file
339  //
340  if (!getArgument(argc,argv,"-o","--output",output_file)) {
342  }
343  if (!output_file.size()) {
344  output_file = "test";
345  }
346  //
347  // *** see if a batch run.
348  //
349  batch_run = false;
350  for (int j=1; j<argc; j++) {
351  string tmp = argv[j];
352  if (tmp == "-b" || tmp == "--batch") {
353  batch_run = true;
354  //for(int i=j; i<argc-1; i++) argv[i] = argv[i+1];
355  //argc--;
356  break;
357  }
358  }
359  //
360  // *** see if parallel run.
361  //
362  string npar, ipar, ifirst;
363  n_parallel = i_parallel = 0;
364  first_parallel = 1;
365  bool have_np = getArgument(argc,argv,"-P","--parallel",npar);
366  bool have_ip = getArgument(argc,argv,"-j","--job",ipar);
367  bool have_first = getArgument(argc,argv,"-f","--first-job",ifirst);
368  if (have_np && have_ip) {
369  n_parallel = ::strtol(npar.c_str(),0,10);
370  i_parallel = ::strtol(ipar.c_str(),0,10);
371  if (have_first) {
372  first_parallel = ::strtol(ifirst.c_str(),0,10);
373  if (first_parallel < 0) {
374  egsWarning("%s\n invalid -f argument %d\n",__egs_app_msg1,
375  n_parallel);
376  n_parallel = 0;
377  i_parallel = 0;
378  }
379  }
380  if (n_parallel < 0) {
381  egsWarning("%s\n invalid -P argument %d\n",__egs_app_msg1,
382  n_parallel);
383  n_parallel = 0;
384  }
385  if (i_parallel < 0) {
386  egsWarning("%s\n invalid -j argument %d\n",__egs_app_msg1,
387  i_parallel);
388  i_parallel = 0;
389  n_parallel = 0;
390  }
391  if (i_parallel > n_parallel + first_parallel -1) {
392  egsWarning("%s\n job number (%d) can not be larger than number"
393  " of parallel jobs(%d). Turning off parallel option\n",
394  __egs_app_msg1,i_parallel,n_parallel+ first_parallel -1);
395  n_parallel = 0;
396  i_parallel = 0;
397  }
398  }
399  else if (have_np && !have_ip) { // user wants to reset n_parallel
400  // and combine parallel jobs
401  n_parallel = ::strtol(npar.c_str(),0,10);
402  simple_run = true;
403  }
404  else if (n_parallel && !have_ip) { // user wants to combine
405  // parallel jobs
406  simple_run = true;
407  }
408  else if (!have_np && have_ip) {
409  egsWarning("\n%s\n to specify a parallel run you need both,"
410  " the -P and -j command line options\n\n",__egs_app_msg1);
411  }
412 
413  //
414  // *** see if user wants simple job control
415  //
416  for (int j=1; j<argc; j++) {
417  string tmp = argv[j];
418  if (tmp == "-s" || tmp == "--simple-run") {
419  simple_run = true;
420  //for(int i=j; i<argc-1; i++) argv[i] = argv[i+1];
421  //argc--;
422  break;
423  }
424  }
425 
426  //
427  // *** See if user wants uniform job control.
428  // (Takes precedence over simple job control)
429  //
430  for (int j=1; j<argc; j++) {
431  string tmp = argv[j];
432  if (tmp == "-u" || tmp == "--urc") {
433  uniform_run = true;
434  simple_run = false;
435  break;
436  }
437  }
438 
440  if (i_parallel > 0 && n_parallel > 0) {
441  batch_run = true;
442  char buf[1024];
443  sprintf(buf,"%s_w%d",output_file.c_str(),i_parallel);
444  output_file = buf;
445  }
446 
447  //
448  // *** read the input
449  //
450  input = new EGS_Input;
451  if (ifile.size() > 0) {
452  if (input->setContentFromFile(ifile.c_str()))
453  egsFatal("%s\n error while reading input file %s\n",
454  __egs_app_msg1,ifile.c_str());
455  }
456 
457 }
458 
459 bool EGS_Application::getArgument(int &argc, char **argv,
460  const char *name1, const char *name2, string &arg) {
461  string n1(name1), n2(name2);
462  for (int j=1; j<argc-1; j++) {
463  if (n1 == argv[j] || n2 == argv[j]) {
464  arg = argv[j+1];
465  //for(int i=j; i<argc-2; i++) argv[i] = argv[i+2];
466  //argc -= 2;
467  return true;
468  }
469  }
470  return false;
471 }
472 
473 string EGS_Application::constructIOFileName(const char *extension,
474  bool with_run_dir) const {
475  string iofile = with_run_dir ? egsJoinPath(app_dir,run_dir) : app_dir;
476  iofile = egsJoinPath(iofile,output_file);
477  if (extension) {
478  iofile += extension;
479  }
480  return iofile;
481 }
482 
484 
485  if (data_out) {
486  delete data_out;
487  }
488  string ofile = constructIOFileName(".egsdat",true);
489  /*
490  string ofile = egsJoinPath(app_dir,run_dir);
491  ofile = egsJoinPath(ofile,output_file);
492  ofile += ".egsdat";
493  */
494  data_out = new ofstream(ofile.c_str());
495  if (!(*data_out)) {
496  egsWarning("EGS_Application::outputData: failed to open %s "
497  "for writing\n",ofile.c_str());
498  return 1;
499  }
500  if (!run->storeState(*data_out)) {
501  return 2;
502  }
504  return 3;
505  }
506  (*data_out) << endl;
507  if (!rndm->storeState(*data_out)) {
508  return 4;
509  }
510  if (!source->storeState(*data_out)) {
511  return 5;
512  }
513  for (int j=0; j<a_objects_list.size(); ++j) {
514  if (!a_objects_list[j]->storeState(*data_out)) {
515  return 6;
516  }
517  }
518  return 0;
519 }
520 
522  if (data_in) {
523  delete data_in;
524  }
525  string ifile = constructIOFileName(".egsdat",false);
526  /*
527  string ifile = egsJoinPath(app_dir,output_file);
528  ifile += ".egsdat";
529  */
530  data_in = new ifstream(ifile.c_str());
531  if (!(*data_in)) {
532  egsWarning("EGS_Application::readData: failed to open %s "
533  "for reading\n",ifile.c_str());
534  return 1;
535  }
536  if (!run->setState(*data_in)) {
537  return 2;
538  }
539  if (!egsGetI64(*data_in,current_case)) {
540  return 3;
541  }
543  if (!rndm->setState(*data_in)) {
544  return 4;
545  }
546  if (!source->setState(*data_in)) {
547  return 5;
548  }
549  for (int j=0; j<a_objects_list.size(); ++j) {
550  if (!a_objects_list[j]->setState(*data_in)) {
551  return 6;
552  }
553  }
554  return 0;
555 }
556 
558  last_case = 0;
559  current_case = 0;
560  run->resetCounter();
561  rndm->resetCounter();
562  source->resetCounter();
563  for (int j=0; j<a_objects_list.size(); ++j) {
564  a_objects_list[j]->resetCounter();
565  }
566 
567 }
568 
569 int EGS_Application::addState(istream &data) {
570  if (!run->addState(data)) {
571  return 1;
572  }
573  EGS_I64 tmp_case;
574  if (!egsGetI64(data,tmp_case)) {
575  return 2;
576  }
577  current_case += tmp_case;
579  if (!rndm->addState(data)) {
580  return 3;
581  }
582  if (!source->addState(data)) {
583  return 4;
584  }
585  for (int j=0; j<a_objects_list.size(); ++j)
586  if (!a_objects_list[j]->addState(data)) {
587  return 5;
588  }
589  return 0;
590 }
591 
592 bool fileExists(const string &name) {
593  struct stat buffer;
594  return (stat(name.c_str(), &buffer) == 0);
595 }
596 
598 
599  char buf[512];
600  int n_of_egsdat = 0;
601 
602  for (int i = first_parallel; i < first_parallel + n_parallel; i++) {
603  sprintf(buf,"%s_w%d.egsdat",final_output_file.c_str(),i);
604  string dfile = egsJoinPath(app_dir,buf);
605  if (fileExists(dfile)) {
606  n_of_egsdat++;
607  }
608  }
609 
610  return n_of_egsdat;
611 }
612 
614  int err = combineResults();
615  if (err) {
616  return err;
617  }
618  for (int j=0; j<a_objects_list.size(); ++j) {
619  a_objects_list[j]->reportResults();
620  }
621  outputResults();
622  return 0;
623 }
624 
627  "\n Suming the following .egsdat files:\n"
628  "=======================================================================\n");
629  char buf[512];
630  resetCounter();
631  EGS_Float last_cpu = 0;
632  EGS_I64 last_ncase = 0;
633  int ndat = 0;
634  bool ok = true;
635  /*
636  If trying to combine results and n_parallel set to 0,
637  use a hard-coded value for number of jobs.This is possible
638  if -P njobs was not passed as argument.
639  */
640  if (!n_parallel) {
641  n_parallel = MAXIMUM_JOB_NUMBER;
642  }
643  for (int j=first_parallel; j < first_parallel + n_parallel; j++) {
644  sprintf(buf,"%s_w%d.egsdat",final_output_file.c_str(),j);
645  string dfile = egsJoinPath(app_dir,buf);
646  ifstream data(dfile.c_str());
647  if (data) {
648  int err = addState(data);
649  ++ndat;
650  if (!err) {
651  EGS_I64 ncase = run->getNdone();
652  EGS_Float cpu = run->getCPUTime();
653  egsInformation("%2d %-30s ncase=%-14lld cpu=%-11.2f\n",
654  ndat,buf,ncase-last_ncase,cpu-last_cpu);
655  last_ncase = ncase;
656  last_cpu = cpu;
657  }
658  else {
659  ok = false;
660  egsWarning("%2d %-30s error %d\n",ndat,buf,err);
661  }
662  }
663  }
664  if (ndat > 0) {
666  "=======================================================================\n");
667  egsInformation("%40s%-14lld cpu=%-11.2f\n\n","Total ncase=",last_ncase,
668  last_cpu);
669  }
670  if (ndat > 0) {
671  return ok ? 0 : -1;
672  }
673  else {
674  return 1;
675  }
676 }
677 
679  if (!rndm) {
680  return 0;
681  }
682  return rndm->numbersUsed();
683 }
684 
686  if (!input) {
687  return -1;
688  }
689  //if( geometry ) { delete geometry; geometry = 0; }
692  if (!geometry) {
693  return 1;
694  }
695  geometry->ref();
696  geometry->setApplication(this);
697  return 0;
698 }
699 
701  if (!input) {
702  return -1;
703  }
704  //if( source ) { delete source; source = 0; }
706  if (!source) {
707  return 1;
708  }
709  source->ref();
710  return 0;
711 }
712 
714  if (run) {
715  delete run;
716  }
717  if (simple_run) {
718  run = new EGS_RunControl(this);
719  }
720  else if (uniform_run) {
721  run = new EGS_UniformRunControl(this);
722  }
723  else {
724  run = EGS_RunControl::getRunControlObject(this);
725  }
726  if (!run) {
727  return 1;
728  }
729  return 0;
730 }
731 
733  if (rndm) {
734  delete rndm;
735  }
736  int sequence = 0;
737  if (n_parallel > 0 && i_parallel > 0) {
738  sequence = i_parallel - 1;
739  }
740  if (input) {
742  }
743  if (!rndm) {
744  egsWarning("EGS_Application::initRNG(): using default RNG\n");
746  }
747  if (!rndm) {
748  egsWarning("EGS_Application::initRNG(): got null RNG?\n");
749  return 1;
750  }
751  return 0;
752 }
753 
755  //if( !input ) { egsWarning("%s no input\n",__egs_app_msg2); return -1; }
756  egsInformation("In EGS_Application::initSimulation()\n");
757  int err;
758  bool ok = true;
759  err = initGeometry();
760  if (err) {
761  egsWarning("\n\n%s geometry initialization failed\n",__egs_app_msg2);
762  ok = false;
763  }
764  err = initSource();
765  if (err) {
766  egsWarning("\n\n%s source initialization failed\n",__egs_app_msg2);
767  ok = false;
768  }
769  err = initRNG();
770  if (err) {
771  egsWarning("\n\n%s RNG initialization failed\n",__egs_app_msg2);
772  ok = false;
773  }
774  err = initRunControl();
775  if (err) {
776  egsWarning("\n\n%s run control initialization failed\n",__egs_app_msg2);
777  ok = false;
778  }
779  if (!ok) {
780  return 1;
781  }
782  err = initEGSnrcBackEnd();
783  if (err) {
784  egsWarning("\n\n%s back-end initialization failed\n",__egs_app_msg2);
785  return 2;
786  }
788  err = initCrossSections();
789  if (err) {
790  egsWarning("\n\n%s cross section initialization failed\n",__egs_app_msg2);
791  return 3;
792  }
793  err = initScoring();
794  if (err) {
795  egsWarning("\n\n%s scoring initialization failed with status %d\n",
796  __egs_app_msg2,err);
797  return 4;
798  }
800  //describeSimulation();
801 
802  return 0;
803 }
804 
805 void EGS_Application::setSimulationChunk(EGS_I64 nstart, EGS_I64 nrun, int npar, int nchunk) {
806  if (source) {
807  source->setSimulationChunk(nstart,nrun,npar,nchunk);
808  }
809 }
810 
812  if (!geometry && !source) {
813  return;
814  }
815  egsInformation("\n\n");
816  if (geometry) {
817  geometry->printInfo();
818  }
819  if (source) egsInformation("\n\nThe simulation uses the following source:"
820  "\n========================================="
821  "\n %s\n\n\n",source->getSourceDescription());
822  if (rndm) {
823  rndm->describeRNG();
824  egsInformation("\n\n");
825  }
826  if (run) {
827  run->describeRCO();
828  egsInformation("\n\n");
829  }
830  if (a_objects_list.size() > 0) {
831  egsInformation("The following ausgab objects are included in the simulation\n");
832  egsInformation("===========================================================\n\n");
833  for (int j=0; j<a_objects_list.size(); ++j) {
834  egsInformation("%s",a_objects_list[j]->getObjectDescription());
835  }
836  egsInformation("\n\n");
837  }
838 }
839 
841  bool ok = true;
842  if (!geometry) {
843  egsWarning("%s no geometry\n",__egs_app_msg3);
844  ok = false;
845  }
846  if (!source) {
847  egsWarning("%s no source\n",__egs_app_msg3);
848  ok = false;
849  }
850  if (!rndm) {
851  egsWarning("%s no RNG\n",__egs_app_msg3);
852  ok = false;
853  }
854  if (!run) {
855  egsWarning("%s no run control object\n",__egs_app_msg3);
856  ok = false;
857  }
858  if (!ok) {
859  return 1;
860  }
861 
862  int start_status = run->startSimulation();
863  if (start_status) {
864  if (start_status < 0) {
865  egsWarning("\n%s failed to start the simulation\n\n",__egs_app_msg3);
866  }
867  return start_status;
868  }
869 
870  EGS_I64 ncase;
871  bool next_chunk = true;
872 
873  while (next_chunk && (ncase = run->getNextChunk()) > 0) {
874 
875  egsInformation("\nRunning %lld histories\n",ncase);
876  double f,df;
877  if (run->getCombinedResult(f,df)) {
878  char c = '%';
879  egsInformation(" combined result from this and other parallel"
880  " runs: %lg +/- %7.3lf%c\n\n",f,df,c);
881  }
882  else {
883  egsInformation("\n");
884  }
885  int nbatch = run->getNbatch();
886  EGS_I64 ncase_per_batch = ncase/nbatch;
887  if (!ncase_per_batch) {
888  ncase_per_batch = 1;
889  nbatch = ncase;
890  }
891  for (int ibatch=0; ibatch<nbatch; ibatch++) {
892  if (!run->startBatch(ibatch,ncase_per_batch)) {
893  egsInformation(" startBatch() loop termination\n");
894  next_chunk = false;
895  break;
896  }
897  for (EGS_I64 icase=0; icase<ncase_per_batch; icase++) {
898  if (simulateSingleShower()) {
899  egsInformation(" simulateSingleShower() "
900  "loop termination\n");
901  next_chunk = false;
902  break;
903  }
904  }
905  if (!next_chunk) {
906  break;
907  }
908  if (!run->finishBatch()) {
909  egsInformation(" finishBatch() loop termination\n");
910  next_chunk = false;
911  break;
912  }
913  }
914  }
915  // call this from within finishSimulation()
916  //run->finishSimulation();
917  return 0;
918 }
919 
921  int ireg;
922  int ntry = 0;
924  do {
925  ntry++;
926  if (ntry > 100000) {
927  egsWarning("EGS_Application::simulateSingleShower(): no particle"
928  " from the source has entered the geometry after 100000"
929  " attempts\n");
930  return 1;
931  }
932  setTimeIndex(-1);
933  current_case =
935 
936  // For dynamic geometries, update positions according to the current
937  // time index, which may have been set by getNextParticle
938  geometry->getNextGeom(rndm);
939 
940  ireg = geometry->isWhere(p.x);
941  if (ireg < 0) {
942  EGS_Float t = veryFar;
943  ireg = geometry->howfar(ireg,p.x,p.u,t);
944  if (ireg >= 0) {
945  p.x += p.u*t;
946  }
947  }
948  }
949  while (ireg < 0);
950  p.ir = ireg;
951  int err = startNewShower();
952  if (err) {
953  return err;
954  }
955  err = shower();
956  if (err) {
957  return err;
958  }
959  return finishShower();
960 }
961 
963  if (current_case != last_case) {
964  for (int j=0; j<a_objects_list.size(); ++j) {
965  a_objects_list[j]->setCurrentCase(current_case);
966  }
967  }
968  return 0;
969 }
970 
972  if (rndm) {
973  delete rndm;
974  }
975  if (run) {
976  delete run;
977  }
978  if (input) {
979  delete input;
980  }
982  if (geometry) {
983  if (!geometry->deref()) {
984  EGS_Application *app = active_egs_application;
985  active_egs_application = this;
987  delete geometry;
988  active_egs_application = app;
989  }
990  }
991  /*
992  if( a_objects ) {
993  for(int j=(int)BeforeTransport; j<=(int)AugerEvent; ++j) {
994  while( a_objects[j].size() ) EGS_Object::deleteObject(a_objects[j].pop());
995  }
996  delete [] a_objects;
997  }
998  */
999  if (a_objects) {
1000  delete [] a_objects;
1001  }
1002  if (ghistory) {
1003  delete ghistory;
1004  }
1005  if (active_egs_application == this) {
1006  active_egs_application = 0;
1007  }
1008 }
1009 
1011  if (!o) {
1012  return;
1013  }
1014  // only one track scoring object is allowed, otherwise there can be bugs
1015  // if both objects try and write to the same file.
1016  if (o->getObjectType() == "EGS_TrackScoring") {
1017  for (int j=0; j<a_objects_list.size(); ++j) {
1018  if (a_objects_list[j]->getObjectType() == "EGS_TrackScoring") {
1019  egsFatal("error: only one ausgab object of type "
1020  "'EGS_TrackScoring' is allowed\n");
1021  }
1022  }
1023  }
1024  o->setApplication(this);
1025  a_objects_list.add(o);
1026  //int ncall = 1 + (int)AugerEvent;
1027  int ncall = (int)UnknownCall;
1028  if (!a_objects) {
1030  }
1031  for (int call=(int)BeforeTransport; call<ncall; ++call) {
1032  if (o->needsCall((AusgabCall)call)) {
1033  a_objects[call].add(o);
1034  setAusgabCall((AusgabCall)call,true);
1035  }
1036  }
1037 }
1038 
1040  if (!input) {
1041  return;
1042  }
1044  for (int i=0; i<EGS_AusgabObject::nObjects(); ++i) {
1046  }
1047 }
1048 
1050  //I don't think we need a separate analyzeResults function.
1051  //analyzeResults();
1052  int err = 0;
1053  if (run) {
1054  err = run->finishSimulation();
1055  if (err < 0) {
1056  return err;
1057  }
1058  }
1059 
1060  outputResults();
1061  for (int j=0; j<a_objects_list.size(); ++j) {
1062  a_objects_list[j]->reportResults();
1063  }
1064 
1065  if (data_out) {
1066  delete data_out;
1067  data_out = 0;
1068  /*
1069  #ifdef WIN32
1070  string dfile = egsJoinPath(app_dir,run_dir);
1071  dfile = egsJoinPath(dfile,output_file);
1072  dfile += ".egsdat";
1073  string command = "move /Y ";
1074  command += dfile; command += " "; command += app_dir;
1075  egsInformation("About to execute <%s>\n",command.c_str());
1076  int istat = system(command.c_str());
1077  if( istat ) egsWarning("Failed to move the .egsdat file from the"
1078  " working directory\n");
1079  #endif
1080  */
1081  }
1082  finishRun();
1083  run_dir = ""; // i.e. from now on all output will go to the user code
1084  // directory.
1085  return err;
1086 }
1087 
1088 void EGS_Application::fillRandomArray(int n, EGS_Float *rarray) {
1089  rndm->fillArray(n,rarray);
1090 }
1091 
1093 #ifndef WIN32
1094  // quit if space left on disk is less than 1 MB to mitigate disk full problems
1095 
1096  // stat the stream
1097  struct stat tmp;
1098  fstat(fileno(stream), &tmp);
1099 
1100  // check only if the stream is a regular file
1101  if (S_ISREG(tmp.st_mode)) {
1102  struct statvfs fstats;
1103  fstatvfs(fileno(stdout), &fstats);
1104  if (fstats.f_bavail*fstats.f_bsize < 1048576) {
1105  egsFatal("\n\n******** Space left on file system is below 1 MB. Quitting now.\n");
1106  exit(1);
1107  }
1108  }
1109 #endif
1110 }
1111 
1112 void EGS_Application::appInformation(const char *msg) {
1113  if (msg) {
1114  fprintf(stdout,"%s",msg);
1115  fflush(stdout);
1116  checkDeviceFull(stdout);
1117  }
1118 }
1119 
1120 void EGS_Application::appWarning(const char *msg) {
1121  if (msg) {
1122  fprintf(stderr,"%s",msg);
1123  fflush(stderr);
1124  checkDeviceFull(stderr);
1125  }
1126 }
1127 
1128 void EGS_Application::appFatal(const char *msg) {
1129  if (msg) {
1130  fprintf(stderr,"%s",msg);
1131  fflush(stderr);
1132  }
1133  exit(1);
1134 }
Base class for advanced EGSnrc C++ applications.
static bool getArgument(int &argc, char **argv, const char *name1, const char *name2, string &arg)
Finds a command line argument.
string app_dir
The user code directory.
virtual EGS_I64 randomNumbersUsed() const
Returns the number of random numbers used.
static EGS_Application * activeApplication()
Get the active application.
bool uniform_run
Use a uniform run control object for parallel runs.
string run_dir
The working directory during the run.
bool simple_run
Use a simple run control object for parallel runs.
EGS_RandomGenerator * rndm
the random number generator
bool is_pegsless
set to true if a pegsless run
int n_parallel
Number of parallel jobs.
virtual void resetCounter()
Reset the application to a 'pristine' state.
virtual int startNewShower()
Called just before the shower() function.
EGS_Application(int argc, char **argv)
Construct an EGSnrc application.
EGS_SimpleContainer< EGS_AusgabObject * > a_objects_list
The ausgab objects.
string input_file
The input file name.
string output_file
The output file name (no extension)
virtual void setAusgabCall(AusgabCall call, bool on_or_off)
Turns on or off a call to the user scoring function ausgab.
virtual void describeSimulation()
Describe the simulation.
EGS_I64 last_case
The last case simulated.
virtual int addState(istream &data)
Add data from a parallel job.
virtual int finishSimulation()
Analyze and output the results.
static void setActiveApplication(EGS_Application *)
Set the active EGS_Application class.
virtual int initRunControl()
Construct the run control object.
virtual void appFatal(const char *)
Write a warning message and exit.
string pegs_file
The pegs file name.
virtual int outputData()
Output intermediate results.
virtual int initScoring()
Initialize the scoring of quantities of interest.
virtual int initSimulation()
Initializes the EGSnrc application.
EGS_Input * input
the input to this simulation.
string app_name
The application name.
virtual void outputResults()
Output the simulation results.
virtual ~EGS_Application()
Destruct the EGSnrc application.
void initAusgabObjects()
Initialize ausgab objects.
string final_output_file
The final output file name.
void addAusgabObject(EGS_AusgabObject *o)
Adds an ausgab object to the list of ausgab objects.
EGS_BaseGeometry * geometry
the geometry of this simulation
AusgabCall
Possible calls to the user scoring function ausgab().
@ BeforeTransport
before the step
@ UnknownCall
last element in the enumeration
@ AfterTransport
after the step
bool ausgab_flag[UnknownCall]
on/off flags for ausgab calls
EGS_I64 current_case
The current case as returned from the source.
virtual int initGeometry()
Initialize the simulation geometry.
virtual int initRNG()
Initialize the random number generator.
bool batch_run
Interactive or batch run.
int i_parallel
Job index in parallel runs.
istream * data_in
data input stream
string egs_home
The EGS_HOME directory.
int first_parallel
first parallel job number
int app_index
the index of this application.
virtual int initCrossSections()
Initialize the EGSnrc cross sections and cross section/transport options.
int howManyJobsDone()
Counts how many *.egsdat files in app folder.
virtual void appInformation(const char *)
Write an information message.
virtual void setSimulationChunk(EGS_I64 nstart, EGS_I64 nrun, int npar, int nchunk)
Set the simulation chunk.
virtual void describeUserCode() const
Describe the user code.
string abs_pegs_file
The pegs file name including absolute path.
virtual int finishShower()
Called just after the shower() function.
int userScoring(int iarg, int ir=-1)
User scoring function for accumulation of results and VRT implementation.
virtual int simulateSingleShower()
Simulates a single particle shower.
ostream * data_out
data output stream
virtual void appWarning(const char *)
Write a warning message.
virtual int initSource()
Initialize the particle source.
EGS_RunControl * run
the run control object.
EGS_SimpleContainer< EGS_AusgabObject * > * a_objects
The ausgab objects for the various ausgab calls.
virtual int combineResults()
Combine results from parallel runs.
static void checkEnvironmentVar(int &argc, char **argv, const char *env, const char *n1, const char *n2, string &var)
Finds a command line argument.
string constructIOFileName(const char *extension, bool with_run_dir) const
Constructs and returns the name of an input/output file.
virtual void fillRandomArray(int n, EGS_Float *rns)
Fill an array with random numbers using the application's RNG.
string hen_house
The HEN_HOUSE directory.
virtual int runSimulation()
Runs an EGSnrc simulation.
virtual int initEGSnrcBackEnd()
Initialize the EGSnrc backend.
void checkDeviceFull(FILE *)
Check if a device holding a given stream is full.
void setTimeIndex(EGS_Float temp_time)
EGS_BaseSource * source
the particle source
virtual int combinePartialResults()
Combine intermediate results from parallel runs.
virtual int shower()
Simulate a single shower.
virtual int readData()
Read intermediate results.
virtual void setApplication(EGS_Application *App)
Set the application this object belongs to.
static EGS_AusgabObject * getObject(size_t j)
Returns the j'th ausgab object in the internal list.
static void createAusgabObjects(EGS_Input *)
Create ausgab objects from the information pointed to by input.
static int nObjects()
Returns the number of ausgab objects in the internal list.
virtual bool needsCall(EGS_Application::AusgabCall iarg) const
Is the ausgab call iarg relevant for this object?
int deref()
Decrease the reference count to this geometry.
virtual int howfar(int ireg, const EGS_Vector &x, const EGS_Vector &u, EGS_Float &t, int *newmed=0, EGS_Vector *normal=0)=0
Calculate the distance to a boundary from x along the direction u.
static void setActiveGeometryList(int list)
Set the currently active geometry list.
static EGS_BaseGeometry * createGeometry(EGS_Input *)
Create a geometry (or geometries) from a given input.
virtual void printInfo() const
Print information about this geometry.
int ref()
Increase the reference count to this geometry.
virtual int isWhere(const EGS_Vector &x)=0
In which region is poisition x?
virtual bool addState(istream &data_in)
Add data from the stream data_in to the source state.
const char * getSourceDescription() const
Get a short description of this source.
virtual void resetCounter()
Reset the source state.
virtual EGS_I64 getNextParticle(EGS_RandomGenerator *rndm, int &q, int &latch, EGS_Float &E, EGS_Float &wt, EGS_Vector &x, EGS_Vector &u)=0
Sample the next source particle from the source probability distribution.
static EGS_BaseSource * createSource(EGS_Input *)
Create sources from the information pointed to by input.
virtual bool setState(istream &data_in)
Set the source state based on data from the stream data_in.
virtual void setSimulationChunk(EGS_I64 nstart, EGS_I64 nrun, int npar, int nchunk)
Set the next simulation chunk to start at nstart and to consist of nrun particles.
virtual bool storeState(ostream &data_out) const
Store the source state into the stream data_out.
A class for storing information in a tree-like structure of key-value pairs. This class is used throu...
Definition: egs_input.h:182
int setContentFromFile(const char *fname)
Set the property from the input file fname (which is considered to be an absolute file name)
Definition: egs_input.cpp:203
int ref()
Increase the reference count to this object.
static void deleteObject(EGS_Object *o)
Delete an object.
const string & getObjectType() const
Get the object type.
virtual void fillArray(int n, EGS_Float *array)=0
Fill the array of n elements pointed to by array with random numbers.
static EGS_RandomGenerator * defaultRNG(int sequence=0)
Returns a pointer to the default egspp RNG.
Definition: egs_rndm.cpp:465
static EGS_RandomGenerator * createRNG(EGS_Input *inp, int sequence=0)
Create a RNG object from the information pointed to by inp and return a pointer to it.
Definition: egs_rndm.cpp:409
bool storeState(ostream &data)
Functions for storing, seting and reseting the state of a RNG object.
Definition: egs_rndm.cpp:83
virtual void describeRNG() const
Describe this RNG.
Definition: egs_rndm.h:279
EGS_I64 numbersUsed() const
Returns the number of random numbers used so far.
Definition: egs_rndm.h:148
A simple run control object for advanced EGSnrc C++ applications.
virtual EGS_I64 getNextChunk()
Returns the number of histories to run in the next simulation chunk.
int getNbatch() const
Returns the number of batches per simulation chunk.
virtual int startSimulation()
Starts the simulation.
virtual bool startBatch(int, EGS_I64)
Start a new batch.
virtual bool finishBatch()
Finish a batch.
virtual int finishSimulation()
Finish the simulation.
A job control object for homogeneous computing environments (HCE).
A class representing 3D vectors.
Definition: egs_vector.h:57
EGS_Float y
y-component
Definition: egs_vector.h:62
EGS_Float z
z-component
Definition: egs_vector.h:63
EGS_Float x
x-component
Definition: egs_vector.h:61
EGS_Application class header file.
EGS_AusgabObject interface class header file.
EGS_BaseGeometry class header file.
EGS_BaseSource class header file.
Global egspp functions header file.
EGS_Input class header file.
#define EGS_EXPORT
Export symbols from the egspp library.
Definition: egs_libconfig.h:90
EGS_RandomGenerator class header file.
EGS_SimpleContainer template class.
bool EGS_EXPORT egsStoreI64(ostream &data, EGS_I64 n)
Writes the 64 bit integer n to the output stream data and returns true on success,...
string egsHostName()
Get the name of the host the program is running on.
int egsGetPid()
Get the process id.
EGS_InfoFunction EGS_EXPORT egsInformation
Always use this function for reporting the progress of a simulation and any other type of information...
EGS_InfoFunction EGS_EXPORT egsFatal
Always use this function for reporting fatal errors.
bool EGS_EXPORT egsGetI64(istream &data, EGS_I64 &n)
Reads a 64 bit integer from the stream data and assigns it to n. Returns true on success,...
string egsJoinPath(const string &first, const string &second)
Join two path variables (or a path and a file name) using the platform specific directory separator a...
EGS_InfoFunction EGS_EXPORT egsWarning
Always use this function for reporting warnings.
const EGS_Float veryFar
A very large float.
string egsStripPath(const string &aname)
Strip the path from a file name and return the result.
EGS_Vector x
position
EGS_Float E
particle energy in MeV
EGS_Vector u
direction
int ir
particle region index
int latch
latch variable (useful as a flag on many occasions)
EGS_Float wt
statistical weight
int q
particle charge