EGSnrc C++ class library  Report PIRS-898 (2021)
Iwan Kawrakow, Ernesto Mainegra-Hing, Frederic Tessier, Reid Townson and Blake Walters
egs_simple_application.cpp
Go to the documentation of this file.
1 /*
2 ###############################################################################
3 #
4 # EGSnrc egs++ simple 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: Reid Townson
27 #
28 ###############################################################################
29 */
30 
31 
40 #include "egs_simple_application.h"
41 #include "egs_input.h"
42 #include "egs_base_source.h"
43 #include "egs_timer.h"
44 #include "egs_rndm.h"
45 
46 #include "egs_interface2.h"
47 
48 #include <cstring>
49 #include <cstdlib>
50 
51 static EGS_SimpleApplication *egsApp = 0;
52 
53 void _null_terminate(char *s, int len) {
54  int j;
55  for (j=len-1; j>=0; j--) {
56  if (!isspace(s[j])) {
57  if (j < len-1) {
58  s[j+1] = 0;
59  }
60  break;
61  }
62  }
63  if (j < 0) {
64  s[0] = 0;
65  }
66 }
67 
68 #ifdef WIN32
69  const char fs = 92;
70 #else
71  const char fs = '/';
72 #endif
73 
74 const char *EGS_SimpleApplication::egsHome() const {
75  return the_egsio->egs_home;
76 }
77 
78 const char *EGS_SimpleApplication::henHouse() const {
79  return the_egsio->hen_house;
80 }
81 
82 const char *EGS_SimpleApplication::pegsFile() const {
83  return the_egsio->pegs_file;
84 }
85 
86 const char *EGS_SimpleApplication::inputFile() const {
87  return the_egsio->input_file;
88 }
89 
90 const char *EGS_SimpleApplication::outputFile() const {
91  return the_egsio->output_file;
92 }
93 
94 const char *EGS_SimpleApplication::userCode() const {
95  return the_egsio->user_code;
96 }
97 
98 const char *EGS_SimpleApplication::workDir() const {
99  return the_egsio->work_dir;
100 }
101 
103  return the_egsio->i_parallel;
104 }
105 
107  return the_egsio->n_parallel;
108 }
109 
111 
112  g = 0;
113  source = 0;
114  rndm = 0;
115  input = 0;
116 
117  //
118  // *** make sure that there is only a single application.
119  //
120  if (egsApp) egsFatal("There can only be a single EGS_SimpleApplication"
121  " in a program\n");
122  egsApp = this;
123  ncase = 0;
124 
125  //
126  // *** set the number of histories to run
127  //
128  for (int i=0; i<argc-1; i++) {
129  if (!strcmp("-n",argv[i]) || !strcmp("--ncase",argv[i])) {
130  ncase = atoi(argv[i+1]);
131  break;
132  }
133  }
134  if (ncase < 1) {
135  ncase = 1000;
136  }
137 
138  //
139  // *** init the EGS system
140  //
141  egsInit(argc,argv);
142 
143  //
144  // *** null terminate directory and file names just in case
145  //
146  _null_terminate(the_egsio->user_code,64);
147  _null_terminate(the_egsio->input_file,256);
148  _null_terminate(the_egsio->output_file,256);
149  _null_terminate(the_egsio->egs_home,128);
150  _null_terminate(the_egsio->hen_house,128);
151  _null_terminate(the_egsio->pegs_file,256);
152  _null_terminate(the_egsio->work_dir,128);
153 
154  //
155  // ********** Get the content of the input file.
156  //
157  string ifile(the_egsio->egs_home);
158  ifile += the_egsio->user_code;
159  ifile += fs;
160  ifile += the_egsio->input_file;
161  ifile += ".egsinp";
162  input = new EGS_Input;
163  input->setContentFromFile(ifile.c_str());
164 
165  //
166  // ********** Construct a simulation geometry from the input
167  //
168  EGS_Input *geom_input = input->takeInputItem("geometry definition");
169  if (!geom_input) {
170  egsFatal("No geometry definition in the input file\n");
171  }
172  g = EGS_BaseGeometry::createGeometry(geom_input);
173  if (!g) {
174  egsFatal("Failed to construct the simulation geometry\n");
175  }
176  delete geom_input;
178  egsInformation("\nThe simulation geometry is of type %s and has the "
179  "name '%s'\n\n",g->getType().c_str(),g->getName().c_str());
180 
181  //
182  // *********** Add the media names present in the geometry
183  //
184  for (int j=0; j<g->nMedia(); j++) {
185  const char *medname = g->getMediumName(j);
186  int len = strlen(medname);
187  int ind = egsAddMedium(medname, len);
188  if (ind != j+1) {
189  egsFatal("Medium index mismatch: %d %d\n",ind,j+1);
190  }
191  }
192 
193  //
194  // ********** Construct a particle source from the input
195  //
196  EGS_Input *source_input = input->takeInputItem("source definition");
197  if (!source_input) {
198  egsFatal("No source definition in the input file\n");
199  }
200  source = EGS_BaseSource::createSource(source_input);
201  if (!source) {
202  egsFatal("Failed to construct the particle source\n");
203  }
204  delete source_input;
205 
206  //
207  // ********* Construct a random number generator from the input
208  //
210  if (!rndm) {
212  }
213 
214  //
215  // ********** Get transport parameter settings from the input file
216  //
217  int ounit = 6;
218  egsGetTransportParameter(&ounit);
219 
220  //
221  // *********** Get the cross section data
222  //
223  egsHatch();
224 
225  //
226  // *********** Set ecut_new and pcut_new
227  //
230 
231  //
232  // ********** Now check if the cross section data covers the energy
233  // range needed by the source
234  //
235  EGS_Float Emax = source->getEmax();
236  bool is_ok = true;
237  for (int imed=0; imed<g->nMedia(); imed++) {
238  if (Emax > the_thresh->up[imed] ||
239  Emax > the_thresh->ue[imed] - the_useful->rm) {
240  egsWarning("The maximum energy of the source (%g) is higher than\n"
241  " the cross section data energy range for medium %d\n",
242  Emax,imed+1);
243  is_ok = false;
244  }
245  }
246  if (!is_ok) {
247  egsFatal("Create new PEGS data sets and retry\n");
248  }
249 
250  nreport = 10;
251 
252 }
253 
255  if (g) {
256  if (g->deref()) {
257  delete g;
258  }
259  }
260  if (source) {
261  delete source;
262  }
263  if (rndm) {
264  delete rndm;
265  }
266  if (input) {
267  delete input;
268  }
269 }
270 
272  egsFinish();
273 }
274 
276 
277  egsInformation("\n\nSimulating %d particles...\n\n",ncase);
278  EGS_Timer timer;
279  timer.start();
280  EGS_I64 nperb = ncase/nreport;
281  if (nperb < 1) {
282  nperb = 1;
283  }
284  EGS_Float aperb = ((EGS_Float)nperb)/((EGS_Float)ncase);
285  int q, latch;
286  EGS_Float E, wt;
287  EGS_Vector x,u;
288  sum_E = 0;
289  sum_E2 = 0;
290  Etot = 0;
291  sum_w = 0;
292  sum_w2 = 0;
293  for (EGS_I64 icase=1; icase<=ncase; icase++) {
294  if (icase%nperb == 0) egsInformation("+Finished %7.2f percent of"
295  " cases, cpu time = %9.3f\n",
296  100*aperb*(icase/nperb),timer.time());
297  EGS_I64 this_case = source->getNextParticle(rndm,q,latch,E,wt,x,u);
298  //egsInformation("Got %d %g %g (%g,%g,%g) (%g,%g,%g) %lld\n",
299  // q,E,wt,x.x,x.y,x.z,u.x,u.y,u.z,this_case);
300  sum_E += E*wt;
301  sum_E2 += wt*E*E;
302  sum_w += wt;
303  sum_w2 += wt*wt;
304  int ireg = g->isWhere(x);
305  if (ireg < 0) {
306  EGS_Float t = veryFar;
307  ireg = g->howfar(ireg,x,u,t);
308  if (ireg >= 0) {
309  x += u*t;
310  }
311  }
312  if (ireg >= 0) {
313  //egsInformation(" entering in region %d\n",ireg);
314  last_case = this_case;
315  if (q == 1) {
316  Etot += (E + 2*the_useful->rm)*wt;
317  }
318  else {
319  Etot += E*wt;
320  }
321  the_stack->E[0] = (q) ? E + the_useful->rm : E;
322  the_stack->x[0] = x.x;
323  the_stack->y[0] = x.y;
324  the_stack->z[0] = x.z;
325  the_stack->u[0] = u.x;
326  the_stack->v[0] = u.y;
327  the_stack->w[0] = u.z;
328  the_stack->dnear[0] = 0;
329  the_stack->wt[0] = wt;
330  the_stack->ir[0] = ireg+2;
331  the_stack->iq[0] = q;
332  the_stack->latch[0] = latch;
333  the_stack->np = 1;
334  startHistory(this_case);
335  egsShower();
336  endHistory();
337  }
338  }
339  egsInformation("\n\nFinished simulation, CPU time was %g\n\n",
340  timer.time());
341  sum_E = sum_E/sum_w;
342  sum_E2 = sum_E2/sum_w;
343  sum_E2 -= sum_E*sum_E;
344  if (sum_E2 > 0) {
345  sum_E2 = sqrt(sum_E2/(sum_w*sum_w/sum_w2-1));
346  }
347  egsInformation("Average particle energy: %g +/- %g\n\n",sum_E,sum_E2);
348 
349  return 0;
350 
351 }
352 
353 void EGS_SimpleApplication::fillRandomArray(int n, EGS_Float *rarray) {
354  rndm->fillArray(n,rarray);
355 }
356 
357 extern __extc__ void egsHowfar() {
358  int np = the_stack->np-1;
359  int ireg = the_stack->ir[np]-2;
360  if (ireg < 0) {
361  the_epcont->idisc = 1;
362  return;
363  }
364  int newmed;
365  int inew = egsApp->howfar(ireg,
366  EGS_Vector(the_stack->x[np],the_stack->y[np],the_stack->z[np]),
367  EGS_Vector(the_stack->u[np],the_stack->v[np],the_stack->w[np]),
368  the_epcont->ustep,&newmed);
369  if (inew != ireg) {
370  the_epcont->irnew = inew+2;
371  the_useful->medium_new = newmed+1;
372  if (inew < 0) {
373  the_epcont->idisc = -1; // i.e. discard after the step.
374  the_useful->medium_new = 0;
375  }
376  }
377 }
378 
379 extern __extc__ void egsAusgab(EGS_I32 *iarg) {
380  egsApp->ausgab(*iarg);
381 }
382 
383 extern __extc__ void egsHownear(EGS_Float *tperp) {
384  int np = the_stack->np-1;
385  int ireg = the_stack->ir[np]-2;
386  *tperp = egsApp->hownear(ireg,EGS_Vector(the_stack->x[np],the_stack->y[np],
387  the_stack->z[np]));
388 }
389 
390 extern __extc__ void egsStartParticle() {
391  int np = the_stack->np - 1;
392  int ir = the_stack->ir[np]-2;
393  the_useful->medium = egsApp->getMedium(ir)+1;
394  the_epcont->idisc = 0;
395 }
396 
397 extern __extc__ void egsFillRandomArray(const EGS_I32 *n, EGS_Float *rarray) {
398  egsApp->fillRandomArray(*n,rarray);
399 }
400 
EGS_I32 iq[MXSTACK]
virtual const string & getType() const =0
Get the geometry type.
static EGS_BaseSource * createSource(EGS_Input *)
Create sources from the information pointed to by input.
__extc__ struct EGS_Stack * the_stack
The address of the mortran STACK common block as a pointer to a C-structure of type EGS_Stack...
EGS_Float ue[MXMED]
const char * egsHome() const
EGS_I32 medium
Current medium.
virtual int run()
Run the simulation.
EGS_Float v[MXSTACK]
int deref()
Decrease the reference count to this geometry.
EGS_Float pcut_new
EGS_Float time()
Returns the CPU time in seconds since start() was called.
Definition: egs_timer.cpp:106
EGS_I32 ir[MXSTACK]
EGS_I64 ncase
Number of showers to simulate.
const char * henHouse() const
EGS_BaseSource class header file.
EGS_BaseSource * source
The particle source.
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:200
void fillRandomArray(int n, EGS_Float *r)
Fill the array pointed to by r with n random numbers.
double sum_E
sum of E*wt of particles from the source
This file defines the C/C++ interface to the EGSnrc mortran back-end.
EGS_Input class header file.
EGS_Float y
y-component
Definition: egs_vector.h:61
EGS_Float pcut
EGS_Float w[MXSTACK]
A class representing 3D vectors.
Definition: egs_vector.h:56
__extc__ struct EGS_IO * the_egsio
The address of the mortran egs_io common block as a pointer to a C-structure of type EGS_IO...
A base class for developing simple EGSnrc applications.
#define egsStartParticle
EGS_I32 medium_new
Medium in the new region.
EGS_Float dnear[MXSTACK]
virtual int isWhere(const EGS_Vector &x)=0
In which region is poisition x?
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.
const EGS_Float veryFar
A very large float.
__extc__ void egsFinish(void)
Finish a simulation.
EGS_Float hownear(int ireg, const EGS_Vector &x)
See the EGSnrc hownear geometry specification .
EGS_Float ecut_new
const char * outputFile() const
__extc__ struct EGS_Epcont * the_epcont
The address of the mortran EPCONT common block as a pointer to a C-structure of type EGS_Epcont...
virtual void fillArray(int n, EGS_Float *array)=0
Fill the array of n elements pointed to by array with random numbers.
__extc__ struct EGS_Bounds * the_bounds
The address of the morrtan BOUNDS common block as a pointer to a C-structure of type EGS_Bounds...
__extc__ EGS_I32 egsAddMedium(const char *medname, EGS_I32 length)
Add a medium to the list of media.
virtual void startHistory(EGS_I64)
Start a new shower.
EGS_I32 latch[MXSTACK]
EGS_Float z
z-component
Definition: egs_vector.h:62
int getMedium(int ireg)
Get the medium index in region ireg.
EGS_InfoFunction EGS_EXPORT egsFatal
Always use this function for reporting fatal errors.
EGS_I32 np
static int nMedia()
Get the number of media registered so far by all geometries.
EGS_Input * input
The input found in the input file.
EGS_Float x[MXSTACK]
EGS_RandomGenerator class header file.
EGS_SimpleApplication class header file.
__extc__ struct EGS_Useful * the_useful
The address of the mortran USEFUL common block as a pointer to a C-structure of type EGS_Useful...
EGS_InfoFunction EGS_EXPORT egsInformation
Always use this function for reporting the progress of a simulation and any other type of information...
const char * inputFile() const
const char * userCode() const
#define egsFillRandomArray
EGS_RandomGenerator * rndm
The random number generator.
virtual void finish()
Finish the simulation.
#define egsAusgab
int nreport
How often to report the progress.
double E[MXSTACK]
A simple class for measuring CPU time.
Definition: egs_timer.h:57
static void describeGeometries()
Describes all existing geometries.
EGS_Float ustep
__extc__ void egsGetTransportParameter(const int *ounit)
Get the transport parameter settings from the input file.
double sum_w
sum of weights
EGS_SimpleApplication(int argc, char **argv)
Construct a simple application object.
EGS_Float x
x-component
Definition: egs_vector.h:60
EGS_Float y[MXSTACK]
EGS_Float rm
Electron rest energy.
EGS_Float wt[MXSTACK]
void start()
Starts the time measurement.
Definition: egs_timer.cpp:102
static EGS_BaseGeometry * createGeometry(EGS_Input *)
Create a geometry (or geometries) from a given input.
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:408
#define egsHowfar
__extc__ void egsInit(int argc, char **argv)
Initializes the EGSnrc mortran back-end.
A class for storing information in a tree-like structure of key-value pairs. This class is used throu...
Definition: egs_input.h:182
static const char * getMediumName(int ind)
Get the name of medium with index ind.
const string & getName() const
Get the name of this geometry.
#define egsHownear
static EGS_RandomGenerator * defaultRNG(int sequence=0)
Returns a pointer to the default egspp RNG.
Definition: egs_rndm.cpp:464
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.
const char * workDir() const
__extc__ struct EGS_Thresh * the_thresh
The address of the mortran THRESH common block as a pointer to a C-structure of type EGS_Thresh...
EGS_Float up[MXMED]
EGS_Float u[MXSTACK]
__extc__ void egsShower(void)
Transport the particles currently on the particle stack.
__extc__ void egsHatch(void)
Initialize cross section data from a PEGS4 data file.
EGS_Float ecut
EGS_Timer class header file.
EGS_Input * takeInputItem(const string &key, bool self=true)
Get the property named key.
Definition: egs_input.cpp:226
EGS_I32 irnew
virtual EGS_Float getEmax() const =0
Return the maximum energy of this source.
double sum_E2
sum of E*E*wt of particles from the source
EGS_I64 last_case
last statistically independent event
double sum_w2
sum of weights squared
const char * pegsFile() const
int howfar(int ireg, const EGS_Vector &x, const EGS_Vector &u, EGS_Float &t, int *newmed)
See the EGSnrc howfar geometry specification .
EGS_BaseGeometry * g
The simulation geometry.
EGS_I32 idisc
EGS_Float z[MXSTACK]
EGS_InfoFunction EGS_EXPORT egsWarning
Always use this function for reporting warnings.