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