EGSnrc C++ class library  Report PIRS-898 (2021)
Iwan Kawrakow, Ernesto Mainegra-Hing, Frederic Tessier, Reid Townson and Blake Walters
egs_base_source.h
Go to the documentation of this file.
1 /*
2 ###############################################################################
3 #
4 # EGSnrc egs++ base source headers
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 # Ernesto Mainegra-Hing
28 # Blake Walters
29 # Alexandre Demelo
30 #
31 ###############################################################################
32 */
33 
34 
43 #ifndef EGS_BASE_SOURCE_
44 #define EGS_BASE_SOURCE_
45 
46 #include "egs_vector.h"
47 #include "egs_object_factory.h"
48 #include "egs_functions.h"
49 #include "egs_ensdf.h"
50 #include "egs_input_struct.h"
51 
52 #include <string>
53 #include <iostream>
54 #include "egs_math.h"
55 
56 using namespace std;
57 
58 class EGS_Input;
60 
61 static shared_ptr<EGS_BlockInput> srcBlockInput = make_shared<EGS_BlockInput>("source");
62 inline void setBaseSourceInputs(bool isSimpleSource = true, bool includeSpectrumBlock = true) {
63  srcBlockInput->addSingleInput("library", true, "The type of source, loaded by shared library in egs++/dso.");
64  srcBlockInput->addSingleInput("name", true, "The user-declared unique name of this source. This is the name you may refer to elsewhere in the input file");
65 
66  if (isSimpleSource) {
67  includeSpectrumBlock = true;
68  srcBlockInput->addSingleInput("charge", true, "The type of particle to emit from the source, as defined by the charge. Use 0 for photons, -1 for electrons and 1 for positrons.", {"0", "1", "-1"});
69  }
70  if (includeSpectrumBlock) {
71  shared_ptr<EGS_BlockInput> specBlock = srcBlockInput->addBlockInput("spectrum");
72  auto typePtr = specBlock->addSingleInput("type", true, "The type of energy distribution for the spectrum.", {"monoenergetic", "Gaussian", "Double Gaussian", "uniform", "tabulated spectrum", "radionuclide"});
73 
74  // Monoenergetic
75  specBlock->addSingleInput("energy", false, "The kinetic energy of the source particles in MeV.")->addDependency(typePtr, "monoenergetic");
76 
77  // Gaussian & double Gaussian
78  specBlock->addSingleInput("mean energy", false, "The mean kinetic energy of the source particles in MeV.")->addDependency(typePtr, "Gaussian");
79  auto sigmaPtr = specBlock->addSingleInput("sigma", false, "The sigma of the spectrum. For a double Gaussian, input two values.");
80  sigmaPtr->addDependency(typePtr, "Gaussian");
81  sigmaPtr->addDependency(typePtr, "Double Gaussian");
82  auto fwhmPtr = specBlock->addSingleInput("fwhm", false, "The full-width-at-half-maximum of the spectrum. For a double Gaussian, input two values.");
83  fwhmPtr->addDependency(typePtr, "Gaussian");
84  fwhmPtr->addDependency(typePtr, "Double Gaussian");
85  fwhmPtr->addDependency(sigmaPtr, "", true);
86  sigmaPtr->addDependency(fwhmPtr, "", true);
87 
88  // Uniform
89  auto rangePtr = specBlock->addSingleInput("range", false, "The minimum and maximum energy for the spectrum, in MeV.");
90  rangePtr->addDependency(typePtr, "uniform");
91  auto minEPtr = specBlock->addSingleInput("minimum energy", false, "The minimum energy for the spectrum, in MeV.");
92  minEPtr->addDependency(typePtr, "uniform");
93  auto maxEPtr = specBlock->addSingleInput("maximum energy", false, "The maximum energy for the spectrum, in MeV.");
94  maxEPtr->addDependency(typePtr, "uniform");
95  minEPtr->addDependency(rangePtr, "", true);
96  maxEPtr->addDependency(rangePtr, "", true);
97  rangePtr->addDependency(minEPtr, "", true);
98  rangePtr->addDependency(maxEPtr, "", true);
99 
100  // Tabulated
101  auto specFilePtr = specBlock->addSingleInput("spectrum file", false, "The full file path to the spectrum file. See documentation for the format of the file.");
102  specFilePtr->addDependency(typePtr, "tabulated spectrum");
103  auto modePtr = specBlock->addSingleInput("spectrum mode", false, "The mode number that denotes how to create the spectrum. Use 0 for histogram counts/bin, 1 for counts/MeV, 2 for a line spectrum and 3 for an interpolated spectrum.");
104  modePtr->addDependency(typePtr, "tabulated spectrum");
105  auto energiesPtr = specBlock->addSingleInput("energies", false, "A list of energies for the spectrum, in MeV. When applicable, this is the upper edge of the bin.");
106  energiesPtr->addDependency(typePtr, "tabulated spectrum");
107  auto probsPtr = specBlock->addSingleInput("probabilities", false, "A list of probabilities for the spectrum. Does not need to be normalized.");
108  probsPtr->addDependency(typePtr, "tabulated spectrum");
109  modePtr->addDependency(specFilePtr, "", true);
110  energiesPtr->addDependency(specFilePtr, "", true);
111  probsPtr->addDependency(specFilePtr, "", true);
112 
113  // Radionuclide
114  specBlock->addSingleInput("nuclide", true, "The name of the nuclide to model, e.g. Co-60 or Tc-99m. If the 'ensdf file' input is not specified, then the ENSDF file will be searched for as $HEN_HOUSE/spectra/lnhb/ensdf/nuclide.txt, where nuclide is the text you input. Note that a radionuclide spectrum is ONLY compatible with a radionuclide source.")->addDependency(typePtr, "radionuclide");
115  specBlock->addSingleInput("ensdf file", false, "The full path to the ENSDF file to use.")->addDependency(typePtr, "radionuclide");
116  specBlock->addSingleInput("relative activity", false, "If multiple radionuclide spectra are specified for a single radionuclide source, this is the relative weight of this spectrum. Defaults to 1.")->addDependency(typePtr, "radionuclide");
117  specBlock->addSingleInput("atomic relaxations", false, "The model to use for atomic relaxations resulting from radionuclide decay. Defaults to EADL.", {"eadl", "ensdf", "off"})->addDependency(typePtr, "radionuclide");
118  specBlock->addSingleInput("output beta spectra", false, "Whether or not to output as files the beta spectra that are used for sampling beta decay energies. Defaults to No.", {"yes", "no"})->addDependency(typePtr, "radionuclide");
119  specBlock->addSingleInput("alpha scoring", false, "The model to use for scoring alpha particles during radionuclide decay. Defaults to Discard.", {"local", "discard"})->addDependency(typePtr, "radionuclide");
120  specBlock->addSingleInput("extra transition approximation", false, "Whether or not to use the option that automatically balances transition intensities. Defaults to Off.", {"on","off"})->addDependency(typePtr, "radionuclide");
121  }
122 }
123 
149 
150 public:
151 
155  EGS_BaseSource(const string &Name="", EGS_ObjectFactory *f = 0) :
156  EGS_Object(Name,f), time_index(-1) {};
157 
167  EGS_Object(input,f), time_index(-1) {};
168  virtual ~EGS_BaseSource() {};
169 
175  const char *getSourceDescription() const {
176  return description.c_str();
177  };
178 
199  virtual EGS_I64 getNextParticle(EGS_RandomGenerator *rndm,
200  int &q, int &latch, // charge and latch
201  EGS_Float &E, EGS_Float &wt, // energy and weight
202  EGS_Vector &x, EGS_Vector &u) = 0; // position and direction
203 
211  virtual void setSimulationChunk(EGS_I64 nstart, EGS_I64 nrun, int npar, int nchunk) {
212  (void)nstart;
213  (void)nrun;
214  (void)npar;
215  (void)nchunk;
216  };
217 
225  virtual int getCharge() const {
226  return -99;
227  };
238  virtual EGS_Float getEmax() const = 0;
239 
253  virtual EGS_Float getFluence() const = 0;
254 
255  /* A virtual function which can be implemented in derived classes
256  * to return a fractional monitor unit associated with each source
257  * particle. Currently only makes sense for IAEA_PhspSource and
258  * EGS_BeamSource.
259  */
260  //virtual EGS_Float getTimeIndex() {
261  //return -1;
262  //};
263 
264  //virtual void setTimeIndex(EGS_Float temp_time) {};
265 
267  virtual void printSampledEmissions() {};
268 
273  virtual vector<EGS_Ensdf *> getRadionuclideEnsdf() {
274  return vector<EGS_Ensdf *>();
275  };
276 
288  virtual bool storeState(ostream &data_out) const {
289  (void)data_out;
290  return true;
291  };
292 
303  virtual bool setState(istream &data_in) {
304  (void)data_in;
305  return true;
306  };
307 
320  virtual bool addState(istream &data_in) {
321  (void)data_in;
322  return true;
323  };
324 
336  virtual void resetCounter() {};
337 
364  static EGS_BaseSource *createSource(EGS_Input *);
365 
374  static EGS_BaseSource *getSource(const string &Name);
375 
383  static void addKnownSource(EGS_BaseSource *o);
384 
393  static void addKnownTypeId(const char *name);
394 
395  /* Centralize the time index parameter so that it can be saved to and
396  * accessed from a single point. In almost any instance where a time index
397  * parameter is created, it is saved in the source object using
398  * setTimeIndex. When other objects would like to access the time index
399  * (most relevant example being the dynamic geometry checking if the source
400  * has provided a time index before setting its own), they can call
401  * getTimeIndex. In many cases, this method is indirectly called via the
402  * getTimeIndex in the application class, which returns the results of
403  * getTimeIndex call on the simulation source. Note there are two cases
404  * which behave slightly differently and may need some modifications. While
405  * the dynamicSource time index implementation was completely absorbed into
406  * the basesource, this was not done for the beam source and the iaea_phsp
407  * source, as they had slightly more involved time index implementations
408  * that seemed best left alone. They do not have setTimeIndex methods, \
409  * and may not return the right thing if we set the time using the geometry,
410  * as calling get may try to get the beam or iaea_phsp time index and not
411  * the basesource index we set with the geometry. */
412  EGS_Float getTimeIndex() {
413  return time_index;
414 
415  };
416 
417  void setTimeIndex(EGS_Float temp_time) {
418  time_index=temp_time;
419  };
420 
421  /* This method is essentially used to determine whether the simulation
422  * source contains a dynamic source. The only
423  * non-empty implementations of this function are in composite sources
424  * (where it simply calls containsDynamic on its components),
425  * where it will update the boolean reference to true and
426  * call containsDynamic on its base geometry, and sources that
427  * can contain time indices (dynamic, phsp, beam sources).
428  * This function was conceived to be used in the
429  * view/viewcontrol (to determine whether time index objects are visible or
430  * hidden), and track scoring */
431  virtual void containsDynamic(bool &hasdynamic) {
432  (void)hasdynamic;
433  };
434 
435 protected:
436 
442  string description;
443 
447  EGS_Float time_index;
448 
449 };
450 
469 
470 public:
471 
477  EGS_BaseSpectrum() : count(0), sum_E(0), sum_E2(0),
478  type("Unknown spectrum") {};
479 
481  virtual ~EGS_BaseSpectrum() {};
482 
489  const string &getType() const {
490  return type;
491  };
492 
499  inline EGS_Float sampleEnergy(EGS_RandomGenerator *rndm) {
500  EGS_Float e = sample(rndm);
501  count++;
502  sum_E += e;
503  sum_E2 += e*e;
504  return e;
505  };
506 
512  virtual EGS_Float maxEnergy() const = 0;
513 
519  virtual EGS_Float expectedAverage() const = 0;
520 
533  virtual bool storeState(ostream &data_out) const {
534  if (!egsStoreI64(data_out,count)) {
535  return false;
536  }
537  data_out << " " << sum_E << " " << sum_E2 << endl;
538  if (!data_out.good() || data_out.fail()) {
539  return false;
540  }
541  return true;
542  };
543 
557  virtual bool setState(istream &data_in) {
558  if (!egsGetI64(data_in,count)) {
559  return false;
560  }
561  data_in >> sum_E >> sum_E2;
562  if (data_in.eof() || !data_in.good() || data_in.fail()) {
563  return false;
564  }
565  return true;
566  };
567 
580  virtual bool addState(istream &data_in) {
581  EGS_I64 count_save = count;
582  double sum_E_save = sum_E, sum_E2_save = sum_E2;
583  if (!setState(data_in)) {
584  return false;
585  }
586  count += count_save;
587  sum_E += sum_E_save;
588  sum_E2 += sum_E2_save;
589  return true;
590  };
591 
603  virtual void resetCounter() {
604  count = 0;
605  sum_E = 0;
606  sum_E2 = 0;
607  };
608 
622  static EGS_BaseSpectrum *createSpectrum(EGS_Input *inp);
623 
629  void getSampledAverage(EGS_Float &e, EGS_Float &de) const {
630  if (count > 1) {
631  e = sum_E/count;
632  de = sum_E2/count;
633  de -= e*e;
634  if (de > 0) {
635  de = sqrt(de/(count-1));
636  }
637  }
638  };
639 
645  void reportAverageEnergy() const {
646  egsInformation("expected average energy: %g\n",expectedAverage());
647  EGS_Float e=0,de=0;
648  getSampledAverage(e,de);
649  egsInformation("sampled average energy: %g +/- %g\n",e,de);
650  };
651 
652 protected:
653 
660  virtual EGS_Float sample(EGS_RandomGenerator *rndm) = 0;
661 
663  EGS_I64 count;
664 
666  double sum_E;
667 
669  double sum_E2;
670 
674  string type;
675 
676 };
677 
697 
698 public:
699 
708  const string &Name="", EGS_ObjectFactory *f=0) :
709  EGS_BaseSource(Name,f), q(Q), s(Spec), count(0) { };
710 
722 
728  if (s) {
729  delete s;
730  }
731  };
732 
743  virtual bool isValid() const {
744  return (s != 0);
745  };
746 
758  virtual EGS_I64 getNextParticle(EGS_RandomGenerator *rndm,
759  int &Q, int &latch, EGS_Float &E, EGS_Float &wt,
760  EGS_Vector &x, EGS_Vector &u) {
761  Q = q;
762  E = s->sampleEnergy(rndm);
763  getPositionDirection(rndm,x,u,wt);
764  setLatch(latch);
765  return ++count;
766  };
767 
777  EGS_Vector &x, EGS_Vector &u, EGS_Float &wt) = 0;
778 
784  virtual EGS_Float getEmax() const {
785  return s->maxEnergy();
786  };
787 
792  int getCharge() const {
793  return q;
794  };
795 
806  virtual bool storeFluenceState(ostream &data_out) const {
807  (void)data_out;
808  return true;
809  };
810 
816  virtual bool storeState(ostream &data_out) const {
817  if (!egsStoreI64(data_out,count)) {
818  return false;
819  }
820  if (!s->storeState(data_out)) {
821  return false;
822  }
823  if (!storeFluenceState(data_out)) {
824  return false;
825  }
826  return true;
827  };
828 
835  virtual bool addState(istream &data) {
836  EGS_I64 count_save = count;
837  if (!egsGetI64(data,count)) {
838  return false;
839  }
840  if (!s->addState(data)) {
841  return false;
842  }
843  if (!addFluenceData(data)) {
844  return false;
845  }
846  count += count_save;
847  return true;
848  };
849 
856  virtual void resetCounter() {
857  count = 0;
858  s->resetCounter();
859  resetFluenceCounter();
860  };
861 
871  virtual bool addFluenceData(istream &data) {
872  (void)data;
873  return true;
874  }
875 
886  virtual void resetFluenceCounter() { };
887 
898  virtual bool setFluenceState(istream &data) {
899  (void)data;
900  return true;
901  };
902 
909  virtual bool setState(istream &data) {
910  if (!egsGetI64(data,count)) {
911  return false;
912  }
913  if (!s->setState(data)) {
914  return false;
915  }
916  if (!setFluenceState(data)) {
917  return false;
918  }
919  return true;
920  };
921 
922 protected:
923 
930  virtual void setLatch(int &latch) {
931  latch = 0;
932  };
933 
935  int q;
936 
939 
941  string type;
942 
944  EGS_I64 count;
945 
946 };
947 
957 template <class T>
959  EGS_ObjectFactory *f, const char *name) {
960  EGS_BaseSource::addKnownTypeId(typeid(T).name());
961  if (!input) {
962  egsWarning("createSource(%s): null input?\n",name);
963  return 0;
964  }
965  T *res = new T(input,f);
966  if (!res->isValid()) {
967  egsWarning("createSource(%s): the input is not "
968  "sufficient to create a valid source\n",name);
969  delete res;
970  return 0;
971  }
972  return res;
973 };
974 
975 #endif
976 
Base class for 'simple' particle sources.
string type
A short description of the source type.
EGS_BaseSimpleSource(int Q, EGS_BaseSpectrum *Spec, const string &Name="", EGS_ObjectFactory *f=0)
Constructor.
~EGS_BaseSimpleSource()
Destructor.
int q
The charge of this simple source.
virtual bool addFluenceData(istream &data)
Add fluence data from the stream data to the current state.
virtual void getPositionDirection(EGS_RandomGenerator *rndm, EGS_Vector &x, EGS_Vector &u, EGS_Float &wt)=0
Sample a particle position and direction.
EGS_BaseSpectrum * s
The energy spectrum of this source.
virtual bool isValid() const
Is this a valid source?
virtual bool setState(istream &data)
Set the source state according to the data in the stream data.
virtual void resetFluenceCounter()
Reset the data related to the sampling of positions and directions to a state with zero sampled parti...
virtual bool storeFluenceState(ostream &data_out) const
Store the fluence state of this source to the data stream data_out.
virtual bool addState(istream &data)
Add the source state from the stream data to the current state.
int getCharge() const
Get the charge of the source.
virtual bool storeState(ostream &data_out) const
Store the source state to the data stream data_out.
virtual EGS_Float getEmax() const
Get the maximum energy of the source.
virtual void resetCounter()
Reset the source to a state with zero sampled particles.
virtual void setLatch(int &latch)
virtual bool setFluenceState(istream &data)
Set the data related to the sampling of positions and directions to a state contained in the stream d...
EGS_I64 count
Number of statistically independent particles delivered so far.
virtual EGS_I64 getNextParticle(EGS_RandomGenerator *rndm, int &Q, int &latch, EGS_Float &E, EGS_Float &wt, EGS_Vector &x, EGS_Vector &u)
Sample the next source particle from the source probability distribution.
Base source class. All particle sources must be derived from this class.
virtual int getCharge() const
Get the charge of the source.
virtual bool addState(istream &data_in)
Add data from the stream data_in to the source state.
EGS_BaseSource(EGS_Input *input, EGS_ObjectFactory *f=0)
Construct a source from the input pointed to by inp.
const char * getSourceDescription() const
Get a short description of this source.
EGS_BaseSource(const string &Name="", EGS_ObjectFactory *f=0)
Construct a source named Name.
virtual void printSampledEmissions()
Print statistics on what was sampled from the source.
virtual EGS_Float getEmax() const =0
Return the maximum energy of this source.
EGS_Float time_index
time index corresponding to a particle. This stores the current time index for all objects in the sim...
virtual EGS_Float getFluence() const =0
Return the fluence this source has emitted so far.
virtual void resetCounter()
Reset the source state.
string description
A short source description.
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 void addKnownTypeId(const char *name)
Add a known source object typeid to the source factory.
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 vector< EGS_Ensdf * > getRadionuclideEnsdf()
Get the radionuclide ENSDF object from the source.
virtual bool storeState(ostream &data_out) const
Store the source state into the stream data_out.
Base class for energy spectra. All energy spectra in the EGSnrc C++ class library are derived from th...
EGS_Float sampleEnergy(EGS_RandomGenerator *rndm)
Sample a particle energy.
virtual bool setState(istream &data_in)
Set the state of the spectrum object from the data in the stream data_in.
virtual ~EGS_BaseSpectrum()
Destructor. Does nothing.
double sum_E2
Sum of energies squared sampled so far.
void reportAverageEnergy() const
Report the average energy (expected and actually sampled).
virtual EGS_Float maxEnergy() const =0
Get the maximum energy of this spectrum.
string type
A short string describing the spectrum that must be set by derived classes.
virtual bool addState(istream &data_in)
Add to the state of this object the data from the stream data_in.
virtual EGS_Float sample(EGS_RandomGenerator *rndm)=0
Sample an energy from the spectrum energy distribution.
virtual EGS_Float expectedAverage() const =0
Get the average energy of the spectrum.
EGS_BaseSpectrum()
Constructor.
void getSampledAverage(EGS_Float &e, EGS_Float &de) const
Get the average sampled energy and its statistical uncertainty.
EGS_I64 count
Number of times the sampleEnergy() method was called.
virtual bool storeState(ostream &data_out) const
Store the state of the spectrum object into the stream data_out.
double sum_E
Sum of energies sampled so far.
const string & getType() const
Get the spectrum type.
virtual void resetCounter()
Reset the state of this spectrum object.
A class for storing information in a tree-like structure of key-value pairs. This class is used throu...
Definition: egs_input.h:182
An object factory.
Base egspp object.
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_BaseSource * createSourceTemplate(EGS_Input *input, EGS_ObjectFactory *f, const char *name)
A template source creation function.
The ensdf library header file.
Global egspp functions header file.
The input struct header file.
#define EGS_EXPORT
Export symbols from the egspp library.
Definition: egs_libconfig.h:90
Attempts to fix broken math header files.
EGS_Object and EGS_ObjectFactory class header file.
EGS_Vector methods for the manipulation of 3D vectors in cartesian co-ordinates.
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,...
EGS_InfoFunction EGS_EXPORT egsInformation
Always use this function for reporting the progress of a simulation and any other type of information...
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,...
EGS_InfoFunction EGS_EXPORT egsWarning
Always use this function for reporting warnings.