EGSnrc C++ class library  Report PIRS-898 (2021)
Iwan Kawrakow, Ernesto Mainegra-Hing, Frederic Tessier, Reid Townson and Blake Walters
egs_beam_source.cpp
Go to the documentation of this file.
1 /*
2 ###############################################################################
3 #
4 # EGSnrc egs++ beam source
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: Blake Walters
27 # Frederic Tessier
28 # Reid Townson
29 # Ernesto Mainegra-Hing
30 # Alexandre Demelo
31 # Hannah Gallop
32 #
33 ###############################################################################
34 */
35 
36 
42 #include "egs_beam_source.h"
43 #include "egs_input.h"
44 #include "egs_functions.h"
45 #include "egs_library.h"
46 #include "egs_application.h"
47 
48 #include <cstdlib>
49 #include <cstring>
50 
51 #define STRINGIFY(s) HELP_S(s)
52 #define HELP_S(s) #s
53 #define F77_NAME(fname,FNAME) STRINGIFY(F77_OBJ(fname,FNAME))
54 #define F77_NAME_(fname,FNAME) STRINGIFY(F77_OBJ_(fname,FNAME))
55 
56 static bool EGS_BEAM_SOURCE_LOCAL inputSet = false;
57 
59  EGS_BaseSource(input,f) {
60  n_reuse_photon = 0;
61  n_reuse_electron = 0;
62  i_reuse_photon = 0;
63  i_reuse_electron = 0;
64  is_valid = false;
65  time_stored = false;
66  lib = 0;
67  Xmin = -veryFar;
68  Xmax = veryFar;
69  Ymin = -veryFar;
70  Ymax = veryFar;
71  wmin = -veryFar;
72  wmax = veryFar;
73  string beam_code;
74  int err1 = input->getInput("beam code",beam_code);
75  string pegs_file;
76  int err2 = input->getInput("pegs file",pegs_file);
77  string input_file;
78  int err3 = input->getInput("input file",input_file);
79  if (err1) {
80  egsWarning("EGS_BeamSource: no 'beam code' input\n");
81  }
82  if (err2) {
83  egsWarning("EGS_BeamSource: no 'pegs file' input\n");
84  }
85  if (err3) {
86  egsWarning("EGS_BeamSource: no 'input file' input\n");
87  }
88  if (err1 || err2 || err3) {
89  return;
90  }
91  string egs_home;
92  int err_eh = input->getInput("egs_home",egs_home);
93  if (err_eh) {
94  char *eh = getenv("EGS_HOME");
95  if (!eh) {
96  egsWarning("EGS_BeamSource: EGS_HOME is not defined\n");
97  return;
98  }
99  else {
100  egs_home = eh;
101  }
102  }
103  else {
104  egs_home = egsExpandPath(egs_home);
105  }
106  string hen_house;
107  int err_hh = input->getInput("hen_house",hen_house);
108  if (err_hh) {
109  char *hh = getenv("HEN_HOUSE");
110  if (!hh) {
111  egsWarning("EGS_BeamSource: HEN_HOUSE is not defined\n");
112  return;
113  }
114  else {
115  hen_house = hh;
116  }
117  }
118  else {
119  hen_house = egsExpandPath(hen_house);
120  }
121  string path = egs_home;
122  path += "bin/";
123  path += CONFIG_NAME;
124  lib = new EGS_Library(beam_code.c_str(),path.c_str());
125 
126  InitFunction init = (InitFunction)
127  lib->resolve(F77_NAME_(beamlib_init,BEAMLIB_INIT));
128  finish = (FinishFunction)
129  lib->resolve(F77_NAME_(beamlib_finish,BEAMLIB_FINISH));
130  sample = (SampleFunction)
131  lib->resolve(F77_NAME_(beamlib_sample,BEAMLIB_SAMPLE));
132  motionsample = (MotionSampleFunction)
133  lib->resolve(F77_NAME_(beamlib_motionsample,BEAMLIB_MOTIONSAMPLE));
134  MaxEnergyFunction maxenergy = (MaxEnergyFunction)
135  lib->resolve(F77_NAME_(beamlib_max_energy,BEAMLIB_MAX_ENERGY));
136  if (!init) {
137  egsWarning("EGS_BeamSource: failed to resolve the init function\n");
138  }
139  if (!sample) {
140  egsWarning("EGS_BeamSource: failed to resolve the sample function\n");
141  }
142  if (!motionsample) {
143  egsWarning("EGS_BeamSource: failed to resolve the motionsample function\n");
144  }
145  if (!finish) {
146  egsWarning("EGS_BeamSource: failed to resolve the finish function\n");
147  }
148  if (!maxenergy) {
149  egsWarning("EGS_BeamSource: failed to resolve the max. energy function\n");
150  }
151  if (!init || !sample || !finish || !maxenergy) {
152  return;
153  }
154 
155  int ipar=0, ilog=6;
156  int npar=0;
158  if (app) {
159  ipar = app->getIparallel();
160  npar = app->getNparallel();
161  }
162 
163  init(&ipar,&npar,&ilog,hen_house.c_str(),egs_home.c_str(),
164  beam_code.c_str(),pegs_file.c_str(),input_file.c_str(),
165  hen_house.size(), egs_home.size(),
166  beam_code.size(),pegs_file.size(),input_file.size());
167  maxenergy(&Emax);
168 
169  is_valid = true;
170 
171  vector<EGS_Float> cutout;
172  int err = input->getInput("cutout",cutout);
173  if (!err && cutout.size() == 4) {
174  setCutout(cutout[0],cutout[1],cutout[2],cutout[3]);
175  }
176  vector<string> ptype;
177  ptype.push_back("electrons");
178  ptype.push_back("photons");
179  ptype.push_back("positrons");
180  ptype.push_back("all");
181  ptype.push_back("charged");
182  particle_type = input->getInput("particle type",ptype,3)-1;
183 
184  vector<EGS_Float> wwindow;
185  err = input->getInput("weight window",wwindow);
186  if (!err && wwindow.size() == 2) {
187  wmin = wwindow[0];
188  wmax = wwindow[1];
189  }
190 
191  int ntmp;
192  err = input->getInput("reuse photons",ntmp);
193  if (!err && ntmp > 1) {
194  n_reuse_photon = ntmp;
195  }
196  err = input->getInput("reuse electrons",ntmp);
197  if (!err && ntmp > 1) {
198  n_reuse_electron = ntmp;
199  }
200 
201  // now see if time is returned from the BEAM source use motionsample
202  // function, ttime will be -1 if not provided by BEAM have to save the
203  // values read here to use as the first particle in the simulation
204  motionsample(&tei,&txi,&tyi,&tzi,&tui,&tvi,&twi,&twti,&tqi,&tlatchi,&counti,&tiphati,&ttimei);
205 
206  if (!time_stored) {
207  if (ttimei >= 0.0 && ttimei <= 1.0) {
208  egsInformation("EGS_BeamSource:: Time index passed from this source.\n");
209  time_stored = true;
210  }
211  }
212 
213  use_iparticle = true;
214 
215  description = beam_code;
216  description += "(";
217  description += input_file;
218  description += ") simulation source";
219  otype="EGS_BeamSource";
220 }
221 
222 EGS_I64 EGS_BeamSource::getNextParticle(EGS_RandomGenerator *, int &q,
223  int &latch, EGS_Float &E, EGS_Float &wt, EGS_Vector &x, EGS_Vector &u) {
224  if (n_reuse_photon > 0 && i_reuse_photon < n_reuse_photon) {
225  q = q_save;
226  latch = latch_save;
227  E = E_save;
228  wt = wt_save;
229  x = x_save;
230  u = u_save;
231  time = time_save;
232  ++i_reuse_photon;
233  return count;
234  }
235  if (n_reuse_electron > 0 && i_reuse_electron < n_reuse_electron) {
236  q = q_save;
237  latch = latch_save;
238  E = E_save;
239  wt = wt_save;
240  x = x_save;
241  u = u_save;
242  time = time_save;
243  ++i_reuse_electron;
244  return count;
245  }
246  EGS_Float te,tx,ty,tz,tu,tv,tw,twt,ttime;
247  int tq,tlatch,tiphat;
248  bool ok;
249  do {
250  if (use_iparticle) {
251  //reuse data for first particle read in when setting up the source
252  te=tei;
253  tx=txi;
254  ty=tyi;
255  tz=tzi;
256  tu=tui;
257  tv=tvi;
258  tw=twi;
259  twt=twti;
260  tq=tqi;
261  tlatch=tlatchi;
262  count=counti;
263  tiphat=tiphati;
264  ttime=ttimei;
265  use_iparticle=false;
266  }
267  else {
268  motionsample(&te,&tx,&ty,&tz,&tu,&tv,&tw,&twt,&tq,&tlatch,&count,&tiphat,&ttime);
269  //sample(&te,&tx,&ty,&tz,&tu,&tv,&tw,&twt,&tq,&tlatch,&count,&tiphat);
270  //egsInformation("EGS_BeamSource::getNextParticle: Got E=%g q=%d wt=%g"
271  // " x=(%g,%g,%g) latch=%d count=%lld\n",te,tq,twt,tx,ty,tz,
272  // tlatch,count);
273  if (time_stored && (ttime < 0. || ttime > 1.0)) {
274  //something's wrong
275  egsWarning("EGS_BeamSource::getNextParticle: Time index is stored in this source but time returned < 0\n");
276  egsWarning("Will no longer read time.\n");
277  time_stored = false;
278  }
279  }
280  if (tq) {
281  te -= EGS_Application::activeApplication()->getRM();
282  }
283  ok = true;
284  if (te > Emax + epsilon) {
285  ok = false;
286  } //egsInformation("Emax rejection\n"); }
287  if (particle_type < 2 && tq != particle_type) {
288  ok = false;
289  } // egsInformation("charge rejection"); }
290  if (particle_type == 3 && !tq) {
291  ok = false;
292  }
293  if (tx < Xmin || tx > Xmax || ty < Ymin || ty > Ymax) {
294  ok = false;
295  } // egsInformation("cutout rejection\n"); }
296  if (twt < wmin || twt > wmax) {
297  ok = false; // egsInformation("weight rejection\n");
298  }
299  }
300  while (!ok);
301  i_reuse_electron = n_reuse_electron;
302  i_reuse_photon = n_reuse_photon;
303  //egsInformation("returning particle\n");
304  E = te;
305  q = tq;
306  latch = 0; //latch = tlatch;
307  bool save_it = false;
308  if (n_reuse_photon > 1 && !tq) {
309  twt /= n_reuse_photon;
310  i_reuse_photon = 1;
311  save_it = true;
312  }
313  if (n_reuse_electron > 1 && tq) {
314  twt /= n_reuse_electron;
315  i_reuse_electron = 1;
316  save_it = true;
317  }
318  wt = twt;
319  x = EGS_Vector(tx,ty,tz);
320  u = EGS_Vector(tu,tv,tw);
321  time = ttime;
322  if (save_it) {
323  q_save = tq;
324  latch_save = 0;
325  E_save = E;
326  wt_save = twt;
327  x_save = x;
328  u_save = u;
329  time_save = time;
330  }
331 
332  if (time_stored) {
333  setTimeIndex(time);
334  /* this is setting the time index using the base source set call. We get
335  * rid of the local getTimeIndex function and it should allow for saving
336  * time in the base source like all the other sources do */
337  }
338  else {
339  setTimeIndex(-1);
340  }
341 
342  return count;
343 }
344 
350 void EGS_BeamSource::containsDynamic(bool &hasdynamic) {
351  hasdynamic = time_stored;
352 }
353 
354 EGS_BeamSource::~EGS_BeamSource() {
355  if (lib) {
356  if (is_valid) {
357  finish();
358  }
359  delete lib;
360  }
361 }
362 
363 extern "C" {
364 
365  static void setInputs() {
366  inputSet = true;
367 
368  setBaseSourceInputs(false, false);
369 
370  srcBlockInput->getSingleInput("library")->setValues({"egs_beam_source"});
371 
372  // Format: name, isRequired, description, vector string of allowed values
373  srcBlockInput->addSingleInput("beam code", true, "The name of the BEAMnrc user code. Note that it must be compiled as a shared library, which is not done by default.");
374  srcBlockInput->addSingleInput("pegs file", true, "The name of the PEGS file to be used in the BEAMnrc simulation. Use 'pegsless' if a pegs file is not used.");
375  srcBlockInput->addSingleInput("input file", true, "The name of the BEAMnrc input file, that must reside in the accelerator directory. Make sure to test running BEAMnrc with it before using it here!");
376  srcBlockInput->addSingleInput("cutout", false, "Discard particles outside of a rectanglular field: 'x1 y1 x2 y2'");
377  srcBlockInput->addSingleInput("particle type", false, "The type of particle to keep from the BEAMnrc simulation. Other types are discarded.", {"all", "electrons", "photons", "positrons", "charged"});
378  srcBlockInput->addSingleInput("weight window", false, "A weight window, outside of which particles are discarded: 'wtmin wtmax'. This allows you to discard high weight particles.");
379  }
380 
381  EGS_BEAM_SOURCE_EXPORT string getExample() {
382  string example;
383  example = {
384  R"(
385  # Example of egs_beam_source
386  #:start source:
387  library = egs_beam_source
388  name = my_source
389  beam code = BEAM_EX10MeVe
390  pegs file = 521icru
391  particle type = all
392  :stop source:
393 )"};
394  return example;
395  }
396 
397  EGS_BEAM_SOURCE_EXPORT shared_ptr<EGS_BlockInput> getInputs() {
398  if(!inputSet) {
399  setInputs();
400  }
401  return srcBlockInput;
402  }
403 
404  EGS_BEAM_SOURCE_EXPORT EGS_BaseSource *createSource(EGS_Input *input,
405  EGS_ObjectFactory *f) {
406  return
407  createSourceTemplate<EGS_BeamSource>(input,f,"beam source");
408  }
409 
410 }
Base class for advanced EGSnrc C++ applications.
static EGS_Application * activeApplication()
Get the active application.
int getNparallel() const
Returns the number of parallel jobs executing.
int getIparallel() const
Returns the job number in a parallel run.
Base source class. All particle sources must be derived from this class.
string description
A short source description.
SampleFunction sample
The function that returns the next particle.
void containsDynamic(bool &hasdynamic)
Check if the simulation source contains time indices.
EGS_BeamSource(EGS_Input *, EGS_ObjectFactory *f=0)
Create a BEAM simulation source from the input inp.
bool time_stored
true if time index stored
FinishFunction finish
EGS_Library * lib
The BEAMnrc user code library.
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 getInput(const string &key, vector< string > &values) const
Assign values to an array of strings from an input identified by key.
Definition: egs_input.cpp:341
A class for dynamically loading shared libraries.
Definition: egs_library.h:52
void * resolve(const char *func)
Returns the address of the exported symbol func.
An object factory.
string otype
The object type.
Base random number generator class. All random number generators should be derived from this class.
Definition: egs_rndm.h:90
A class representing 3D vectors.
Definition: egs_vector.h:57
EGS_Application class header file.
A BEAM simulation source.
Global egspp functions header file.
EGS_Input class header file.
EGS_Library class header file.
EGS_InfoFunction EGS_EXPORT egsInformation
Always use this function for reporting the progress of a simulation and any other type of information...
string egsExpandPath(const string &aname)
Expands first environment variable found in a file name.
const EGS_Float epsilon
The epsilon constant for floating point comparisons.
Definition: egs_functions.h:62
EGS_InfoFunction EGS_EXPORT egsWarning
Always use this function for reporting warnings.
const EGS_Float veryFar
A very large float.