EGSnrc C++ class library  Report PIRS-898 (2021)
Iwan Kawrakow, Ernesto Mainegra-Hing, Frederic Tessier, Reid Townson and Blake Walters
iaea_phsp_source.cpp
Go to the documentation of this file.
1 /*
2 ###############################################################################
3 #
4 # EGSnrc egs++ IAEA format 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: Blake Walters, 2013
25 #
26 # Contributors: Reid Townson
27 # Hubert Ho
28 # Alexandre Demelo
29 #
30 ###############################################################################
31 */
32 
33 
39 #include "iaea_phsp.h"
40 #include "iaea_phsp_source.h"
41 #include "egs_input.h"
42 #include "egs_functions.h"
43 
44 static bool IAEA_PHSP_SOURCE_LOCAL inputSet = false;
45 
46 IAEA_PhspSource::IAEA_PhspSource(const string &phsp_file,
47  const string &Name, EGS_ObjectFactory *f) : EGS_BaseSource(Name,f) {
48  init();
49  openFile(phsp_file);
50 }
51 
52 void IAEA_PhspSource::init() {
53  otype = "IAEA_PhspSource";
54  Xmin = -veryFar;
55  Xmax = veryFar;
56  Ymin = -veryFar;
57  Ymax = veryFar;
58  is_valid = false;
59  mode2 = false;
60  swap_bytes = false;
61  the_file_name = "no file";
62  filter_type = -1;
63  particle_type = 2;
64  description = "Invalid IAEA phase space source";
65  Nread = 0;
66  count = 0;
67  Nrewind = 0;
68  Npos = 0;
69  Nlast = 0;
70  wmin = -veryFar;
71  wmax = veryFar;
72  Nrecycle_g = 0;
73  Nrecycle_e = 0;
74  Nrecycle = 0;
75  Nuse = -1;
76  first = true;
77 }
78 
79 void IAEA_PhspSource::openFile(const string &phsp_file) {
80  the_file_name = "no file";
81  is_valid = false;
82  int rwmode=1; //read only
83  iaea_fileid=0; //this is just an array index for the iaea routines, not an actual
84  //unit no., as in Fortran, so it can really be any integer value
85  //not above MAX_NUM_SOURCES (30)
86 
87  //below is required because iaea opening routine gets file name as char array
88  int len = phsp_file.length();
89  char phsp_name_tmp[len+1];
90  phsp_file.copy(phsp_name_tmp,len,0);
91  //now put a null character on the end
92  phsp_name_tmp[len]='\0';
93 
94  //use iaea function for opening phase space file
95  iaea_new_source(&iaea_fileid,phsp_name_tmp,&rwmode,&iaea_iostat,len);
96  if (iaea_iostat==105) {
97  egsWarning("IAEA_PhspSource::openFile: no header file name supplied.\n");
98  return;
99  }
100  else if (iaea_iostat==-96) {
101  egsWarning("IAEA_PhspSource::openFile: failed to open header file %s.IAEAheader\n"
102  " for reading\n",phsp_file.c_str());
103  return;
104  }
105  else if (iaea_iostat==-94) {
106  egsWarning("IAEA_PhspSource::openFile: failed to open phase space file %s.IAEAphsp\n"
107  " for reading\n",phsp_file.c_str());
108  return;
109  }
110  else if (iaea_iostat==-1) {
111  egsWarning("IAEA_PhspSource::openFile: failed to initialize phase space source %s\n",phsp_file.c_str());
112  return;
113  }
114  else if (iaea_iostat==-91) {
115  egsWarning("IAEA_PhspSource::openFile: failed to get record contents from header file %s.IAEAheader\n",phsp_file.c_str());
116  return;
117  }
118  else if (iaea_iostat <0) {
119  egsWarning("IAEA_PhspSource::openFile: I/O error ocurred on opening phase space file %s\n",phsp_file.c_str());
120  return;
121  }
122 
123  //now check file size and byte order
124 
125  swap_bytes = false;
126  iaea_check_file_size_byte_order(&iaea_fileid,&iaea_iostat);
127  if (iaea_iostat==-1) {
128  egsWarning("IAEA_PhspSource::openFile: error reading file size/byte order from header %s.IAEAheader\n",phsp_file.c_str());
129  return;
130  }
131  else if (iaea_iostat==-4) {
132  egsWarning("IAEA_PhspSource::openFile: byte mismatch between phase space file and machine. Will swap bytes.\n");
133  swap_bytes = true;
134  }
135  else if (iaea_iostat==-3 || iaea_iostat==-5) {
136  egsWarning("IAEA_PhspSource::openFile: mismatch between file size in header and actual file size of %s\n",phsp_file.c_str());
137  return;
138  }
139 
140  //now get some info from the header
141  EGS_I64 n, n_photon, pinc;
142  float emax;
143  int iaea_type=-1; //for getting no. of particles
144  iaea_get_max_particles(&iaea_fileid,&iaea_type,&n);
145  if (n<0) {
146  egsWarning("IAEA_PhspSource::openFile: failed to get total no. of particles from %s.IAEAheader\n",phsp_file.c_str());
147  return;
148  }
149  iaea_type=1; //for getting no. of photons
150  iaea_get_max_particles(&iaea_fileid,&iaea_type,&n_photon);
151  if (n_photon<0) {
152  egsWarning("IAEA_PhspSource::openFile: failed to get no. of photons from %s.IAEAheader\n",phsp_file.c_str());
153  return;
154  }
155  //now get max. energy
156  iaea_get_maximum_energy(&iaea_fileid,&emax);
157  if (emax<0) {
158  egsWarning("IAEA_PhspSource::openFile: failed to get max. energy from %s.IAEAheader\n",phsp_file.c_str());
159  return;
160  }
161  //no. of particles incident from original source
162  iaea_get_total_original_particles(&iaea_fileid,&pinc);
163  if (pinc<0) {
164  egsWarning("IAEA_PhspSource::openFile: failed to get no. of original particles from %s.IAEAheader\n",phsp_file.c_str());
165  return;
166  }
167 
168  //get number of extra float and extra long variables so we can set array dimensions
169  iaea_get_extra_numbers(&iaea_fileid,&n_extra_floats,&n_extra_longs);
170  if (n_extra_floats==-1 || n_extra_longs==-1) {
171  egsWarning("IAEA_PhspSource::openFile: failed to get no. of extra floats and longs stored in %s.IAEAphsp\n",phsp_file.c_str());
172  return;
173  }
174  //determine if Zlast is stored in the file and, if so, its array index, i_zlast
175  int extrafloat_types[MAXEXTRAS], extralong_types[MAXEXTRAS];
176  iaea_get_type_extra_variables(&iaea_fileid,&iaea_iostat,extralong_types,extrafloat_types);
177  if (iaea_iostat==-1) {
178  egsWarning("IAEA_PhspSource::openFile: failed to get Mode of data %s.IAEAheader\n",phsp_file.c_str());
179  return;
180  }
181  mode2=false;
182  i_zlast = -1;
183  for (int i=0; i< n_extra_floats; i++) {
184  if (extrafloat_types[i]==3) {
185  mode2=true;
186  i_zlast=i;
187  break;
188  }
189  }
190  //now see if time index is stored in the file
191  //assume it is the first variable stored in extra_float
192  //after zlast
193  i_time=-1;
194  time_stored=false;
195  if (n_extra_floats > i_zlast+1) {
196  if (extrafloat_types[i_zlast+1] == 0) {
197  i_time=i_zlast+1;
198  time_stored=true;
199  egsInformation("IAEA_PhspSource::openFile: Time index included in data in %s.IAEAphsp\n",phsp_file.c_str());
200  }
201  }
202 
203  //determine array index of latch
204  latch_stored=false;
205  for (int i=0; i< n_extra_longs; i++) {
206  if (extralong_types[i]==2) {
207  latch_stored=true;
208  i_latch=i;
209  break;
210  }
211  }
212  if (!latch_stored) {
213  egsWarning("IAEA_PhspSource::openFile: LATCH is not stored in data in %s.IAEAphsp\n",phsp_file.c_str());
214  }
215 
216  Npos = 0;
217  Nlast = n;
218  Nfirst = 1;
219  // at this point the position should be at the first particle in the file
220  Emax = emax;
221  Pinc = pinc;
222  Nparticle = n;
223  Nphoton = n_photon;
224  is_valid = true;
225  the_file_name = phsp_file;
226 }
227 
229  EGS_BaseSource(input,f) {
230  init();
231  string fname;
232  int err = input->getInput("iaea phase space file",fname);
233  if (err) {
234  egsWarning("IAEA_PhspSource: no 'iaea phase space file' input\n");
235  return;
236  }
237  openFile(fname);
238  if (!isValid()) {
239  egsWarning("IAEA_PhspSource: errors while opening the phase space file"
240  " %s\n",fname.c_str());
241  return;
242  }
243  vector<EGS_Float> cutout;
244  err = input->getInput("cutout",cutout);
245  if (!err && cutout.size() == 4) {
246  setCutout(cutout[0],cutout[1],cutout[2],cutout[3]);
247  }
248  vector<string> ptype;
249  ptype.push_back("electrons");
250  ptype.push_back("photons");
251  ptype.push_back("positrons");
252  ptype.push_back("all");
253  ptype.push_back("charged");
254  particle_type = input->getInput("particle type",ptype,3)-1;
255  vector<int> the_filter;
256  vector<string> the_latch;
257  err = input->getInput("filter type",the_filter);
258  int err1 = input->getInput("latch setting",the_latch);
259  if (!err && !err1) {
260  if (the_filter[0] >= 0 && the_filter[0] <= 3) {
261  int nbit1 = the_latch[0].size();
262  int nbit2 = 0;
263  if (!the_filter[0]) {
264  nbit2 = the_latch[1].size();
265  }
266  if (nbit1 + nbit2 > 0) {
267  int *the_bits = new int [nbit1+nbit2];
268  for (int j=0; j<nbit1+nbit2; j++) {
269  if (j < nbit1) {
270  the_bits[j]=(int)(the_latch[0][j] == '1');
271  }
272  else {
273  the_bits[j] = (int)(the_latch[1][j-nbit1] == '1');
274  }
275  }
276  setFilter(the_filter[0],nbit1,nbit2,the_bits);
277  delete [] the_bits;
278  }
279  }
280  }
281  vector<EGS_Float> wwindow;
282  err = input->getInput("weight window",wwindow);
283  if (!err && wwindow.size() == 2) {
284  wmin = wwindow[0];
285  wmax = wwindow[1];
286  }
287  int ntmp;
288  err = input->getInput("reuse photons",ntmp);
289  if (!err && ntmp > 0) {
290  Nrecycle_g = ntmp;
291  }
292  else {
293  err = input->getInput("recycle photons",ntmp);
294  if (!err && ntmp > 0) {
295  Nrecycle_g = ntmp;
296  }
297  }
298  err = input->getInput("reuse electrons",ntmp);
299  if (!err && ntmp > 0) {
300  Nrecycle_e = ntmp;
301  }
302  else {
303  err = input->getInput("recycle electrons",ntmp);
304  if (!err && ntmp > 0) {
305  Nrecycle_e = ntmp;
306  }
307  }
308  description = "IAEA phase space source from ";
310 }
311 
312 EGS_I64 IAEA_PhspSource::getNextParticle(EGS_RandomGenerator *, int &q,
313  int &latch, EGS_Float &E, EGS_Float &wt, EGS_Vector &x, EGS_Vector &u) {
314  /*
315  if( Nuse >= Nrecycle ) {
316  do { readParticle(); } while ( rejectParticle() );
317  }
318  */
319  int nstat,extrainttemp[MAXEXTRAS];
320  float extrafloattemp[MAXEXTRAS];
321  if (Nuse > Nrecycle || Nuse < 0) { //get a new particle
322  if ((++Npos) > Nlast) {
323  egsWarning("IAEA_PhspSource::getNextParticle(): reached the end of the "
324  "phase space file chunk (%lld)\n will start from the beginning "
325  "of the chunk (%lld) but this "
326  "implies that uncertainty estimates will be inaccurate\n",
327  Nlast,Nfirst);
328  iaea_set_record(&iaea_fileid,&Nfirst,&iaea_iostat);
329  if (iaea_iostat<0) {
330  egsFatal("IAEA_PhspSource::getNextParticle(): error rewinding phase space chunk\n");
331  }
332  Nrewind++;
333  Npos = Nfirst;
334  }
335  iaea_get_particle(&iaea_fileid,&nstat,&p.q,&p.E,&p.wt,&p.x,&p.y,&p.z,&p.u,&p.v,&p.w,extrafloattemp,extrainttemp);
336  ++Nread;
337  p.latch=0; //important if we are using latch to do vr
338  /*
339  if (latch_stored) {
340  p.latch = extrainttemp[i_latch];
341  }
342  */
343  if (mode2) {
344  p.zlast = extrafloattemp[i_zlast];
345  }
346  if (time_stored) {
347  p.time = extrafloattemp[i_time];
348  setTimeIndex(p.time);
349  /* this is setting the time index using the base source set call. We get rid of the local getTimeIndex function and
350  * it should allow for saving time in the base source like all the other sources do */
351  }
352  else {
353  setTimeIndex(-1);
354  }
355  if (swap_bytes) {
356  egsSwapBytes(&p.q);
357  egsSwapBytes(&nstat);
358  egsSwapBytes(&p.zlast);
359  egsSwapBytes(&p.latch);
360  egsSwapBytes(&p.E);
361  egsSwapBytes(&p.wt);
362  egsSwapBytes(&p.x);
363  egsSwapBytes(&p.y);
364  egsSwapBytes(&p.z);
365  egsSwapBytes(&p.u);
366  egsSwapBytes(&p.v);
367  egsSwapBytes(&p.w);
368  egsSwapBytes(&p.time);
369  }
370  //do check here because we need the swapped version of nstat
371  if (nstat<0) {
372  egsFatal("IAEA_PhspSource::getNextParticle(): error reading particle number %i\n",Npos);
373  }
374  //convert charge from iaea type
375  if (p.q==1) {
376  p.q=0;
377  }
378  else if (p.q==2) {
379  p.q=-1;
380  }
381  else if (p.q==3) {
382  p.q=1;
383  }
384  else {
385  egsFatal("IAEA_PhspSource::getNextParticle: unknown charge on particle\n");
386  }
387  //note: we don't have to convert to p.E to K.E. because that's what IAEA format stores
388  if (first || nstat>0) {
389  count++; //increment primary history counter
390  }
391  first= false;
392  //store Nrecycle
393  if (p.q) {
395  }
396  else {
398  }
399  //reset Nuse
400  Nuse = 0;
401  p.wt /= (Nrecycle+1);
402  }
403 
404  //energy, wt, position and direction cosines
405  x.x = p.x;
406  x.y = p.y;
407  x.z = p.z;
408  u.x = p.u;
409  u.y = p.v, u.z = p.w;
410  wt=p.wt;
411  if (rejectParticle()) {
412  wt = 0;
413  }
414  E=p.E;
415  q=p.q;
416  //latch = 0;
417  latch= p.latch;
418  //rejectParticle uses BeamParticle, p
419  ++Nuse;
420  return count;
421 }
422 
423 #ifndef SKIP_DOXYGEN
428 union __egs_data32 {
429  int i;
430  float f;
431  char c[4];
432 };
433 #endif
434 
435 void IAEA_PhspSource::setSimulationChunk(EGS_I64 nstart, EGS_I64 nrun, int npar, int nchunk) {
436  //determine the simulation chunk and use this to calculate first/last particles
437  //in the phase space chunk
438  EGS_I64 particlesPerChunk = Nparticle/(npar*nchunk);
439  int ichunk = nstart/nrun;
440  if (ichunk > npar*nchunk-1) {
441  //remainder of histories, reuse the last chunk of the phsp
442  //there may be a more clever strategy
443  egsInformation("IAEA_PhspSource: Remainder of histories will reuse the last chunk of the phase space source.\n");
444  ichunk = npar*nchunk-1;
445  }
446  Nfirst = ichunk*particlesPerChunk+1;
447  if (ichunk == npar*nchunk-1) {
448  //last chunk of the phsp file, just go to the end of the file
449  Nlast = Nparticle;
450  }
451  else {
452  Nlast = Nfirst-1+particlesPerChunk;
453  }
454  Npos = Nfirst-1;
455  iaea_set_record(&iaea_fileid,&Nfirst,&iaea_iostat);
456  if (iaea_iostat<0) {
457  egsWarning("IAEA_PhspSource::setSimulationChunk(): error setting phase space chunk\n");
458  return;
459  }
460  egsInformation("IAEA_PhspSource: using phsp portion between %lld and %lld\n",
461  Nfirst,Nlast);
462 }
463 
464 bool IAEA_PhspSource::rejectParticle() const {
465  if (particle_type < 2 && p.q != particle_type) {
466  return true;
467  }
468  if (particle_type == 3 && !p.q) {
469  return true;
470  }
471  if (p.x < Xmin || p.x > Xmax || p.y < Ymin || p.y > Ymax) {
472  return true;
473  }
474  if (p.wt < wmin || p.wt > wmax) {
475  return true;
476  }
477  if (p.latch & 2147483648UL) {
478  return true;
479  }
480  if (filter_type < 0) {
481  return false;
482  }
483  if (filter_type == 1) {
484  bool r1;
485  if (filter1) {
486  r1 = !(p.latch & filter1);
487  }
488  else {
489  r1 = false;
490  }
491  bool r2 = (p.latch & filter2);
492  return (r1 || r2);
493  }
494  if (filter_type == 1) {
495  return (p.latch & filter1);
496  }
497  int l = p.latch >> 24;
498  bool res = l & filter1;
499  return filter_type == 3 ? res : !res;
500 }
501 
502 void IAEA_PhspSource::setFilter(int type, int nbit1, int nbit2, const int *bits) {
503  if (type < 0 || type > 3) {
504  egsWarning("IAEA_PhspSource::setFilter: invalid filter type %d\n",type);
505  return;
506  }
507  int ntot = nbit1;
508  if (type == 0) {
509  ntot += nbit2;
510  }
511  if (ntot > 29) {
512  egsWarning("IAEA_PhspSource::setFilter: maximum number of bits is "
513  "limited to 29, you requested %d\n",ntot);
514  return;
515  }
516  if (!ntot) {
517  return;
518  }
519  filter_type = type;
520  if (filter_type == 0) {
521  int i;
522  filter1 = 0;
523  filter2 = 0;
524  for (i=0; i<ntot; i++) {
525  if (bits[i]) {
526  unsigned int aux = 1;
527  aux = (aux << i);
528  if (i < nbit1) {
529  filter1 += aux;
530  }
531  else {
532  filter2 += aux;
533  }
534  }
535  }
536  }
537  else if (filter_type == 1) { // TODO
538  }
539  else if (filter_type == 2) { // TODO
540  }
541  else if (filter_type == 3) { // TODO
542  }
543 }
544 
550 void IAEA_PhspSource::containsDynamic(bool &hasdynamic) {
551  hasdynamic = time_stored;
552 }
553 
554 extern "C" {
555 
556  static void setInputs() {
557  inputSet = true;
558 
559  setBaseSourceInputs(false, false);
560 
561  srcBlockInput->getSingleInput("library")->setValues({"iaea_phsp_source"});
562 
563  // Format: name, isRequired, description, vector string of allowed values
564  srcBlockInput->addSingleInput("iaea phase space file", true, "The path to and name of the phase-space file, no extension. Both the .IAEAphsp and .IAEAheader file must be in the same directory.");
565  srcBlockInput->addSingleInput("particle type", true, "The type of particle to keep from the phase-space. Other types are discarded.", {"all", "charged", "electrons", "positrons", "photons"});
566  srcBlockInput->addSingleInput("cutout", false, "Discard particles outside of a rectanglular field: 'x1 y1 x2 y2'");
567  srcBlockInput->addSingleInput("weight window", false, "A weight window, outside of which particles are discarded: 'wtmin wtmax'. This allows you to discard high weight particles.");
568  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.");
569  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.");
570  }
571 
572  IAEA_PHSP_SOURCE_EXPORT string getExample() {
573  string example;
574  example = {
575  R"(
576  # Example of iaea_phsp_soure
577  #:start source:
578  name = my_source
579  library = iaea_phsp_source
580  iaea phase space file = myPhsp # No extension, both .IAEAphsp and .IAEAheader must be present
581  particle type = all
582  cutout = -1 1 -2 2
583  recycle photons = 10
584  recycle electrons = 10
585  :stop source:
586 )"};
587  return example;
588  }
589 
590  IAEA_PHSP_SOURCE_EXPORT shared_ptr<EGS_BlockInput> getInputs() {
591  if(!inputSet) {
592  setInputs();
593  }
594  return srcBlockInput;
595  }
596 
597  IAEA_PHSP_SOURCE_EXPORT EGS_BaseSource *createSource(EGS_Input *input,
598  EGS_ObjectFactory *f) {
599  return
600  createSourceTemplate<IAEA_PhspSource>(input,f,"iaea phsp source");
601  }
602 
603 }
604 
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.
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_I64 Npos
Next record to be read.
int Nrecycle_g
Number of times to recycle a photon.
string the_file_name
The phase-space file name.
EGS_I64 Nlast
Last record this source can use.
EGS_I64 Nphoton
Number of photons in the file.
int i_latch
index of latch in extra_floats array
int Nuse
Number of times current particle was used so far.
EGS_I64 Nread
Number of particles read so far.
EGS_I64 Nfirst
first record this source can use
int Nrecycle
Number of times to recycle current particle.
bool time_stored
true if time index stored
int iaea_fileid
phsp file unit no.
int n_extra_floats
no. of extra floats stored in phsp file
int i_zlast
index of zlast in extra_floats array
int i_time
index of time index in extra_floats array
int Nrewind
Number of times the phsp file was rewinded.
EGS_Float Pinc
Number of incident particles that created the file.
EGS_I64 Nparticle
Number of particles in the file.
bool mode2
true, if a MODE2 file (i.e. storing Zlast)
int n_extra_longs
no. of extra longs stored in phsp file
IAEA_PhspSource(const string &phsp_file, const string &Name="", EGS_ObjectFactory *f=0)
Constructor.
int Nrecycle_e
Number of times to recycle a charged particle.
bool latch_stored
true if LATCH is stored in data
EGS_Float Emax
Maximum k.e. (obtained from the phsp file)
int iaea_iostat
iostat on read/write of iaea phsp file
void containsDynamic(bool &hasdynamic)
Check if the simulation source contains time indices.
Global egspp functions header file.
EGS_Input 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...
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.
An IAEA format phase-space file source.