EGSnrc C++ class library  Report PIRS-898 (2021)
Iwan Kawrakow, Ernesto Mainegra-Hing, Frederic Tessier, Reid Townson and Blake Walters
egs_phsp_source.cpp
Go to the documentation of this file.
1 /*
2 ###############################################################################
3 #
4 # EGSnrc egs++ phase-space 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: Ernesto Mainegra-Hing
27 # Frederic Tessier
28 # Reid Townson
29 # Hannah Gallop
30 #
31 ###############################################################################
32 */
33 
34 
40 #include "egs_phsp_source.h"
41 #include "egs_input.h"
42 #include "egs_functions.h"
43 #include "egs_application.h"
44 
45 static bool EGS_PHSP_SOURCE_LOCAL inputSet = false;
46 
47 EGS_PhspSource::EGS_PhspSource(const string &phsp_file,
48  const string &Name, EGS_ObjectFactory *f) : EGS_BaseSource(Name,f) {
49  init();
50  openFile(phsp_file);
51 }
52 
53 void EGS_PhspSource::init() {
54  otype = "EGS_PhspSource";
55  recl = 0;
56  Xmin = -veryFar;
57  Xmax = veryFar;
58  Ymin = -veryFar;
59  Ymax = veryFar;
60  is_valid = false;
61  record = 0;
62  mode2 = false;
63  swap_bytes = false;
64  the_file_name = "no file";
65  filter_type = -1;
66  particle_type = 2;
67  description = "Invalid phase space source";
68  Nread = 0;
69  count = 0;
70  Nrewind = 0;
71  Npos = 0;
72  Nlast = 0;
73  wmin = -veryFar;
74  wmax = veryFar;
75  Nrecycle_g = 0;
76  Nrecycle_e = 0;
77  Nrecycle = 0;
78  Nuse = -1;
79  first = true;
80 }
81 
82 void EGS_PhspSource::openFile(const string &phsp_file) {
83  if (the_file.is_open()) {
84  the_file.close();
85  }
86  the_file_name = "no file";
87  is_valid = false;
88  recl = 0;
89  if (record) {
90  delete [] record;
91  record = 0;
92  }
93  the_file.open(phsp_file.c_str(),ios::binary | ios::in);
94  if (!the_file.is_open()) {
95  egsWarning("EGS_PhspSource::openFile: failed to open binary file %s"
96  " for reading\n",phsp_file.c_str());
97  return;
98  }
99  string cmode;
100  char auxc;
101  for (int i=0; i<5; i++) {
102  the_file.get(auxc);
103  if (the_file.eof() || !the_file.good()) {
104  egsWarning("EGS_PhspSource::openFile: an I/O error occured "
105  "while reading the first record of %s\n",phsp_file.c_str());
106  return;
107  }
108  cmode += auxc;
109  }
110  if (cmode == "MODE0") {
111  mode2 = false;
112  recl = 28;
113  }
114  else if (cmode == "MODE2") {
115  mode2 = true;
116  recl = 32;
117  }
118  else {
119  egsWarning("EGS_PhspSource::openFile: the file %s is not a MODE0 or"
120  " MODE2 file\n",phsp_file.c_str());
121  return;
122  }
123  record = new char [recl];
124  int n, n_photon;
125  float emax, emin, pinc;
126  the_file.read((char *) &n, sizeof(int));
127  the_file.read((char *) &n_photon, sizeof(int));
128  the_file.read((char *) &emax, sizeof(float));
129  the_file.read((char *) &emin, sizeof(float));
130  the_file.read((char *) &pinc, sizeof(float));
131  if (the_file.eof() || !the_file.good()) {
132  egsWarning("EGS_PhspSource::openFile: an I/O error occured "
133  "while reading the first record of %s\n",phsp_file.c_str());
134  recl = 0;
135  return;
136  }
137  swap_bytes = false;
138  if (n <= 0 || n_photon < 0 || n_photon > n || emin < 0 || emax < 0 ||
139  emax < emin || pinc < 0) {
140  swap_bytes = true;
141  egsSwapBytes(&n);
142  egsSwapBytes(&n_photon);
143  egsSwapBytes(&emin);
144  egsSwapBytes(&emax);
145  egsSwapBytes(&pinc);
146  if (n <= 0 || n_photon < 0 || n_photon > n || emin < 0 || emax < 0 ||
147  emax < emin || pinc < 0) {
148  egsWarning("EGS_PhspSource::openFile: phase space file header"
149  " contains meaningless values with and without byte swaping:\n");
150  if (n <= 0) {
151  egsWarning(" number of particles: %d\n",n);
152  }
153  if (n_photon < 0) {
154  egsWarning(" number of photons: %d\n",n_photon);
155  }
156  if (n_photon > n) egsWarning(" number of photons (%d) is "
157  "greater than number of particles (%d)\n",n_photon,n);
158  if (emin < 0) {
159  egsWarning(" minimum energy: %g\n",emin);
160  }
161  if (emax < 0) {
162  egsWarning(" maximum energy: %g\n",emax);
163  }
164  if (emin > emax) {
165  egsWarning(" emin > emax: %g %g\n",emin,emax);
166  }
167  if (pinc < 0) {
168  egsWarning(" incident particles: %g\n",pinc);
169  }
170  recl = 0;
171  return;
172  }
173  }
174  // at this points we have passed a set of checks and think that
175  // we have some meaningful information about number of particles, etc.
176  // to be completely sure, it is a good idea to read the last particle
177  // in the file and check for errors.
178  istream::off_type nend = n;
179  nend = nend*recl;
180  //the_file.seekg(recl*n,ios::beg);
181  the_file.seekg(nend,ios::beg);
182  the_file.read(record,recl*sizeof(char));
183  if (the_file.bad() || the_file.fail()) {
184  egsWarning("EGS_PhspSource::openFile: failed to read the last"
185  " particle in the file, this indicates some unknown error condition\n");
186  recl = 0;
187  return;
188  }
189  the_file.clear();
190  the_file.seekg(recl,ios::beg);
191  Npos = 0;
192  Nlast = n;
193  Nfirst = 1;
194  // at this point the position should be at the first particle in the file
195  Emax = emax;
196  Emin = emin;
197  Pinc = pinc;
198  Nparticle = n;
199  Nphoton = n_photon;
200  is_valid = true;
201  the_file_name = phsp_file;
202 }
203 
205  EGS_BaseSource(input,f) {
206  init();
207  string fname;
208  int err = input->getInput("phase space file",fname);
209  if (err) {
210  egsWarning("EGS_PhspSource: no 'phase space file' input\n");
211  return;
212  }
213  openFile(fname);
214  if (!isValid()) {
215  egsWarning("EGS_PhspSource: errors while opening the phase space file"
216  " %s\n",fname.c_str());
217  return;
218  }
219  vector<EGS_Float> cutout;
220  err = input->getInput("cutout",cutout);
221  if (!err && cutout.size() == 4) {
222  setCutout(cutout[0],cutout[1],cutout[2],cutout[3]);
223  }
224  vector<string> ptype;
225  ptype.push_back("electrons");
226  ptype.push_back("photons");
227  ptype.push_back("positrons");
228  ptype.push_back("all");
229  ptype.push_back("charged");
230  particle_type = input->getInput("particle type",ptype,3)-1;
231  vector<int> the_filter;
232  vector<string> the_latch;
233  err = input->getInput("filter type",the_filter);
234  int err1 = input->getInput("latch setting",the_latch);
235  if (!err && !err1) {
236  if (the_filter[0] >= 0 && the_filter[0] <= 3) {
237  int nbit1 = the_latch[0].size();
238  int nbit2 = 0;
239  if (!the_filter[0]) {
240  nbit2 = the_latch[1].size();
241  }
242  if (nbit1 + nbit2 > 0) {
243  int *the_bits = new int [nbit1+nbit2];
244  for (int j=0; j<nbit1+nbit2; j++) {
245  if (j < nbit1) {
246  the_bits[j]=(int)(the_latch[0][j] == '1');
247  }
248  else {
249  the_bits[j] = (int)(the_latch[1][j-nbit1] == '1');
250  }
251  }
252  setFilter(the_filter[0],nbit1,nbit2,the_bits);
253  delete [] the_bits;
254  }
255  }
256  }
257  vector<EGS_Float> wwindow;
258  err = input->getInput("weight window",wwindow);
259  if (!err && wwindow.size() == 2) {
260  wmin = wwindow[0];
261  wmax = wwindow[1];
262  }
263  int ntmp;
264  err = input->getInput("reuse photons",ntmp);
265  if (!err && ntmp > 0) {
266  Nrecycle_g = ntmp;
267  }
268  else {
269  err = input->getInput("recycle photons",ntmp);
270  if (!err && ntmp > 0) {
271  Nrecycle_g = ntmp;
272  }
273  }
274  err = input->getInput("reuse electrons",ntmp);
275  if (!err && ntmp > 0) {
276  Nrecycle_e = ntmp;
277  }
278  else {
279  err = input->getInput("recycle electrons",ntmp);
280  if (!err && ntmp > 0) {
281  Nrecycle_e = ntmp;
282  }
283  }
284  description = "Phase space source from ";
286 }
287 
288 EGS_I64 EGS_PhspSource::getNextParticle(EGS_RandomGenerator *, int &q,
289  int &latch, EGS_Float &E, EGS_Float &wt, EGS_Vector &x, EGS_Vector &u) {
290  if (!recl) egsFatal("EGS_PhspSource::readParticle(): the file is not "
291  "open yet\n");
292  /*
293  if( Nuse >= Nrecycle ) {
294  do { readParticle(); } while ( rejectParticle() );
295  }
296  */
297  if (Nuse > Nrecycle || Nuse < 0) {
298  readParticle();
299  }
300  x.x = p.x;
301  x.y = p.y;
302  x.z = 0;
303  u.x = p.u;
304  u.y = p.v;
305  EGS_Float aux = p.u*p.u+p.v*p.v;
306  if (aux < 1) {
307  aux = sqrt(1-aux);
308  }
309  else {
310  aux = 0;
311  }
312  if (p.wt > 0) {
313  u.z = aux;
314  wt = p.wt;
315  }
316  else {
317  u.z = -aux;
318  wt = -p.wt;
319  }
320  if (rejectParticle()) {
321  wt = 0;
322  }
323  E = p.E;
324  q = p.q;
325  latch = 0; //latch = p.latch;
326  ++Nuse;
327  return count;
328 }
329 
330 #ifndef SKIP_DOXYGEN
335 union __egs_data32 {
336  int i;
337  float f;
338  char c[4];
339 };
340 #endif
341 
342 void EGS_PhspSource::setSimulationChunk(EGS_I64 nstart, EGS_I64 nrun, int npar, int nchunk) {
343  //determine the simulation chunk and use this to calculate first/last particles
344  //in the phase space chunk
345  EGS_I64 particlesPerChunk = Nparticle/(npar*nchunk);
346  int ichunk = nstart/nrun;
347  if (ichunk > npar*nchunk-1) {
348  //remainder of histories, reuse the last chunk of the phsp
349  //there may be a more clever strategy
350  egsWarning("EGS_PhspSource: Remainder of histories will reuse the last chunk of the phase space source.\n");
351  ichunk = npar*nchunk-1;
352  }
353  Nfirst = ichunk*particlesPerChunk+1;
354  if (ichunk == npar*nchunk-1) {
355  //last chunk of the phsp file, just go to the end of the file
356  Nlast = Nparticle;
357  }
358  else {
359  Nlast = Nfirst-1+particlesPerChunk;
360  }
361  Npos = Nfirst-1; //we increment Npos before attempting to read a particle
362  istream::off_type pos = Nfirst*recl;
363  the_file.seekg(pos,ios::beg);
364  egsInformation("EGS_PhspSource: using phsp portion between %lld and %lld\n",
365  Nfirst,Nlast);
366 }
367 
368 void EGS_PhspSource::readParticle() {
369  if ((++Npos) > Nlast) {
370  egsWarning("EGS_PhspSource::readParticle(): reached the end of the "
371  "phase space file chunk (%lld)\n will start from the beginning "
372  "of the chunk (%lld) but this "
373  "implies that uncertainty estimates will be inaccurate\n",
374  Nlast,Nfirst);
375  istream::off_type pos = Nfirst*recl;
376  the_file.seekg(pos,ios::beg);
377  Nrewind++;
378  Npos = Nfirst;
379  }
380  the_file.read(record,recl*sizeof(char));
381  ++Nread;
382  if (the_file.eof() || !the_file.good())
383  egsFatal("EGS_PhspSource::readParticle(): I/O error while reading "
384  "phase space file\n");
385  __egs_data32 *data;
386  data = (__egs_data32 *) &record[0];
387  p.latch = data->i;
388  data = (__egs_data32 *) &record[4];
389  p.E = data->f;
390  data = (__egs_data32 *) &record[8];
391  p.x = data->f;
392  data = (__egs_data32 *) &record[12];
393  p.y = data->f;
394  data = (__egs_data32 *) &record[16];
395  p.u = data->f;
396  data = (__egs_data32 *) &record[20];
397  p.v = data->f;
398  data = (__egs_data32 *) &record[24];
399  p.wt = data->f;
400  if (swap_bytes) {
401  egsSwapBytes(&p.latch);
402  egsSwapBytes(&p.E);
403  egsSwapBytes(&p.wt);
404  egsSwapBytes(&p.x);
405  egsSwapBytes(&p.y);
406  egsSwapBytes(&p.u);
407  egsSwapBytes(&p.v);
408  }
409  if (p.latch & 1073741824) {
410  p.q = -1;
411  }
412  else if (p.latch & 536870912) {
413  p.q = 1;
414  }
415  else {
416  p.q = 0;
417  }
418  if (p.E < 0) {
419  count++;
420  p.E = -p.E;
421  }
422  else if (first) {
423  ++count;
424  }
425  first = false;
426  if (p.q) {
427  p.E -= EGS_Application::activeApplication()->getRM();
429  }
430  else {
432  }
433  Nuse = 0;
434  p.wt /= (Nrecycle+1);
435 }
436 
437 bool EGS_PhspSource::rejectParticle() const {
438  if (particle_type < 2 && p.q != particle_type) {
439  return true;
440  }
441  if (particle_type == 3 && !p.q) {
442  return true;
443  }
444  if (p.x < Xmin || p.x > Xmax || p.y < Ymin || p.y > Ymax) {
445  return true;
446  }
447  if (p.wt < wmin || p.wt > wmax) {
448  return true;
449  }
450  if (p.latch & 2147483648UL) {
451  return true;
452  }
453  if (filter_type < 0) {
454  return false;
455  }
456  if (filter_type == 0) {
457  bool r1;
458  if (filter1) {
459  r1 = !(p.latch & filter1);
460  }
461  else {
462  r1 = false;
463  }
464  bool r2 = (p.latch & filter2);
465  return (r1 || r2);
466  }
467  if (filter_type == 1) {
468  return (p.latch & filter1);
469  }
470  int l = p.latch >> 24;
471  bool res = l & filter1;
472  return filter_type == 3 ? res : !res;
473 }
474 
475 void EGS_PhspSource::setFilter(int type, int nbit1, int nbit2, const int *bits) {
476  if (type < 0 || type > 3) {
477  egsWarning("EGS_PhspSource::setFilter: invalid filter type %d\n",type);
478  return;
479  }
480  int ntot = nbit1;
481  if (type == 0) {
482  ntot += nbit2;
483  }
484  if (ntot > 29) {
485  egsWarning("EGS_PhspSource::setFilter: maximum number of bits is "
486  "limited to 29, you requested %d\n",ntot);
487  return;
488  }
489  if (!ntot) {
490  return;
491  }
492  filter_type = type;
493  if (filter_type == 0) {
494  int i;
495  filter1 = 0;
496  filter2 = 0;
497  for (i=0; i<ntot; i++) {
498  if (bits[i]) {
499  unsigned int aux = 1;
500  aux = (aux << i);
501  if (i < nbit1) {
502  filter1 += aux;
503  }
504  else {
505  filter2 += aux;
506  }
507  }
508  }
509  }
510  else if (filter_type == 1) { // TODO
511  }
512  else if (filter_type == 2) { // TODO
513  }
514  else if (filter_type == 3) { // TODO
515  }
516 }
517 
518 extern "C" {
519 
520  static void setInputs() {
521  inputSet = true;
522 
523  setBaseSourceInputs(false, false);
524 
525  srcBlockInput->getSingleInput("library")->setValues({"egs_phsp_source"});
526 
527  // Format: name, isRequired, description, vector string of allowed values
528  srcBlockInput->addSingleInput("phase space file", true, "The name of the phase-space file.");
529  srcBlockInput->addSingleInput("particle type", true, "The type of particle to keep from the phase-space. Other types are discarded.", {"all", "charged", "electrons", "positrons", "photons"});
530  srcBlockInput->addSingleInput("cutout", false, "Discard particles outside of a rectanglular field: 'x1 y1 x2 y2'");
531  srcBlockInput->addSingleInput("weight window", false, "A weight window, outside of which particles are discarded: 'wtmin wtmax'. This allows you to discard high weight particles.");
532  srcBlockInput->addSingleInput("recycle photons", false, "The number of time to recycle each photon. E.g. set to 1 to use each photon twice. Set <1 or neglect to disable.");
533  srcBlockInput->addSingleInput("recycle electrons", false, "The number of time to recycle each electron. E.g. set to 1 to use each electron twice. Set <1 or neglect to disable.");
534  }
535 
536  EGS_PHSP_SOURCE_EXPORT string getExample() {
537  string example;
538  example = {
539  R"(
540  # Example of egs_phsp_soure
541  #:start source:
542  name = my_source
543  library = egs_phsp_source
544  phase space file = ../BEAM_EX16MVp/EX16MVp.egsphsp1
545  particle type = all
546  cutout = -1 1 -2 2
547  recycle photons = 10
548  recycle electrons = 10
549  :stop source:
550 )"};
551  return example;
552  }
553 
554  EGS_PHSP_SOURCE_EXPORT shared_ptr<EGS_BlockInput> getInputs() {
555  if(!inputSet) {
556  setInputs();
557  }
558  return srcBlockInput;
559  }
560 
561  EGS_PHSP_SOURCE_EXPORT EGS_BaseSource *createSource(EGS_Input *input,
562  EGS_ObjectFactory *f) {
563  return
564  createSourceTemplate<EGS_PhspSource>(input,f,"phsp source");
565  }
566 
567 }
static EGS_Application * activeApplication()
Get the active application.
Base source class. All particle sources must be derived from this class.
string description
A short source description.
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
An object factory.
string otype
The object type.
int Nrecycle_g
Number of times to recycle a photon.
int Nrecycle
Number of times to recycle current particle.
EGS_Float Emin
Minimum energy (obtained from the phsp file)
EGS_I64 Nfirst
first record this source can use
string the_file_name
The phase-space file name.
EGS_I64 Nparticle
Number of particles in the file.
int Nrecycle_e
Number of times to recycle a charged particle.
EGS_Float Emax
Maximum energy (obtained from the phsp file)
EGS_PhspSource(const string &phsp_file, const string &Name="", EGS_ObjectFactory *f=0)
Constructor.
int recl
The particle record length.
int Nrewind
Number of times the phsp file was rewinded.
EGS_I64 Nlast
Last record this source can use.
EGS_I64 Npos
Next record to be read.
ifstream the_file
Phase space data stream.
int Nuse
Number of times current particle was used so far.
char * record
Memory to read a particle into.
EGS_I64 Nread
Number of particles read so far.
EGS_I64 Nphoton
Number of photons in the file.
bool mode2
true, if a MODE2 file
EGS_Float Pinc
Number of incident particles that created the file.
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_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.
Global egspp functions header file.
EGS_Input class header file.
A phase-space file source.
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.
void egsSwapBytes(int *n)
Swap the bytes of 32 bit integers.
EGS_InfoFunction EGS_EXPORT egsWarning
Always use this function for reporting warnings.
const EGS_Float veryFar
A very large float.