EGSnrc C++ class library  Report PIRS-898 (2021)
Iwan Kawrakow, Ernesto Mainegra-Hing, Frederic Tessier, Reid Townson and Blake Walters
egs_atomic_relaxations.cpp
Go to the documentation of this file.
1 /*
2 ###############################################################################
3 #
4 # EGSnrc egs++ atomic relaxation
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, 2008
25 #
26 # Contributors: Reid Townson
27 #
28 ###############################################################################
29 */
30 
36 #include "egs_atomic_relaxations.h"
37 #include "egs_rndm.h"
38 #include "egs_functions.h"
39 #include "egs_application.h"
40 #include "egs_alias_table.h"
41 
42 #include <iostream>
43 #include <fstream>
44 #include <string>
45 #include <cstdlib>
46 
47 using namespace std;
48 
49 /*
50 class EGS_LOCAL EGS_SimpleAliasTable {
51 
52 public:
53 
54  EGS_SimpleAliasTable(int N, const EGS_Float *f);
55 
56  ~EGS_SimpleAliasTable();
57 
58  int sample(EGS_RandomGenerator *rndm) const {
59  int bin = (int) (rndm->getUniform()*n);
60  return rndm->getUniform() < wi[bin] ? bin : bins[bin];
61  };
62 
63  int n; //!< number of subintervals
64  EGS_Float *wi; //!< array of bin branching probabilities
65  unsigned short *bins; //!< bins
66 
67 };
68 
69 EGS_SimpleAliasTable::EGS_SimpleAliasTable(int N, const EGS_Float *f) : n(0) {
70  if( N < 1 ) return;
71  n = N;
72  wi = new EGS_Float [n]; bins = new unsigned short [n]; int i;
73  double sum = 0; double *fcum = new double [n];
74  for(i=0; i<n; ++i) { fcum[i] = f[i]; sum += fcum[i]; bins[i] = n+1; }
75  sum /= n; int jh, jl;
76  for(i=0; i<n-1; ++i) {
77  for(jh=0; jh<n-1; jh++) {
78  if( bins[jh] > n && fcum[jh] > sum ) break;
79  }
80  for(jl=0; jl<n-1; jl++) {
81  if( bins[jl] > n && fcum[jl] < sum ) break;
82  }
83  double aux = sum - fcum[jl];
84  fcum[jh] -= aux;
85  wi[jl] = fcum[jl]/sum; bins[jl] = jh;
86  }
87  for(i=0; i<n; ++i) {
88  if( bins[i] > n ) { bins[i] = i; wi[i] = 1; }
89  //egsInformation("alias table: %d %d %g\n",i,bins[i],wi[i]);
90  }
91  delete [] fcum;
92 }
93 
94 EGS_SimpleAliasTable::~EGS_SimpleAliasTable() {
95  if( n > 0 ) { delete [] wi; delete [] bins; }
96 }
97 */
98 
99 class EGS_LOCAL EGS_ShellData {
100 
101 public:
102 
103  float be;
104  unsigned short type;
105  unsigned short ntrans;
106  unsigned short *ttypes;
108 
109  EGS_ShellData() : ntrans(0), table(0) {};
110  ~EGS_ShellData() {
111  deleteData();
112  }
113 
114  void deleteData() {
115  if (ntrans > 0) {
116  delete [] ttypes;
117  ntrans = 0;
118  }
119  if (table) {
120  delete table;
121  table = 0;
122  }
123  };
124 
125  bool loadData(istream &data);
126 
127  int sample(EGS_RandomGenerator *rndm) const {
128  return ttypes[table->sample(rndm)];
129  };
130 
131 };
132 
133 bool EGS_ShellData::loadData(istream &data) {
134  deleteData();
135  char t;
136  data.read((char *)&t,sizeof(char));
137  type = t;
138  data.read((char *)&ntrans,sizeof(short));
139  data.read((char *)&be,sizeof(float));
140  //egsInformation("shell is of type %d, has BE=%g and %d transitions\n",type,be,ntrans);
141  if (data.fail() || ntrans > 10000) {
142  ntrans = 0;
143  return false;
144  }
145  if (ntrans == 0) {
146  return true;
147  }
148  ttypes = new unsigned short [ntrans];
149  EGS_Float *tmp = new EGS_Float [ntrans];
150  float aux;
151  for (int i=0; i<ntrans; ++i) {
152  data.read((char *)&ttypes[i],sizeof(unsigned short));
153  data.read((char *)&aux,sizeof(float));
154  tmp[i] = aux;
155  //egsInformation("got transition %d with p=%g\n",ttypes[i],aux);
156  }
157  if (data.fail()) {
158  delete [] tmp;
159  deleteData();
160  return false;
161  }
162  table = new EGS_SimpleAliasTable(ntrans,tmp);
163  delete [] tmp;
164  return true;
165 }
166 
167 class EGS_LOCAL EGS_ElementRelaxData {
168 
169 public:
170 
171  EGS_ElementRelaxData() : Z(0), nshell(0), shells(0) {};
172 
174  deleteData();
175  };
176 
177  int loadData(int iZ, istream &data);
178 
179 
180  unsigned short Z;
181  unsigned short nshell;
183 
184  void deleteData() {
185  if (nshell > 0) {
186  delete [] shells;
187  }
188  Z = 0;
189  nshell = 0;
190  shells = 0;
191  };
192 
193 };
194 
195 int EGS_ElementRelaxData::loadData(int iZ, istream &data) {
196  if (iZ == Z) {
197  return 0;
198  }
199  deleteData();
200  Z = iZ;
201  int pos = 2 + (Z-1)*sizeof(int);
202  data.seekg(pos,ios::beg);
203  data.read((char *)&pos,sizeof(int));
204  if (data.fail()) {
205  egsWarning("Failed reading position for element %d\n",Z);
206  Z = 0;
207  return 5;
208  }
209  data.seekg(pos,ios::beg);
210  data.read((char *)&nshell,sizeof(nshell));
211  if (data.fail() || nshell < 1 || nshell > 63) {
212  egsWarning("Failed reading number of shells for Z=%d (got %d shells and fail()=%d\n",
213  Z,nshell,data.fail());
214  nshell = 0;
215  return 6;
216  }
217  //egsInformation("element %d has %d shells\n",Z,nshell);
218  shells = new EGS_ShellData [nshell];
219  for (int j=0; j<nshell; ++j) {
220  if (!shells[j].loadData(data)) {
221  egsWarning("Failed loading data for shell %d of element %d\n",j+1,Z);
222  deleteData();
223  return 7;
224  }
225  }
226  return 0;
227 }
228 
229 class EGS_LOCAL EGS_RelaxImplementation {
230 
231 public:
232 
233  EGS_RelaxImplementation(const char *data_path) : elements(0), nz(0) {
234  data_file = egsJoinPath(data_path,"relax_onebyte.data");
235  };
236 
238  if (nz > 0) {
239  for (int j=0; j<nz; ++j) {
240  if (elements[j]) {
241  delete elements[j];
242  }
243  }
244  delete [] elements;
245  }
246  };
247 
248  int loadData(int Z);
249  int loadData(int Z, istream &data);
250  int loadData(int Nz, const int *Zarray);
251  int loadAllData();
252 
253  int openDataFile(istream **data);
254 
255  void checkData(int Z, int shell) {
256  static const char *func_name = "checkData";
257  if (!elements)
258  if (loadData(Z)) egsFatal("%s: failed to load data for Z=%d\n",
259  func_name,Z);
260  if (Z < 1 || Z > nz)
261  egsFatal("%s: Z=%d is outside of initialized range 1...%d\n",
262  func_name,Z,nz);
263  if (shell < 0 || shell >= elements[Z-1]->nshell)
264  egsFatal("%s: element %d has %d shells but you are asking for "
265  "shell %d\n",func_name,Z,elements[Z-1]->nshell,shell);
266  };
267 
268  void relax(int Z, int sh, EGS_Float ecut, EGS_Float pcut,
269  EGS_RandomGenerator *rndm, double &edep,
271  checkData(Z,sh);
272  EGS_Float minE = pcut < ecut ? pcut : ecut;
273  relax(Z,sh,minE,ecut,pcut,rndm,edep,particles);
274  };
275 
276  EGS_Float bindingEnergy(int Z, int shell) {
277  checkData(Z,shell);
278  return elements[Z-1]->shells[shell].be;
279  };
280 
281  int getNShell(int Z) {
282  return elements[Z-1]->nshell;
283  };
284 
285  void setBindingEnergy(int Z, int shell, EGS_Float new_be) {
286  checkData(Z,shell);
287  elements[Z-1]->shells[shell].be = new_be;
288  };
289 
290  EGS_Float getMaxGammaEnergy(int Z, int shell) {
291  checkData(Z,shell);
292  int ntrans = elements[Z-1]->shells[shell].ntrans;
293  if (ntrans < 1) {
294  return 0;
295  }
296  EGS_Float E = elements[Z-1]->shells[shell].be;
297  EGS_Float emax = 0;
298  for (int j=0; j<ntrans; ++j) {
299  int transition = elements[Z-1]->shells[shell].ttypes[j];
300  if (transition < 64) {
301  EGS_Float Egamma = E - elements[Z-1]->shells[transition].be;
302  if (Egamma > emax) {
303  emax = Egamma;
304  }
305  }
306  }
307  return emax;
308  };
309 
310  EGS_Float getMaxElectronEnergy(int Z, int shell) {
311  checkData(Z,shell);
312  int ntrans = elements[Z-1]->shells[shell].ntrans;
313  if (ntrans < 1) {
314  return 0;
315  }
316  EGS_Float E = elements[Z-1]->shells[shell].be;
317  EGS_Float emax = 0;
318  for (int j=0; j<ntrans; ++j) {
319  int transition = elements[Z-1]->shells[shell].ttypes[j];
320  if (transition >= 64) {
321  int sh1 = (transition >> 6);
322  int sh2 = transition - (sh1 << 6);
323  EGS_Float Eelec = E - (elements[Z-1]->shells[sh1].be +
324  elements[Z-1]->shells[sh2].be);
325  if (Eelec > emax) {
326  emax = Eelec;
327  }
328  }
329  }
330  return emax;
331  };
332 
333  void relax(int Z, int sh, EGS_Float minE, EGS_Float ecut, EGS_Float pcut,
334  EGS_RandomGenerator *rndm, double &edep,
336  EGS_Float E = elements[Z-1]->shells[sh].be;
337  //egsInformation("relax(%d,%d): E=%g minE=%g\n",Z,sh,E,minE);
338  if (E <= minE || elements[Z-1]->shells[sh].ntrans < 1) {
339  //egsInformation("relax: terminating\n");
340  edep += E;
341  return;
342  }
343  int transition = elements[Z-1]->shells[sh].sample(rndm);
344  //egsInformation("relax: got transition %d\n",transition);
345  if (transition < 64) {
346  EGS_Float Egamma = E - elements[Z-1]->shells[transition].be;
347  //egsInformation("->flourescence, Egamma=%g\n",Egamma);
348  if (Egamma > pcut) {
349  EGS_RelaxationParticle p(0,Egamma);
350  particles.add(p);
351  }
352  else {
353  edep += Egamma;
354  }
355  relax(Z,transition,minE,ecut,pcut,rndm,edep,particles);
356  }
357  else {
358  int sh1 = (transition >> 6);
359  int sh2 = transition - (sh1 << 6);
360  EGS_Float Eelec = E - elements[Z-1]->shells[sh1].be - elements[Z-1]->shells[sh2].be;
361  //egsInformation("->Auger, sh1=%d sh2=%d E=%g\n",sh1,sh2,Eelec);
362  if (Eelec > ecut) {
363  EGS_RelaxationParticle p(-1,Eelec);
364  particles.add(p);
365  }
366  else {
367  edep += Eelec;
368  }
369  relax(Z,sh1,minE,ecut,pcut,rndm,edep,particles);
370  relax(Z,sh2,minE,ecut,pcut,rndm,edep,particles);
371  }
372  };
373 
374  EGS_ElementRelaxData **elements;
375  string data_file;
376  int nz;
377 
378 };
379 
380 int EGS_RelaxImplementation::openDataFile(istream **the_data) {
381  static const char *func_name = "EGS_RelaxImplementation::openDataFile()";
382  *the_data = 0;
383  ifstream *data = new ifstream(data_file.c_str(),ios::binary);
384  if (!(*data)) {
385  egsWarning("%s: failed to open data file %s\n",
386  func_name,data_file.c_str());
387  return 1;
388  }
389  short Nz;
390  data->read((char *)&Nz,sizeof(short));
391  if (data->fail() || Nz < 1 || Nz > 200) {
392  egsWarning("%s: failed reading first record from %s\n",
393  func_name,data_file.c_str());
394  return 2;
395  }
396  if (Nz > nz) {
397  EGS_ElementRelaxData **new_elements = new EGS_ElementRelaxData* [Nz];
398  if (nz > 0) {
399  for (int j=0; j<nz; ++j) {
400  new_elements[j] = elements[j];
401  }
402  delete [] elements;
403  }
404  else {
405  for (int j=0; j<Nz; ++j) {
406  new_elements[j] = 0;
407  }
408  }
409  elements = new_elements;
410  nz = Nz;
411  }
412  *the_data = data;
413  return 0;
414 }
415 
416 
417 int EGS_RelaxImplementation::loadData(int Z) {
418  static const char *func_name = "EGS_RelaxImplementation::loadData()";
419  if (Z < 1) {
420  egsWarning("%s: called with Z=%d?\n",func_name,Z);
421  return 3;
422  }
423  istream *the_data;
424  int res = openDataFile(&the_data);
425  if (res || !the_data) {
426  return res;
427  }
428  istream &data = *the_data;
429  if (Z > nz) {
430  egsWarning("%s: called with Z=%d, but I only have data for Z<=%d.\n",
431  func_name,Z,nz);
432  return 4;
433  }
434  res = loadData(Z,data);
435  delete the_data;
436  return res;
437 }
438 
439 int EGS_RelaxImplementation::loadData(int Z, istream &data) {
440  if (elements[Z-1]) {
441  return 0;
442  }
443  elements[Z-1] = new EGS_ElementRelaxData;
444  return elements[Z-1]->loadData(Z,data);
445 }
446 
447 int EGS_RelaxImplementation::loadData(int Nz, const int *Zarray) {
448  istream *the_data;
449  int res = openDataFile(&the_data);
450  if (res || !the_data) {
451  return res;
452  }
453  istream &data = *the_data;
454  for (int j=0; j<Nz; ++j) {
455  res = loadData(Zarray[j],data);
456  if (res) {
457  break;
458  }
459  }
460  delete the_data;
461  return res;
462 }
463 
464 int EGS_RelaxImplementation::loadAllData() {
465  istream *the_data;
466  int res = openDataFile(&the_data);
467  if (res || !the_data) {
468  return res;
469  }
470  istream &data = *the_data;
471  for (int Z=1; Z<=nz; ++Z) {
472  res = loadData(Z,data);
473  if (res) {
474  break;
475  }
476  }
477  delete the_data;
478  return res;
479 }
480 
482  string path;
483  if (!data_path) {
485  if (app) {
486  path = egsJoinPath(app->getHenHouse(),"data");
487  }
488  else {
489  char *hen_house = getenv("HEN_HOUSE");
490  if (!hen_house) {
491  egsWarning("EGS_AtomicRelaxations::EGS_AtomicRelaxations: "
492  "no active application and HEN_HOUSE not defined.\n"
493  " assuming local directory for relax data\n");
494  path = "./";
495  }
496  else {
497  path = egsJoinPath(hen_house,"data");
498  }
499  }
500  }
501  else {
502  path = data_path;
503  }
504  p = new EGS_RelaxImplementation(path.c_str());
505 }
506 
507 EGS_AtomicRelaxations::~EGS_AtomicRelaxations() {
508  delete p;
509 }
510 
512  return p->loadData(Z);
513 }
514 
515 int EGS_AtomicRelaxations::loadData(int nz, const int *Zarray) {
516  return p->loadData(nz,Zarray);
517 }
518 
520  return p->loadAllData();
521 }
522 
523 void EGS_AtomicRelaxations::relax(int Z, int sh, EGS_Float ecut, EGS_Float pcut,
524  EGS_RandomGenerator *rndm, double &edep,
526  p->relax(Z,sh,ecut,pcut,rndm,edep,particles);
527 }
528 
529 EGS_Float EGS_AtomicRelaxations::getBindingEnergy(int Z, int shell) {
530  return p->bindingEnergy(Z,shell);
531 }
532 
534  return p->getNShell(Z);
535 }
536 
538  EGS_Float new_be) {
539  p->setBindingEnergy(Z,shell,new_be);
540 }
541 
542 EGS_Float EGS_AtomicRelaxations::getMaxGammaEnergy(int Z, int shell) {
543  return p->getMaxGammaEnergy(Z,shell);
544 }
545 
546 EGS_Float EGS_AtomicRelaxations::getMaxElectronEnergy(int Z, int shell) {
547  return p->getMaxElectronEnergy(Z,shell);
548 }
unsigned short type
shell type according to EADL nomenclature
EGS_SimpleAliasTable * table
for sampling transitions
EGS_Float getMaxGammaEnergy(int Z, int shell)
unsigned short * ttypes
types of the ntrans transitions
EGS_AliasTable class header file.
EGS_AtomicRelaxations(const char *data_path=0)
EGS_AtomicRelaxations class header file.
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...
unsigned short Z
atomic number
Global egspp functions header file.
unsigned short ntrans
number of transitions
EGS_Float getBindingEnergy(int Z, int shell)
void relax(int Z, int sh, EGS_Float ecut, EGS_Float pcut, EGS_RandomGenerator *rndm, double &edep, EGS_SimpleContainer< EGS_RelaxationParticle > &particles)
EGS_Float getMaxElectronEnergy(int Z, int shell)
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_RandomGenerator class header file.
A class for sampling random bins from a given probability distribution using the alias table techniqu...
void setBindingEnergy(int Z, int shell, EGS_Float new_be)
static EGS_Application * activeApplication()
Get the active application.
unsigned short nshell
number of shells
float be
binding energy
const string & getHenHouse() const
Returns the HEN_HOUSE directory.
EGS_ShellData * shells
shell data
EGS_Application class header file.
Base class for advanced EGSnrc C++ applications.
EGS_InfoFunction EGS_EXPORT egsWarning
Always use this function for reporting warnings.