EGSnrc C++ class library  Report PIRS-898 (2021)
Iwan Kawrakow, Ernesto Mainegra-Hing, Frederic Tessier, Reid Townson and Blake Walters
egs_phsp_scoring.cpp
Go to the documentation of this file.
1 /*
2 ###############################################################################
3 #
4 # EGSnrc egs++ phase space scoring object
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, 2018
25 #
26 # Contributors: Reid Townson
27 # Hannah Gallop
28 #
29 ###############################################################################
30 */
31 
32 
38 #include <sstream>
39 #include <fstream>
40 #include <string>
41 #include <cstdlib>
42 
43 #include "egs_phsp_scoring.h"
44 #include "egs_input.h"
45 #include "egs_functions.h"
46 #include "iaea_phsp.h"
47 
48 static bool EGS_PHSP_SCORING_LOCAL inputSet = false;
49 
50 EGS_PhspScoring::EGS_PhspScoring(const string &Name,
51  EGS_ObjectFactory *f) :
52  EGS_AusgabObject(Name,f), phsp_index(0), store_max(1000), phsp_file(),
53  count(0), countg(0), emin(1.e30), emax(-1.e30), first_flush(true), is_resume(false) {
54  otype = "EGS_PhspScoring";
55 }
56 
57 EGS_PhspScoring::~EGS_PhspScoring() {
58 }
59 
60 void EGS_PhspScoring::setApplication(EGS_Application *App) {
62  if (!app) {
63  return;
64  }
65 
66  char buf[512];//useful character buffer
67  //set up the stack of particles to output to the phase space file
68  //1000 particles at a time
69  p_stack = new Particle[store_max];
70 
71  description = "\n*******************************************\n";
72  description += "Phase Space Scoring Object (";
73  description += name;
74  description += ")\n";
75  description += "*******************************************\n";
76  if (score_type==0) {
77  description += "\n Will output phase space for particles crossing surfaces of geometry:\n";
78  description += phsp_geom->getName();
79  description += "\n Particles scored on: ";
80  if (scoredir == 0) {
81  description += "entering and exiting phase space geometry";
82  }
83  else if (scoredir == 1) {
84  description += "entering phase space geometry";
85  }
86  else if (scoredir == 2) {
87  description += "exiting phase space geometry";
88  }
89  }
90  else if (score_type==1) {
91  description += "\n Will output phase space for the following exit/entry region pairs:\n";
92  description += " Exit regions:\n";
93  for (int i=0; i<fromreg.size(); i++) {
94  sprintf(buf,"%d ",fromreg[i]);
95  description += buf;
96  }
97  description += "\n Entry regions:\n";
98  for (int i=0; i<fromreg.size(); i++) {
99  sprintf(buf,"%d ",toreg[i]);
100  description += buf;
101  }
102  description += "\n";
103  //now, for every region, set up a (possibly empty) array of entry regions
104  int nreg = app->getnRegions();
105  for (int ir=0; ir<nreg; ir++) {
106  vector<int> tolist;
107  for (int i=0; i<fromreg.size(); i++) {
108  if (fromreg[i]==ir) {
109  tolist.push_back(toreg[i]);
110  }
111  }
112  from_to.push_back(tolist);
113  }
114  }
115 
116  //construct name of phase space file -- opening to occur later
117  if (phspoutdir == "") {
118  phspoutdir = app->getAppDir();
119  }
120  if (oformat==0) {
121  description += "\n Data will be output in EGSnrc format.\n";
122  if (app->getNparallel()>0) {
123  sprintf(buf,"%s_w%d.egsphsp1",getObjectName().c_str(),app->getIparallel());
124  }
125  else {
126  sprintf(buf,"%s.egsphsp1",getObjectName().c_str());
127  }
128  phsp_fname=egsJoinPath(phspoutdir,buf);
129  description += "\n Phase space file name:\n";
130  description += phsp_fname;
131  }
132  else if (oformat==1) {
133  description += "\n Data will be output in IAEA format.\n";
134  if (app->getNparallel()>0) {
135  sprintf(buf,"%s_w%d.1",getObjectName().c_str(),app->getIparallel());
136  }
137  else {
138  sprintf(buf,"%s.1",getObjectName().c_str());
139  }
140  phsp_fname=egsJoinPath(phspoutdir,buf);
141 
142  //need to add a null terminator
143  len = phsp_fname.length();
144  phsp_fname_char = new char[len+1];
145  phsp_fname.copy(phsp_fname_char,len,0);
146  phsp_fname_char[len]='\0'; //null terminator on string
147 
148  //iaea particle charge
149  iaea_q_type[0]=2; //e-
150  iaea_q_type[1]=1; //photon
151  iaea_q_type[2]=3; //e+
152 
153  iaea_id = 1;
154 
155  //set up extra float and extra long array indices
156  latch_ind = 2;//type of latch as defined by iaea
157  iaea_n_extra_long=1; //only store latch
158  iaea_i_latch=0; // position of latch in array
159  if (score_time) {
160  iaea_n_extra_float=1;
161  time_ind = 0; //set type to generic float
162  iaea_i_time=0; //position of time index in array
163  }
164  else {
165  iaea_n_extra_float=0; //no extra floats
166  }
167 
168  description += "\n Phase space file names:\n";
169  description += " Header file: " + phsp_fname + ".IAEAheader\n";
170  description += " Data file: " + phsp_fname + ".IAEAphsp";
171  string xyzname[3] = {"X", "Y", "Z"};
172  for (int i=0; i<3; i++) {
173  if (xyz_is_const[i]) {
174  ostringstream xyz;
175  xyz << xyzscore[i];
176  description += "\n Data scored at constant " + xyzname[i] + " = " + xyz.str() + " cm";
177  }
178  }
179  }
180  description += "\n Particles scored: ";
181  if (ocharge == 0) {
182  description += "all";
183  }
184  else if (ocharge == 1) {
185  description += "photons";
186  }
187  else if (ocharge == 2) {
188  description += "charged";
189  }
190  if (oformat ==1 && score_time) {
191  description += "\n time index will be scored (if available)";
192  }
193  if (oformat ==0 && score_mc) {
194  description += "\n will score multiple crossers (and descendents)";
195  }
196 }
197 
198 //final buffer flush and then close file
199 //we want to output some data about particles scored
200 //may ultimately want to allow the user to define scoring zones for output
201 void EGS_PhspScoring::reportResults() {
202  flushBuffer();
203  if (oformat == 1) { //iaea
204  int iaea_iostat;
205  iaea_destroy_source(&iaea_id,&iaea_iostat);
206  if (iaea_iostat<0) {
207  egsFatal("\n EGS_PhspScoring: Error closing phase space file.\n");
208  }
209  }
210  else if (oformat == 0) {
211  phsp_file.close();
212  }
213  egsInformation("\n======================================================\n");
214  egsInformation("Phase Space Scoring Object(%s)\n",name.c_str());
215  egsInformation("======================================================\n");
216  if (oformat==1) {
217  egsInformation("\n IAEA format phase space output:\n");
218  egsInformation(" Header file: %s.IAEAheader\n",phsp_fname.c_str());
219  egsInformation(" Data file: %s.IAEAphsp\n",phsp_fname.c_str());
220  }
221  else if (oformat == 0) {
222  egsInformation("\n EGSnrc format phase space output:\n");
223  egsInformation(" Data file: %s\n",phsp_fname.c_str());
224  }
225  float emintmp;
226  if (count == countg) {
227  emintmp = 0.0;
228  }
229  else {
230  emintmp = emin;
231  }
232  egsInformation("Summary of scored data:\n");
233  egsInformation("=> total no. of particles = %lld \n", count);
234  egsInformation("=> no. of photons = %lld \n", countg);
235  egsInformation("=> max. k.e. of all particles = %g MeV\n",emax);
236  egsInformation("=> min. k.e. of charged particles = %g MeV\n",emintmp);
237  egsInformation("=> no. of primary histories represented = %lld\n",last_case);
238  egsInformation("\n======================================================\n");
239 }
240 
241 //store 1000 particles at a time in p_stack
242 //if we're at 1000, actually write the particles to the file and update
243 //the header info
244 //also, keep track of phase space file counters, min., max. energy
245 void EGS_PhspScoring::storeParticle(EGS_I64 ncase) {
246 
247  //if user requested time index scoring, check if time is available
248  if (score_time && app->getTimeIndex() < 0) {
249  egsWarning("\nEGS_PhspScoring: User requested time index scoring, but time is inavailable with this source.\n");
250  egsWarning("Turning off time index scoring.\n");
251  score_time=false;
252  }
253 
254  //counters, min. and max. k.e.
255  EGS_Float prm = app->getRM();
256  count++;
257  if (app->top_p.q==0) {
258  countg++;
259  }
260  double ke = app->top_p.E-abs(app->top_p.q)*prm;
261  if (ke > emax) {
262  emax = ke;
263  }
264  if (app->top_p.q != 0 && app->top_p.E - prm < emin) {
265  emin = app->top_p.E - prm;
266  }
267 
268  // Store kinetic energy for IAEA format phsp, and total energy for egsphsp
269  double E;
270  if (oformat == 0) {
271  E = app->top_p.E;
272  }
273  else if (oformat == 1) {
274  E = ke;
275  }
276 
277  //set -ve energy marker if this is a new primary hist.
278  if (ncase != last_case) {
279  E = -E;
280  last_case = ncase;
281  }
282 
283  //store particle data in p_stack
284  p_stack[phsp_index].E = E;
285  p_stack[phsp_index].wt = app->top_p.wt;
286  p_stack[phsp_index].x = app->top_p.x.x;
287  p_stack[phsp_index].y = app->top_p.x.y;
288  p_stack[phsp_index].z = app->top_p.x.z;
289  p_stack[phsp_index].u = app->top_p.u.x;
290  p_stack[phsp_index].v = app->top_p.u.y;
291  p_stack[phsp_index].w = app->top_p.u.z;
292  p_stack[phsp_index].q = app->top_p.q;
293  if (score_time) {
294  p_stack[phsp_index].time = app->getTimeIndex();
295  }
296  p_stack[phsp_index++].latch = app->top_p.latch;
297 
298  if (phsp_index > store_max - 1) {
299  //write store_max particles to the file and reset phsp_index counter
300  flushBuffer();
301  }
302 }
303 
304 //open the phase space file for writing/appending data
305 void EGS_PhspScoring::openPhspFile() const {
306 //the file has already been named at this point
307  if (oformat==0) { //EGSnrc format
308  if (is_resume) {
309  phsp_file.open(phsp_fname.c_str(),ios::binary|ios::out|ios::in);
310  if (!(phsp_file))
311  egsFatal("\nEGS_PhspScoring: Failed to open phase space file %s for appending.\n",
312  phsp_fname.c_str());
313  //check that total no. of particles in header = total no. read from .egsdat file
314  unsigned int count4;
315  phsp_file.seekg(5,ios::beg);
316  phsp_file.read((char *) &count4, sizeof(unsigned int));
317  if (count4 != countprev) {
318  egsFatal("\nEGS_PhspScoring: Particle no. mismatch between %s and .egsdat file.\n",phsp_fname.c_str());
319  }
320  //go to the end of the file
321  phsp_file.seekp(0,ios::end);
322  if (phsp_file.tellp() != 28 + countprev*sizeof(egs_phsp_write_struct)) {
323  egsFatal("\nEGS_PhspScoring: File size mismatch in %s and .egsdat file.\n",phsp_fname.c_str());
324  }
325  }
326  else {
327  phsp_file.open(phsp_fname.c_str(),ios::binary|ios::out);
328  if (!(phsp_file))
329  egsFatal("\nEGS_PhspScoring: Failed to open phase space file %s for writing.\n",
330  phsp_fname.c_str());
331  //always MODE0 files--i.e. no ZLAST
332  phsp_file.write("MODE0",5);
333  //leave space for/skip over the rest of the header
334  phsp_file.seekp(28,ios::beg);
335  }
336  }
337  else if (oformat == 1) { //IAEA format
338  int iaea_iostat;
339  iaea_id = 1; //numerical index indicating this is the 1st file associated with this object scored
340  //hard coded to 1
341  if (is_resume) {
342  int rwmode = 3;
343  iaea_new_source(&iaea_id,phsp_fname_char,&rwmode,&iaea_iostat,len);
344  if (iaea_iostat < 0) {
345  egsFatal("\nEGS_PhspScoring: Failed to open phase space file %s.IAEAphsp for appending.\n",phsp_fname.c_str());
346  }
347  //check for consistency with total no. of scored particles as read from .egsdat file
348  EGS_I64 nparticle;
349  int type = -1;
350  int iaea_iostat;
351  iaea_get_max_particles(&iaea_id,&type,&nparticle);
352  if (nparticle != countprev) {
353  egsFatal("\nEGS_PhspScoring: Particle no. mismatch between %s.IAEAphsp and .egsdat file.\n",phsp_fname.c_str());
354  }
355  iaea_check_file_size_byte_order(&iaea_id,&iaea_iostat);
356  if (iaea_iostat != 0) {
357  egsFatal("\nEGS_PhspScoring: Byte order/file size mismatch in %s.IAEAphsp.\n",phsp_fname.c_str());
358  }
359  }
360  else {
361  int rwmode = 2;
362  iaea_new_source(&iaea_id,phsp_fname_char,&rwmode,&iaea_iostat,len);
363  if (iaea_iostat < 0) {
364  egsFatal("\nEGS_PhspScoring: Failed to open phase space file %s.IAEAphsp for writing.\n",phsp_fname.c_str());
365  }
366  }
367 
368 
369  //set up constant variables
370  for (int i=0; i<3; i++) {
371  if (xyz_is_const[i]) {
372  int index = i;
373  float constval = xyzscore[i];
374  iaea_set_constant_variable(&iaea_id,&index,&constval);
375  }
376  }
377  //set up extra floats and int indices and types
378  //need to store below in _tmp variables because this is a const function
379  int latch_ind_tmp = latch_ind;
380  int iaea_n_extra_long_tmp=iaea_n_extra_long;
381  int iaea_i_latch_tmp=iaea_i_latch;
382  int time_ind_tmp = time_ind;
383  int iaea_i_time_tmp = iaea_i_time;
384  int iaea_n_extra_float_tmp=iaea_n_extra_float;
385 
386  iaea_set_extra_numbers(&iaea_id,&iaea_n_extra_float_tmp,&iaea_n_extra_long_tmp);
387  iaea_set_type_extralong_variable(&iaea_id,&iaea_i_latch_tmp,&latch_ind_tmp);
388  if (score_time) {
389  iaea_set_type_extrafloat_variable(&iaea_id,&iaea_i_time_tmp,&time_ind_tmp);
390  }
391  }
392 }
393 
394 //write phsp_index particles to phase space file
395 //update header and reset phsp_index
396 int EGS_PhspScoring::flushBuffer() const {
397 
398  if (first_flush) {
399  openPhspFile(); //here's where we open the phase space file
400  }
401  //awkward logic because we do not know if this is a resumed simulation
402  //until after initialization
403  first_flush = false;
404 
405  if (oformat == 1) { //iaea format
406  for (int j=0; j<phsp_index; j++) {
407  //fairly transparent, could probably put a lot of this in a separate method
408  //undo -ve energy marker and use n_stat to indicate new primary hist.
409  int n_stat = p_stack[j].E < 0 ? 1 : 0;
410  float E = abs(p_stack[j].E);
411  //convert charge to iaea type
412  int type = iaea_q_type[p_stack[j].q+1];
413 
414  //store latch in iaea_extra_long
415  EGS_I32 *iaea_extra_long = new EGS_I32[iaea_n_extra_long];
416  iaea_extra_long[iaea_i_latch]=p_stack[j].latch;
417  float *iaea_extra_float = new float[iaea_n_extra_float];
418  if (score_time) {
419  iaea_extra_float[iaea_i_time] = p_stack[j].time;
420  }
421 
422  //now store double precision values in single precision reals
423  float wt = p_stack[j].wt;
424  float x = p_stack[j].x;
425  float y = p_stack[j].y;
426  float z = p_stack[j].z;
427  float u = p_stack[j].u;
428  float v = p_stack[j].v;
429  float w = p_stack[j].w;
430  //now actually write data
431 
432  iaea_write_particle(&iaea_id,&n_stat,&type,&E,&wt,&x,&y,&z,&u,&v,&w,iaea_extra_float,iaea_extra_long);
433  if (n_stat < 0) {
434  egsFatal("\nEGS_PhspScoring: Failed to write particle data to phase space file.");
435  }
436  }
437  //update header with no. of primary histories
438  EGS_I64 last_case_tmp = last_case;
439  iaea_set_total_original_particles(&iaea_id,&last_case_tmp);
440  //update header file
441  int iaea_iostat;
442  iaea_update_header(&iaea_id,&iaea_iostat);
443  if (iaea_iostat<0) {
444  egsFatal("\nEGS_PhspScoring: Failed to update phase space header file.");
445  }
446  }
447  else if (oformat == 0) { //EGSnrc format
448  if (!phsp_file) {
449  egsFatal("\nEGS_PhspScoring: phase space file is not open for writing.");
450  }
451  //don't forget that phsp_index is incremented after every particle written to p_stack
452  for (int j=0; j<phsp_index; j++) {
453  egs_phsp_write_struct ws(p_stack[j]);
454  phsp_file.write((char *) &ws, sizeof(ws));
455  }
456  //store position of end of file
457  iostream::off_type pos = (count+1)*sizeof(egs_phsp_write_struct);
458  //update header
459  phsp_file.seekp(5,ios::beg);
460  unsigned int count4 = count, countg4 = countg;
461  float pinc = last_case;
462  float emintmp;
463  if (countg4==count4) {
464  emintmp = 0.0;
465  }
466  else {
467  emintmp = emin;
468  }
469  phsp_file.write((char *) &count4, sizeof(unsigned int));
470  phsp_file.write((char *) &countg4, sizeof(unsigned int));
471  phsp_file.write((char *) &emax, sizeof(float));
472  phsp_file.write((char *) &emintmp, sizeof(float));
473  phsp_file.write((char *) &pinc, sizeof(float));
474  phsp_file.seekp(pos,ios::beg);
475  }
476 
477  phsp_index=0;
478 
479  return 0;
480 };
481 
482 bool EGS_PhspScoring::storeState(ostream &data) const {
483  if (!egsStoreI64(data,count)) {
484  return false;
485  }
486  if (!egsStoreI64(data,countg)) {
487  return false;
488  }
489  //update phase space file at the end of each batch
490  flushBuffer();
491  return true;
492 }
493 
494 bool EGS_PhspScoring::setState(istream &data) {
495  if (!egsGetI64(data,count)) {
496  return false;
497  }
498  if (!egsGetI64(data,countg)) {
499  return false;
500  }
501  countprev = count;
502  is_resume = true;
503  return true;
504 }
505 
506 bool EGS_PhspScoring::addState(istream &data) {
507  EGS_I64 tmp;
508  if (!egsGetI64(data,tmp)) { //return false;
509  egsWarning("error while reading count\n");
510  return false;
511  }
512  count += tmp;
513  if (!egsGetI64(data,tmp)) { //return false;
514  egsWarning("error while reading countg\n");
515  return false;
516  }
517  countg += tmp;
518  return true;
519 }
520 
521 //*********************************************************************
522 // Process input for this ausgab object
523 //**********************************************************************
524 extern "C" {
525 
526  static void setInputs() {
527  inputSet = true;
528 
529  setBaseAusgabObjectInputs();
530 
531  ausBlockInput->getSingleInput("library")->setValues({"egs_phsp_scoring"});
532 
533  // Format: name, isRequired, description, vector string of allowed values
534  auto formatPtr = ausBlockInput->addSingleInput("output format", false, "The phase-space format to output. Defaults to EGSnrc", {"EGSnrc", "IAEA"});
535 
536  auto xPtr = ausBlockInput->addSingleInput("constant X", false, "X values(cm) at which all particles are scored.");
537  xPtr->addDependency(formatPtr, "IAEA");
538  auto yPtr = ausBlockInput->addSingleInput("constant Y", false, "Y values(cm) at which all particles are scored.");
539  yPtr->addDependency(formatPtr, "IAEA");
540  auto zPtr = ausBlockInput->addSingleInput("constant Z", false, "Z values(cm) at which all particles are scored.");
541  zPtr->addDependency(formatPtr, "IAEA");
542  auto muPtr = ausBlockInput->addSingleInput("score time index", false, "Whether to score the time index for each particle. Only valid for IAEA phase-spaces. Default is no.", {"yes", "no"});
543  muPtr->addDependency(formatPtr, "IAEA");
544 
545  auto multiPtr = ausBlockInput->addSingleInput("score multiple crossers", false, "Whether to score the same particle multiple times, if it happens to cross the phase-space surface more than once. Default is no.", {"yes", "no"});
546  multiPtr->addDependency(formatPtr, "EGSnrc");
547 
548  ausBlockInput->addSingleInput("particle type", true, "The type of particle to score", {"all", "photons", "charged"});
549  ausBlockInput->addSingleInput("output directory", true, "The name of the output directory");
550 
551  // Method 1: Score particles on entry to/exit from a predefined geometry
552  auto spacePtr = ausBlockInput->addSingleInput("phase space geometry", true, "The name of a previously defined geometry");
553  auto scorePtr = ausBlockInput->addSingleInput("score particles on", false, "Which situation to score particles as they cross the geometry boundary. On entry, exit, or entry and exit. Default is entry and exit.", {"entry", "exit", "entry and exit"});
554 
555  // Method 2: Score particles on exiting one region and entering another
556  auto fromPtr = ausBlockInput->addSingleInput("from regions", true, "A list of exit region numbers");
557  auto toPtr = ausBlockInput->addSingleInput("to regions", true, "A list of entry region numbers");
558 
559  // Can only use one method
560  spacePtr->addDependency(fromPtr, "", true);
561  spacePtr->addDependency(toPtr, "", true);
562  scorePtr->addDependency(fromPtr, "", true);
563  scorePtr->addDependency(toPtr, "", true);
564  fromPtr->addDependency(spacePtr, "", true);
565  fromPtr->addDependency(scorePtr, "", true);
566  toPtr->addDependency(spacePtr, "", true);
567  toPtr->addDependency(scorePtr, "", true);
568  }
569 
570  EGS_PHSP_SCORING_EXPORT string getExample() {
571  string example;
572  example = {
573  R"(
574  # Example of egs_phsp_scoring
575  #:start ausgab object:
576  library = egs_phsp_scoring
577  name = test
578  from regions = 0 2
579  to regions = 3 5
580  output format = IAEA
581  constant Z = 10.0
582  particle type = all
583  score time index = no
584  :stop ausgab object:
585 
586  #:start ausgab object:
587  library = egs_phsp_scoring
588  name = test2
589  phase space geometry = scoreplane
590  output format = EGSnrc
591  particle type = all
592  score particles on = entry
593  score multiple crossers = yes
594  :stop ausgab object:
595 )"};
596  return example;
597  }
598 
599  EGS_PHSP_SCORING_EXPORT shared_ptr<EGS_BlockInput> getInputs() {
600  if(!inputSet) {
601  setInputs();
602  }
603  return ausBlockInput;
604  }
605 
606  EGS_PHSP_SCORING_EXPORT EGS_AusgabObject *createAusgabObject(EGS_Input *input,
607  EGS_ObjectFactory *f) {
608  const static char *func = "createAusgabObject(phsp_scoring)";
609  if (!input) {
610  egsWarning("%s: null input?\n",func);
611  return 0;
612  }
613  string str;
614  EGS_BaseGeometry *phspgeom;
615  int iscoremc = 0; //default to not score multiple crossers
616  vector <int> from_reg, to_reg;
617  int stype = 0; //default is to use scoring geom
618  int phspouttype;
619  int ptype;
620  int sdir=0;
621  int itimescore = 0;
622  float xyzconst[3];
623  bool xyzisconst[3] = {false, false, false};
624  string gname;
625  string outdir;
626  int err01 = input->getInput("phase space geometry",gname);
627  if (err01) {
628  stype = 1;
629  }
630  else {
631  phspgeom = EGS_BaseGeometry::getGeometry(gname);
632  if (!phspgeom) {
633  egsWarning("\nEGS_PhspScoring: %s does not name an existing geometry.\n"
634  "Will assume you want to use exit/entry region pairs.\n",gname.c_str());
635  stype = 1;
636  }
637  else {
638  if (input->getInput("score particles on", str) < 0) {
639  egsInformation("EGS_PhspScoring: No input for scoring direction.\n");
640  egsInformation("Will score on entry and exit from phase space geometry.\n");
641  sdir = 0;
642  }
643  else {
644  //get scoring direction
645  vector<string> allowed_sdir;
646  allowed_sdir.push_back("entry and exit");
647  allowed_sdir.push_back("entry");
648  allowed_sdir.push_back("exit");
649  sdir = input->getInput("score particles on",allowed_sdir,-1);
650  if (sdir < 0) {
651  egsFatal("\nEGS_PhspScoring: Invalid scoring direction.\n");
652  }
653  }
654  }
655  }
656  if (stype==1) {
657  // user wants to use exit/entry region pairs
658  int err05 = input->getInput("from regions",from_reg);
659  int err06 = input->getInput("to regions",to_reg);
660  if (err05 || err06) {
661  egsFatal("\nEGS_PhspScoring: Missing/incorrect input for scoring method\n"
662  "(scoring geometry or pairs of exit/entry regions)\n");
663  }
664  else {
665  //run some checks on exit/entry region pairs
666  vector<int>::iterator p,p1;
667  if (from_reg.size() > to_reg.size()) {
668  p = from_reg.begin();
669  egsWarning("\nEGS_PhspScoring: Mismatch in no. of exit/entry regions.\n"
670  "Will only score for matched pairs.\n");
671  p += to_reg.size();
672  from_reg.erase(p,p+from_reg.size()-to_reg.size());
673  }
674  else if (to_reg.size() > from_reg.size()) {
675  p = to_reg.begin();
676  egsWarning("\nEGS_PhspScoring: Mismatch in no. of exit/entry regions.\n"
677  "Will only score for matched pairs.\n");
678  p += from_reg.size();
679  to_reg.erase(p,p+to_reg.size()-from_reg.size());
680  }
681  //now go through and look for exit region = entry region
682  int i=0;
683  while (i<from_reg.size()) {
684  if (from_reg[i]==to_reg[i]) {
685  egsInformation("\nEGS_PhspScoring: Cannot have entry region = exit region (reg no. %d)\n",from_reg[i]);
686  egsInformation("Will delete this pair\n");
687  p=from_reg.begin()+i;
688  p1 =to_reg.begin()+i;
689  from_reg.erase(p);
690  to_reg.erase(p1);
691  }
692  else {
693  //advance counter
694  i++;
695  }
696  }
697  }
698  }
699  //now get common inputs for both scoring methods
700  if (input->getInput("output format", str) < 0) {
701  egsInformation("EGS_PhspScoring: No input for output format type. Will default to EGSnrc.\n");
702  phspouttype = 0;
703  }
704  else {
705  vector<string> allowed_oformat;
706  allowed_oformat.push_back("EGSnrc");
707  allowed_oformat.push_back("IAEA");
708  phspouttype = input->getInput("output format", allowed_oformat, -1);
709  if (phspouttype < 0) {
710  egsFatal("\nEGS_PhspScoring: Invalid output format.\n");
711  }
712  //see if the user wants to specify constant X/Y/Z for IAEA format
713  if (phspouttype == 1) {
714  int err02 = input->getInput("constant X",xyzconst[0]);
715  int err03 = input->getInput("constant Y",xyzconst[1]);
716  int err04 = input->getInput("constant Z",xyzconst[2]);
717  if (!err02) {
718  xyzisconst[0] = true;
719  }
720  if (!err03) {
721  xyzisconst[1] = true;
722  }
723  if (!err04) {
724  xyzisconst[2] = true;
725  }
726  //see if user wants to score time index (if available)
727  //default is not to score
728  // The "score mu" input is supported for backwards compatibility
729  if (!input->getInput("score mu", str)) {
730  vector<string> allowed_timescore;
731  allowed_timescore.push_back("no");
732  allowed_timescore.push_back("yes");
733  itimescore = input->getInput("score mu",allowed_timescore,-1);
734  if (itimescore < 0) {
735  egsWarning("\nEGS_PhspScoring: Invalid input for time index scoring. Will not score time.\n");
736  itimescore = 0;
737  }
738  }
739  // Now "score time index" is used instead of "score mu"
740  if (!input->getInput("score time index", str)) {
741  vector<string> allowed_timescore;
742  allowed_timescore.push_back("no");
743  allowed_timescore.push_back("yes");
744  itimescore = input->getInput("score time index",allowed_timescore,-1);
745  if (itimescore < 0) {
746  egsWarning("\nEGS_PhspScoring: Invalid input for time index scoring. Will not score time.\n");
747  itimescore = 0;
748  }
749  }
750  }
751  }
752  if (phspouttype == 0) {
753  //see if user wants to score multiple crossers
754  if (!input->getInput("score multiple crossers", str)) {
755  vector<string> allowed_scoremc;
756  allowed_scoremc.push_back("no");
757  allowed_scoremc.push_back("yes");
758  iscoremc = input->getInput("score multiple crossers",allowed_scoremc,-1);
759  if (iscoremc < 0) {
760  egsWarning("\nEGS_PhspScoring: Invalid input for score multiple crossers. Will not score.\n");
761  iscoremc = 0;
762  }
763  }
764  }
765  if (input->getInput("output directory",outdir) < 0) {
766  outdir="";
767  }
768  if (input->getInput("particle type", str) < 0) {
769  egsInformation("EGS_PhspScoring: No input for particle type. Will score all.\n");
770  ptype = 0;
771  }
772  else {
773  //get particle type
774  vector<string> allowed_ptype;
775  allowed_ptype.push_back("all");
776  allowed_ptype.push_back("photons");
777  allowed_ptype.push_back("charged");
778  ptype = input->getInput("particle type",allowed_ptype,-1);
779  if (ptype < 0) {
780  egsFatal("\nEGS_PhspScoring: Invalid particle type.\n");
781  }
782  }
783 
784  //=================================================
785 
786  /* Setup phsp scoring object with input parameters */
787  EGS_PhspScoring *result = new EGS_PhspScoring("",f);
788  result->setName(input);
789  if (stype==0) {
790  result->setGeom(phspgeom);
791  }
792  else if (stype==1) {
793  result->setEntryExitReg(from_reg,to_reg);
794  }
795  result->setOType(phspouttype);
796  result->setXYZconst(xyzisconst,xyzconst);
797  result->setOutDir(outdir);
798  result->setParticleType(ptype);
799  result->setScoreDir(sdir);
800  result->setTimeScore(itimescore);
801  result->setScoreMC(iscoremc);
802  return result;
803  }
804 }
Base class for advanced EGSnrc C++ applications.
int getNparallel() const
Returns the number of parallel jobs executing.
EGS_Float getTimeIndex()
Returns the value of the time synchronization parameter.
const string & getAppDir() const
Returns the absolute path to the user code directory.
int getIparallel() const
Returns the job number in a parallel run.
EGS_Particle top_p
The top particle on the stack (i.e., the particle being transported)
virtual void setApplication(EGS_Application *App)
Set the application this object belongs to.
string description
A short ausgab object description.
EGS_Application * app
The application this object belongs to.
Base geometry class. Every geometry class must be derived from EGS_BaseGeometry.
const string & getName() const
Get the name of this geometry.
static EGS_BaseGeometry * getGeometry(const string &Name)
Get a pointer to the geometry named Name.
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.
void setName(EGS_Input *inp)
Set the name of the object from the information provided by inp.
const string & getObjectName() const
Get the object name.
string name
The object name.
A phase space scoring object: header.
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
Global egspp functions header file.
EGS_Input class header file.
A phase space scoring ausgab object.
EGS_RADIATIVE_SPLITTING_EXPORT EGS_AusgabObject * createAusgabObject(EGS_Input *input, EGS_ObjectFactory *f)
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...
EGS_InfoFunction EGS_EXPORT egsFatal
Always use this function for reporting fatal errors.
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,...
string egsJoinPath(const string &first, const string &second)
Join two path variables (or a path and a file name) using the platform specific directory separator a...
EGS_InfoFunction EGS_EXPORT egsWarning
Always use this function for reporting warnings.
EGS_Vector x
position
EGS_Float E
particle energy in MeV
EGS_Vector u
direction
int latch
latch variable (useful as a flag on many occasions)
EGS_Float wt
statistical weight
int q
particle charge