EGSnrc C++ class library  Report PIRS-898 (2021)
Iwan Kawrakow, Ernesto Mainegra-Hing, Frederic Tessier, Reid Townson and Blake Walters
egs_radionuclide_source.cpp
Go to the documentation of this file.
1 /*
2 ###############################################################################
3 #
4 # EGSnrc egs++ radionuclide 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: Reid Townson, 2016
25 #
26 # Contributors: Martin Martinov
27 #
28 ###############################################################################
29 */
30 
31 
38 #include "egs_input.h"
39 #include "egs_math.h"
40 #include "egs_application.h"
41 
43  EGS_ObjectFactory *f) : EGS_BaseSource(input,f),
44  baseSource(0), q_allowed(0), decays(0), activity(1), sCount(0) {
45 
46  int err;
47  vector<int> tmp_q;
48  err = input->getInput("charge", tmp_q);
49  if (!err) {
50  if (std::find(q_allowed.begin(), q_allowed.end(), -1) != q_allowed.end()
51  && std::find(q_allowed.begin(), q_allowed.end(), 0) != q_allowed.end()
52  && std::find(q_allowed.begin(), q_allowed.end(), 1) != q_allowed.end()
53  && std::find(q_allowed.begin(), q_allowed.end(), 2) != q_allowed.end()
54  ) {
55  q_allowAll = true;
56  }
57  else {
58  q_allowAll = false;
59  }
60  q_allowed = tmp_q;
61  }
62  else {
63  q_allowAll = true;
64  q_allowed.push_back(-1);
65  q_allowed.push_back(1);
66  q_allowed.push_back(0);
67  q_allowed.push_back(2);
68  }
69 
70  // Create the decay spectra
71  count = 0;
72  sCount = 0;
73  Emax = 0;
74  unsigned int i = 0;
75  EGS_Float spectrumWeightTotal = 0;
76  disintegrationOccurred = true;
77  ishower = -1;
78  time = 0;
79  lastDisintTime = 0;
80  while (input->getInputItem("spectrum")) {
81 
82  egsInformation("**********************************************\n");
83 
84  decays.push_back(static_cast<EGS_RadionuclideSpectrum *>(EGS_BaseSpectrum::createSpectrum(input)));
85 
86  // If spectrum creation failed skip to the next spectrum block
87  // We check the getShowerIndex function to ensure this cast to a
88  // radionuclide spectrum succeeded. Other spectra will fail!
89  if (!decays[i] || decays[i]->getShowerIndex() != -1) {
90  decays.pop_back();
91  continue;
92  }
93 
94  EGS_Float spectrumMaxE = decays[i]->maxEnergy();
95  if (spectrumMaxE > Emax) {
96  Emax = spectrumMaxE;
97  }
98 
99  spectrumWeightTotal += decays[i]->getSpectrumWeight();
100 
101  ++i;
102  }
103  if (decays.size() < 1) {
104  egsFatal("\nEGS_RadionuclideSource: Error: No spectrum of type EGS_RadionuclideSpectrum was defined.\n");
105  }
106 
107  // Normalize the spectrum weights
108  for (i=0; i<decays.size(); ++i) {
109  decays[i]->setSpectrumWeight(
110  decays[i]->getSpectrumWeight() / spectrumWeightTotal);
111 
112  if (i > 0) {
113  decays[i]->setSpectrumWeight(
114  decays[i]->getSpectrumWeight() +
115  decays[i-1]->getSpectrumWeight());
116  }
117  }
118 
119  // Get the activity
120  EGS_Float tmp_A;
121  err = input->getInput("activity", tmp_A);
122  if (!err) {
123  activity = tmp_A;
124  }
125  else {
126  activity = 1;
127  }
128 
129  egsInformation("EGS_RadionuclideSource: Activity [disintegrations/s]: %e\n",
130  activity);
131 
132  // Get the experiment time
133  // This puts a limit on emission times - particles beyond the
134  // limit are discarded
135  err = input->getInput("experiment time", experimentTime);
136  if (err) {
137  experimentTime = 0.;
138  }
139 
140  if (experimentTime > 0.) {
141  egsInformation("EGS_RadionuclideSource: Experiment time [s]: %e\n",
142  experimentTime);
143  }
144  else {
145  egsInformation("EGS_RadionuclideSource: Experiment time will not limit the simulation.\n");
146  }
147 
148  // Get the active application
150 
151  // Check for deprecated inputs
152  string dummy;
153  err = input->getInput("source type",dummy);
154  int err2 = input->getInput("geometry",dummy);
155  if (!err || !err2) {
156  egsWarning("\nEGS_RadionuclideSource: Warning: Inputs for defining the radionuclide source as an isotropic or collimated source (e.g. 'source type') are deprecated. Please see the documentation - define the type of source separately and then refer to it using the new 'base source' input.\n");
157  }
158 
159 
160  // Import base source
161  err = input->getInput("base source",sName);
162  if (err) {
163  egsFatal("\nEGS_RadionuclideSource: Error: Base source must be defined\n"
164  "using 'base source = some_name'\n");
165  }
166  baseSource = EGS_BaseSource::getSource(sName);
167  if (!baseSource) {
168  egsFatal("\nEGS_RadionuclideSource: Error: no source named %s"
169  " is defined\n",sName.c_str());
170  }
171 
172  // Initialize emission type to signify nothing has happened yet
173  emissionType = 99;
174 
175  // Finish
176  setUp();
177 }
178 
180  &q, int &latch, EGS_Float &E, EGS_Float &wt, EGS_Vector &x, EGS_Vector
181  &u) {
182 
183  unsigned int i = 0;
184  if (decays.size() > 1 && disintegrationOccurred) {
185  // Sample a uniform random number
186  EGS_Float uRand = rndm->getUniform();
187 
188  // Sample which spectrum to use
189  for (i=0; i<decays.size(); ++i) {
190  if (uRand < decays[i]->getSpectrumWeight()) {
191  break;
192  }
193  }
194  }
195 
196  // Check if the emission time is within the experiment time limit
197  if (experimentTime <= 0. || time < experimentTime) {
198  // Keep this particle
199  }
200  else {
201  // If the particle was emitted outside the
202  // experiment time window, just set the energy to zero to discard
203  E = 0;
204  return ++count;
205  }
206 
207  EGS_I64 ishowerOld = decays[i]->getShowerIndex();
208 
209  E = decays[i]->sampleEnergy(rndm);
210 
211  EGS_I64 ishowerNew = decays[i]->getShowerIndex();
212  if (ishowerNew > ishowerOld) {
213  disintegrationOccurred = true;
214  time = lastDisintTime + -log(1.-rndm->getUniform()) / activity * (ishowerNew - ishowerOld);
215 
216  lastDisintTime = time;
217  ishower += (ishowerNew - ishowerOld);
218  }
219  else {
220  disintegrationOccurred = false;
221  // The time returned from the spectrum is just the time
222  // since the last disintegration event, so this is only
223  // non-zero for internal transitions. This is why the
224  // times are added here - each transition occurs only after
225  // the delay of the previous.
226  time += decays[i]->getTime();
227  }
228 
229  q = decays[i]->getCharge();
230  int qTemp(q), latchTemp(latch);
231  EGS_Float ETemp(E);
232  baseSource->getNextParticle(rndm, qTemp, latchTemp, ETemp, wt, x, u);
233  sCount++;
234  latch = 0;
235 
236  if (disintegrationOccurred) {
237  xOfDisintegration = x;
238  }
239  else {
240  x = xOfDisintegration;
241  }
242 
243  // Now that we have the position of the particle, we can
244  // find the region and deposit any sub-threshold contributions locally
245  // This includes edep from relaxations, and alpha particle energy
246  EGS_Float edep = decays[i]->getEdep();
247  if (edep > 0) {
248  app->setEdep(edep);
249  int ireg = app->isWhere(x);
250  app->userScoring(3, ireg);
251  }
252 
253  // Check if the charge is allowed
254  if (q_allowAll || std::find(q_allowed.begin(), q_allowed.end(), q) != q_allowed.end()) {
255  // Keep the particle
256  }
257  else {
258  // Don't transport the particle
259  E = 0;
260  }
261 
262  // If the energy is zero, also set the weight to zero
263  // If you don't do this, electrons will still be given their rest
264  // mass energy in shower()
265  if (E < epsilon) {
266  wt = 0;
267  }
268 
269  return ++count;
270 }
271 
272 void EGS_RadionuclideSource::setUp() {
273  otype = "EGS_RadionuclideSource";
274  if (!isValid()) {
275  description = "Invalid radionuclide source";
276  }
277  else {
278  description = "Radionuclide production in base source ";
279  description += sName;
280 
281  description += " with:";
282  if (std::find(q_allowed.begin(), q_allowed.end(), -1) !=
283  q_allowed.end()) {
284  description += " electrons";
285  }
286  if (std::find(q_allowed.begin(), q_allowed.end(), 0) != q_allowed.end()) {
287  description += " photons";
288  }
289  if (std::find(q_allowed.begin(), q_allowed.end(), 1) != q_allowed.end()) {
290  description += " positrons";
291  }
292  if (std::find(q_allowed.begin(), q_allowed.end(), 1) != q_allowed.end()) {
293  description += " alphas";
294  }
295 
296  description += "\nBase source description:\n";
297  description += baseSource->getSourceDescription();
298  }
299 }
300 
301 bool EGS_RadionuclideSource::storeState(ostream &data_out) const {
302  for (unsigned int i=0; i<decays.size(); ++i) {
303  if (!decays[i]->storeState(data_out)) {
304  return false;
305  }
306  }
307  egsStoreI64(data_out,count);
308  egsStoreI64(data_out,sCount);
309  baseSource->storeState(data_out);
310 
311  return true;
312 }
313 
314 bool EGS_RadionuclideSource::addState(istream &data) {
315  for (unsigned int i=0; i<decays.size(); ++i) {
316  if (!decays[i]->setState(data)) {
317  return false;
318  }
319  ishower += decays[i]->getShowerIndex();
320  }
321  EGS_I64 tmp_val;
322  egsGetI64(data,tmp_val);
323  count += tmp_val;
324  egsGetI64(data,tmp_val);
325  sCount += tmp_val;
326  baseSource->addState(data);
327 
328  return true;
329 }
330 
332  for (unsigned int i=0; i<decays.size(); ++i) {
333  decays[i]->resetCounter();
334  }
335  ishower = 0;
336  count = 0;
337  sCount = 0;
338  baseSource->resetCounter();
339 }
340 
341 bool EGS_RadionuclideSource::setState(istream &data) {
342  for (unsigned int i=0; i<decays.size(); ++i) {
343  if (!decays[i]->setState(data)) {
344  return false;
345  }
346  }
347  egsGetI64(data,count);
348  egsGetI64(data,sCount);
349  baseSource->setState(data);
350 
351  return true;
352 }
353 
354 extern "C" {
355 
356  EGS_RADIONUCLIDE_SOURCE_EXPORT EGS_BaseSource *createSource(EGS_Input
357  *input, EGS_ObjectFactory *f) {
358  return
359  createSourceTemplate<EGS_RadionuclideSource>(input,f,"radionuclide "
360  "source");
361  }
362 
363 }
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, false on failure.
bool addState(istream &data)
Add the source state from the stream data to the current state.
EGS_Input class header file.
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, false on failure.
A class representing 3D vectors.
Definition: egs_vector.h:56
A radionuclide source.
virtual bool addState(istream &data_in)
Add data from the stream data_in to the source state.
bool storeState(ostream &data_out) const
Store the source state to the data stream data_out.
virtual void resetCounter()
Reset the source state.
EGS_RadionuclideSource(EGS_Input *, EGS_ObjectFactory *f=0)
Constructor from input file.
const char * getSourceDescription() const
Get a short description of this source.
static EGS_BaseSpectrum * createSpectrum(EGS_Input *inp)
Create and return a pointer to a spectrum object from the information pointed to by inp...
virtual bool storeState(ostream &data_out) const
Store the source state into the stream data_out.
Base random number generator class. All random number generators should be derived from this class...
Definition: egs_rndm.h:67
EGS_InfoFunction EGS_EXPORT egsFatal
Always use this function for reporting fatal errors.
EGS_Input * getInputItem(const string &key) const
Same as the previous function but now ownership remains with the EGS_Input object.
Definition: egs_input.cpp:245
EGS_I64 getNextParticle(EGS_RandomGenerator *rndm, int &q, int &latch, EGS_Float &E, EGS_Float &wt, EGS_Vector &x, EGS_Vector &u)
Gets the next particle from the radionuclide spectra.
virtual bool setState(istream &data_in)
Set the source state based on data from the stream data_in.
EGS_InfoFunction EGS_EXPORT egsInformation
Always use this function for reporting the progress of a simulation and any other type of information...
An object factory.
bool setState(istream &data)
Set the source state according to the data in the stream data.
static EGS_Application * activeApplication()
Get the active application.
static EGS_BaseSource * getSource(const string &Name)
Get a pointer to the source named Name.
Attempts to fix broken math header files.
EGS_Float getUniform()
Returns a random number uniformly distributed between zero (inclusive) and 1 (exclusive).
Definition: egs_rndm.h:103
const EGS_Float epsilon
The epsilon constant for floating point comparisons.
Definition: egs_functions.h:61
EGS_I64 getShowerIndex() const
Returns the shower index of the most recent particle.
bool isValid() const
Checks the validity of the source.
int userScoring(int iarg, int ir=-1)
User scoring function for accumulation of results and VRT implementation.
A class for storing information in a tree-like structure of key-value pairs. This class is used throu...
Definition: egs_input.h:182
void resetCounter()
Reset the source to a state with zero sampled particles.
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.
string otype
The object type.
EGS_Application class header file.
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:338
Base source class. All particle sources must be derived from this class.
string description
A short source description.
EGS_InfoFunction EGS_EXPORT egsWarning
Always use this function for reporting warnings.