EGSnrc C++ class library  Report PIRS-898 (2021)
Iwan Kawrakow, Ernesto Mainegra-Hing, Frederic Tessier, Reid Townson and Blake Walters
egs_fluence_scoring.h
Go to the documentation of this file.
1 /*
2 ###############################################################################
3 #
4 # EGSnrc egs++ fluence scoring object header
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: Ernesto Mainegra-Hing, 2022
25 #
26 # Contributors:
27 #
28 ###############################################################################
29 #
30 # Ausgab objects (AOs) for fluence scoring in arbitrary geometrical regions or at
31 # circular or rectangular scoring fields located anywhere in space for a specific
32 # particle type. Fluence can be scored for multiple particle types by definining
33 # different AOs. An option exists for scoring the fluence of primary particles.
34 # Classification into primary and secondary particles follows the definition used
35 # in FLURZnrc for IPRIMARY = 2 (primaries) and IPRIMARY = 4 (secondaries).
36 #
37 ###############################################################################
38 */
39 
45 #ifndef EGS_FLUENCE_SCORING_
46 #define EGS_FLUENCE_SCORING_
47 
48 #include "egs_ausgab_object.h"
49 #include "egs_transformations.h"
50 #include "egs_interpolator.h"
51 #include <egs_scoring.h>
52 
53 #include <fstream>
54 using namespace std;
55 
56 
57 #ifdef WIN32
58 
59  #ifdef BUILD_FLUENCE_SCORING_DLL
60  #define EGS_FLUENCE_SCORING_EXPORT __declspec(dllexport)
61  #else
62  #define EGS_FLUENCE_SCORING_EXPORT __declspec(dllimport)
63  #endif
64  #define EGS_FLUENCE_SCORING_LOCAL
65 
66 #else
67 
68  #ifdef HAVE_VISIBILITY
69  #define EGS_FLUENCE_SCORING_EXPORT __attribute__ ((visibility ("default")))
70  #define EGS_FLUENCE_SCORING_LOCAL __attribute__ ((visibility ("hidden")))
71  #else
72  #define EGS_FLUENCE_SCORING_EXPORT
73  #define EGS_FLUENCE_SCORING_LOCAL
74  #endif
75 
76 #endif
77 
79 enum FieldType { circle=0, rectangle=1 };
80 
82 enum ParticleType { electron = -1, photon = 0, positron = 1, unknown = -99 };
83 
85 enum eFluType { flurz=0, stpwr=1, stpwrO5=2 };
86 
98 class EGS_FLUENCE_SCORING_EXPORT EGS_FluenceScoring : public EGS_AusgabObject {
99 
100 public:
102  EGS_FluenceScoring(const string &Name="", EGS_ObjectFactory *f = 0);
105 
106  void initScoring(EGS_Input *inp);
107 
108  void getSensitiveRegions(EGS_Input *inp);
109 
110  void getNumberRegions(const string &str, vector<int> &regs);
111 
112  void getLabelRegions(const string &str, vector<int> &regs);
113 
114  void setUpRegionFlags();
115 
116  void describeMe();
117 
118  int getDigits(int i) {
119  int imax = 10;
120  while (i>=imax) {
121  imax*=10;
122  }
123  return (int)log10((float)imax);
124  };
125 
126  void flagSecondaries(const int &iarg, const int &q) {
127  int npold = app->getNpOld(),
128  np = app->getNp();
129  if (scoring_charge) {
130  /***************************************************************
131  DEFAULT:
132  FLURZnrc IPRIMARY = 2 (primaries) IPRIMARY = 4 (secondaries)
133  Secondary charged particles defined as those resulting
134  from charged particle interactions, atomic relaxations
135  following EII, brems and annihilation photons.
136 
137  OPTIONAL:
138  FLURZnrc IPRIMARY = 1 (e- from brems as primaries)
139  Set `source particle` to 'photon' in the input file to not flag
140  brems photons so that when scoring charged particle fluence in
141  photon beams, first generation e- are primaries. This is
142  implicit for photon interactions when scoring charged particle
143  fluence. But one must explicitly account for that during brems events.
144  ****************************************************************/
145  if (iarg == EGS_Application::AfterBrems ||
149  /************************************************************************
150  Skip block below for a photon beam. First generation e- are primaries.
151  This will apply to ALL brems events in a photon beam simulation. One
152  could fine tune it to only brems events in certain regions, for instance
153  a bremsstrahlung target, by using the is_source flag for those regions.
154  *************************************************************************/
155  if (!(iarg == EGS_Application::AfterBrems && source_charge == photon)) {
156  for (int ip = npold+1; ip <= np; ip++) {
157  app->setLatch(ip,1);
158  }
159  }
160  }
161  else if (iarg == EGS_Application::AfterBhabha) {
162  if (q == -1) {
163  app->setLatch(np,1);
164  }
165  else {
166  app->setLatch(np-1,1);
167  }
168  }
169  }
170  else {
171  /***************************************************************
172  FLURZnrc IPRIMARY = 3
173  Flag scattered photons, secondaries, and relaxation
174  particles as secondaries
175  ****************************************************************/
176  if (iarg == EGS_Application::AfterPair ||
178  iarg == EGS_Application::AfterPhoto ||
180  for (int ip = npold; ip <= np; ip++) {
181  app->setLatch(ip,1);
182  }
183  }
184  }
185 
186  };
187 
188 protected:
189 
190  EGS_I64 current_ncase;
191 
192  ParticleType scoring_charge;// charge of scored particles
193  ParticleType source_charge; // charge of source particles
194 
195  /* Fluence Scoring Arrays */
196  EGS_ScoringArray **flu; // differential fluence: primaries + secondaries
197  EGS_ScoringArray **flu_p; // differential fluence: primaries only
198  EGS_ScoringArray *fluT; // Total fluence: primaries + secondaries
199  EGS_ScoringArray *fluT_p;// Total fluence: primaries only
200 
201  /* Regions flags */
202  vector<bool> is_sensitive; // flag scoring regions
203  vector<bool> is_source; // Flag regions such as brems target or radiactive source
204  // Interacting particles not subjected to classification
205  vector <int> f_start, f_stop; // Markers for group regions input
206  vector <int> f_region; // Input list of scoring regions
207  vector <int> s_region; // Input list of source regions
208  string f_regionsString; // Input string of scoring regions or labels
209  string s_regionsString; // Input string of source regions or labels
210  int n_scoring_regions;// number of scoring regions
211  int n_source_regions; // number of source regions
212  int nreg; // regions in geometry
213  int max_reg; // maximum scoring region number
214  int active_region; // Region showing calculation progress
215  bool score_in_all_regions;
216  bool source_in_all_regions;
217 
218  EGS_Float norm_u; // User normalization
219 
220  /* Energy grid inputs */
221  EGS_Float flu_a, flu_a_i,
222  flu_b,
223  flu_xmin,
224  flu_xmax;
225  int flu_s,
226  flu_nbin;
227  /* Classification variables */
228  EGS_Float m_primary,
229  m_tot;
230 
231  string particle_name;
232  /* Auxiliary input variables*/
233  bool verbose,
234  score_spe,
235  score_primaries;
236 };
237 
317 class EGS_FLUENCE_SCORING_EXPORT EGS_PlanarFluence : public EGS_FluenceScoring {
318 
319 public:
321  EGS_PlanarFluence(const string &Name="", EGS_ObjectFactory *f = 0);
324  EGS_Float area() {
325  return Area;
326  };
327  bool needsCall(EGS_Application::AusgabCall iarg) const {
328  if (iarg == EGS_Application::BeforeTransport ||
330  return true;
331  }
332  else if (score_primaries &&
333  (iarg == EGS_Application::AfterPair ||
335  iarg == EGS_Application::AfterPhoto ||
337  iarg == EGS_Application::AfterBrems ||
342  return true;
343  }
344  else {
345  return false;
346  }
347  };
348 
349  inline int hitsField(const EGS_Particle &p, EGS_Float *dist);
350  inline void score(const EGS_Particle &p, const int &ivoxel);
351  void describeMe();
352  void initScoring(EGS_Input *inp);
353  void setApplication(EGS_Application *App);
354  void ouputPlanarFluence(EGS_ScoringArray *fT, const double &norma);
355  void ouputResults();
356  void reportResults();
357  int processEvent(EGS_Application::AusgabCall iarg) {
358 
359  int q = app->top_p.q,
360  ir = app->top_p.ir;
361 
362  if (q == scoring_charge && ir >= 0 && is_sensitive[ir]) {
363 
364  /* Quantify contribution to scoring field */
365  if (iarg == EGS_Application::BeforeTransport) {
366  ixy = hitsField(app->top_p,&distance);
367  if (ixy >= 0) {
368  x0 = app->top_p.x;
369  hits_field = true;
370  }
371  else {
372  hits_field = false;
373  }
374  }
375 
376  if (iarg == EGS_Application::AfterTransport && hits_field) {
377  EGS_Vector xstep = app->top_p.x - x0;
378  if (xstep.length() >= distance) { // crossed scoring field
379  //if (!app->top_p.latch ) m_primary += app->top_p.wt;
380  m_tot += app->top_p.wt;
381  score(app->top_p, ixy);
382  }
383  hits_field = false;
384  }
385  }
386 
387  /********************************************************************
388  * Flag secondaries after interactions. Definition of secondaries
389  * matches FLURZnrc. One could fine tune it by using the is_source
390  * flag to skip this block in certains regions such as brems targets,
391  * radioactive sources, etc.
392  *
393  * BEWARE: Latch set to 1 (bit 0) to flag secondaries.
394  * Other applications might use latch for other purposes!
395  *********************************************************************/
396  if (score_primaries && ir >= 0 && !is_source[ir]) {
397  flagSecondaries(iarg, q);
398  }
399 
400  return 0;
401 
402  };
403 
404  void setCurrentCase(EGS_I64 ncase) {
405  if (ncase != current_ncase) {
406  current_ncase = ncase;
407 
408  fluT->setHistory(ncase);
409 
410  if (score_spe) {
411  for (int j = 0; j < Nx*Ny; j++) {
412  flu[j]->setHistory(ncase);
413  }
414  }
415 
416  if (score_primaries) {
417  fluT_p->setHistory(ncase);
418  if (score_spe) {
419  for (int j = 0; j < Nx*Ny; j++) {
420  flu_p[j]->setHistory(ncase);
421  }
422  }
423  }
424  }
425  };
426 
427  void resetCounter() {
428  current_ncase = 0;
429  fluT->reset();
430  if (flu) {
431  for (int j = 0; j < Nx*Ny; j++) {
432  flu[j]->reset();
433  }
434  }
435  if (score_primaries) {
436  fluT_p->reset();
437  if (score_spe) {
438  for (int j = 0; j < Nx*Ny; j++) {
439  flu_p[j]->reset();
440  }
441  }
442  }
443  }
444  bool storeState(ostream &data) const;
445  bool setState(istream &data);
446  bool addState(istream &data);
447 
448 private:
449 
450  FieldType field_type;
451 
452  EGS_Float Area;
453 
454  /* Circular scoring field parameters */
455  EGS_Vector m_normal,
456  m_midpoint,
457  ux, uy;
458  EGS_Vector x0;
459  EGS_Float m_R, m_R2; // scoring field
460  /* Rectangular field parameters */
461  EGS_Float ax, ay, vx, vy;
462  int Nx, Ny, n_sensitive_regs, ixy;
463 
464  EGS_Float m_d; // distance from origin to center of scoring field
465  EGS_Float distance; // distance to scoring field along particle's direction
466  bool hits_field;
467 
468 };
469 
552 class EGS_FLUENCE_SCORING_EXPORT EGS_VolumetricFluence : public EGS_FluenceScoring {
553 
554 public:
556  EGS_VolumetricFluence(const string &Name="", EGS_ObjectFactory *f = 0);
557 
560 
561  /***************************************************************
562  NOTE: Primary particles defined as particles that suffer any
563  type of interaction, except for the slowing down of
564  charged particles in a medium.
565  ****************************************************************/
566  bool needsCall(EGS_Application::AusgabCall iarg) const {
567  if (iarg == EGS_Application::BeforeTransport ||
569  return true;
570  }
571  else if (score_primaries &&
572  (iarg == EGS_Application::AfterPair ||
574  iarg == EGS_Application::AfterPhoto ||
576  iarg == EGS_Application::AfterBrems ||
581  return true;
582  }
583  else {
584  return false;
585  }
586  };
587 
588  void describeMe();
589 
590  void initScoring(EGS_Input *inp);
591 
592  void setApplication(EGS_Application *App);
593 
594  void ouputVolumetricFluence(EGS_ScoringArray *fT, const double &norma);
595 
596  void ouputResults();
597 
598  void reportResults();
599 
600  int processEvent(EGS_Application::AusgabCall iarg) {
601 
602  int q = app->top_p.q,
603  ir = app->top_p.ir,
604  latch = app->top_p.latch;
605 
606  if (q == scoring_charge && ir >= 0 && is_sensitive[ir]) {
607 
608  if (!q) { // It's a photon
609  /* Score photon fluence */
610  if (iarg == EGS_Application::BeforeTransport) {
611  /* Linear track-Length scoring */
612  EGS_Float wtstep = app->top_p.wt*app->getTVSTEP();
613  /* Score total fluence */
614  fluT->score(ir,wtstep);
615  if (score_primaries && !latch) {
616  fluT_p->score(ir,wtstep);
617  }
618  /* Score differential fluence */
619  if (score_spe) {
620  EGS_Float e = app->top_p.E;
621  if (flu_s) {
622  e = log(e);
623  }
624  EGS_Float ae;
625  int je;
626  /* Score differential fluence */
627  if (e > flu_xmin && e <= flu_xmax) {
628  ae = flu_a*e + flu_b;
629  je = min((int)ae,flu_nbin-1);
630  EGS_ScoringArray *aux = flu[ir];
631  aux->score(je,wtstep);
632  if (score_primaries && !latch) {
633  flu_p[ir]->score(je,wtstep);
634  }
635  }
636  }
637  }
638  }
639  else {// It's a charged particle
640 
641  EGS_Float edep = app->getEdep();
642 
643  /* Score charged particle fluence */
644  if (edep &&
646  iarg == EGS_Application::UserDiscard)) {
647 
648  /**************************/
649  /***** Initialization *****/
650  /**************************/
651  EGS_Float weight = app->top_p.wt;
652  bool score_p = score_primaries && !latch;
653  /* Integral fluence scoring arrays */
654  EGS_ScoringArray *auxT = fluT, *auxT_p;
655  if (score_p) {
656  auxT_p = fluT_p;
657  }
658 
659  /***************************************/
660  /* Score integral fluence using TVSTEP */
661  /***************************************/
662  EGS_Float a_step = weight*app->getTVSTEP();
663  auxT->score(ir,a_step);
664  if (score_p) {
665  auxT_p->score(ir,a_step);
666  }
667  /***************************************/
668 
669  if (score_spe) {
670 
671  EGS_ScoringArray *aux, *aux_p;
672  aux = flu[ir];
673  if (score_p) {
674  aux_p = flu_p[ir];
675  }
676 
677  EGS_Float Eb = app->top_p.E - app->getRM(),
678  Ee = Eb - edep;
679 
680  EGS_Float xb, xe;
681  if (flu_s) {
682  xb = log(Eb);
683  if (Ee > 0) {
684  xe = log(Ee);
685  }
686  else {
687  xe = -15;
688  }
689  }
690  else {
691  xb = Eb;
692  xe = Ee;
693  }
694  /**********************************************************/
695  /* If not out of bounds, proceed with rest of calculation */
696  /**********************************************************/
697  if (xb > flu_xmin && xe < flu_xmax) {
698  EGS_Float ab, ae;
699  int jb, je;
700  /* Fraction of the initial bin covered */
701  if (xb < flu_xmax) {
702  ab = flu_a*xb + flu_b;
703  jb = (int) ab;
704  /* Variable bin-width for log scale*/
705  if (flu_s) {
706  ab = (Eb*a_const[jb]-1)*r_const;
707  }
708  else {
709  ab -= jb;
710  }
711  }
712  else { // particle's energy above Emax
713  xb = flu_xmax;
714  ab = 1;
715  jb = flu_nbin - 1;
716  }
717  /* Fraction of the final bin covered */
718  if (xe > flu_xmin) {
719  ae = flu_a*xe + flu_b;
720  je = (int) ae;
721  /* Variable bin-width for log scale*/
722  if (flu_s) {
723  ae = (Ee*a_const[je]-1)*r_const;
724  }
725  else {
726  ae -= je;
727  }
728  }
729  else {
730  xe = flu_xmin; // extends below Emin
731  ae = 0;
732  je = 0;
733  }
734 
735 #ifdef DEBUG
736  if (jb == je) {
737  one_bin++;
738  }
739  else {
740  multi_bin++;
741  }
742 
743  binDist->score(jb-je,weight);
744 
745  EGS_Float totStep = 0, the_step = app->getTVSTEP();
746 #endif
747 
748  /************************************************
749  * Approach A:
750  * -----------
751  * Uses either an O(3) or O(5) series expansion of the
752  * integral of the inverse of the stopping power with
753  * respect to energy. The stopping power is represented
754  * as a linear interpolation over a log energy grid. It
755  * accounts for stopping power variation along the particle's
756  * step within the resolution of the scoring array. This
757  * is more accurate than the method used in FLURZnrc albeit
758  * about 10% slower in electron beam cases.
759  *
760  * BEWARE: For this approach to work, no range rejection
761  * ------ nor Russian Roulette should be used.
762  *
763  ************************************************/
764  if (flu_stpwr) {
765  int imed = app->getMedium(ir);
766  // Initial and final energies in same bin
767  EGS_Float step;
768  if (jb == je) {
769  step = weight*(ab-ae)*getStepPerEnergyLoss(imed,xb,xe);
770 #ifdef DEBUG
771  totStep += step;
772 #endif
773  /* Differential fluence */
774  if (score_spe) {
775  aux->score(jb,step);
776  if (score_p) {
777  aux_p->score(jb,step);
778  }
779  }
780  }
781  else {
782 
783  // First bin
784 
785  Ee = flu_xmin + jb*flu_a_i;
786  Eb=xb;
787  step = weight*ab*getStepPerEnergyLoss(imed,Eb,Ee);
788 #ifdef DEBUG
789  totStep += step;
790 #endif
791  /* Differential fluence */
792  if (score_spe) {
793  aux->score(jb,step);
794  if (score_p) {
795  aux_p->score(jb,step);
796  }
797  }
798 
799  // Last bin
800 
801  Ee = xe;
802  Eb = flu_xmin+(je+1)*flu_a_i;
803  step = weight*(1-ae)*getStepPerEnergyLoss(imed,Eb,Ee);
804 #ifdef DEBUG
805  totStep += step;
806 #endif
807  /* Differential fluence */
808  if (score_spe) {
809  aux->score(je,step);
810  if (score_p) {
811  aux_p->score(je,step);
812  }
813  }
814 
815  // intermediate bins
816 
817  for (int j=je+1; j<jb; j++) {
818  if (flu_stpwr == stpwrO5) {
819  Ee = Eb;
820  Eb = flu_xmin + (j+1)*flu_a_i;
821  /* O(eps^5) would require more pre-computed values
822  * than just 1/Lmid. One requires lnEmid[i] to get
823  * the b parameter and eps[i]=1-E[i]/E[i+1]. Not
824  * impossible, but seems unnecessary considering
825  * the excellent agreement with O(eps^3), which
826  * should be always used.
827  */
828  step = weight*getStepPerEnergyLoss(imed,Eb,Ee);
829  }
830  else { // use pre-computed values of 1/Lmid
831  step = weight*Lmid_i[j + imed*flu_nbin];
832  }
833 #ifdef DEBUG
834  totStep += step;
835 #endif
836  /* Differential fluence */
837  if (score_spe) {
838  aux->score(j,step);
839  if (score_p) {
840  aux_p->score(j,step);
841  }
842  }
843  }
844  }
845  }
846  /***************************************************
847  * -----------------------
848  * Approach B (FLURZnrc):
849  * ----------------------
850  * Path length at each energy interval from energy
851  * deposited edep and total particle step tvstep. It
852  * assumes stopping power constancy along the particle's
853  * step. It might introduce artifacts if ESTEPE or the
854  * scoring bin width are too large.
855  *
856  * BEWARE: For this approach to work, no range rejection
857  * ------ nor Russian Roulette should be used.
858  **************************************************/
859  else {
860  EGS_Float step, wtstep = weight*app->getTVSTEP()/edep;
861  // Initial and final energies in same bin
862  if (jb == je) {
863  step = wtstep*(ab-ae);
864 #ifdef DEBUG
865  totStep += step;
866 #endif
867  /* Differential fluence */
868  if (score_spe) {
869  aux->score(jb,step);
870  if (score_p) {
871  aux_p->score(jb,step);
872  }
873  }
874  }
875  else {
876 
877  // First bin
878 
879  step = wtstep*ab;
880 #ifdef DEBUG
881  totStep += step;
882 #endif
883  /* Differential fluence */
884  if (score_spe) {
885  aux->score(jb,step);
886  if (score_p) {
887  aux_p->score(jb,step);
888  }
889  }
890 
891  // Last bin
892 
893  step = wtstep*(1-ae);
894 #ifdef DEBUG
895  totStep += step;
896 #endif
897  /* Differential fluence */
898  if (score_spe) {
899  aux->score(je,step);
900  if (score_p) {
901  aux_p->score(je,step);
902  }
903  }
904  // intermediate bins
905  for (int j=je+1; j<jb; j++) {
906 #ifdef DEBUG
907  totStep += wtstep;
908 #endif
909  /* Differential fluence */
910  if (score_spe) {
911  aux->score(j,wtstep);
912  if (score_p) {
913  aux_p->score(j,wtstep);
914  }
915  }
916  }
917  }
918  }
919 
920 #ifdef DEBUG
921  EGS_Float edep_step = totStep*flu_a_i, diff = edep_step/the_step;
922  EGS_Float astep = step_a*the_step + step_b;
923  int jstep = (int) astep;
924  if (jstep < 0 || jstep > n_step_bins) {
925  egsFatal("\n**** EGS_VolumetricFluence::processEvent-> jstep = %d\n is out of bound!\n");
926  }
927  stepDist->score(jstep,app->top_p.wt);
928  relStepDiff->score(jstep,diff);
929  eCases++;
930 #endif
931  }
932  }
933  }
934  }
935  }
936 
937  /********************************************************************
938  * Flag secondaries after interactions. Definition of secondaries
939  * matches FLURZnrc. One could fine tune it by using the is_source
940  * flag to skip this block in certains regions such as brems targets,
941  * radioactive sources, etc.
942  *
943  * BEWARE: Latch set to 1 (bit 0) to flag secondaries.
944  * Other applications might use latch for other purposes!
945  *********************************************************************/
946  if (score_primaries && ir >= 0 && !is_source[ir]) {
947  flagSecondaries(iarg, q);
948  }
949 
950  return 0;
951 
952  };
953 
968  EGS_Float getStepPerEnergyLoss(const int &imed,
969  const EGS_Float &Eb,
970  const EGS_Float &Ee) {
971  EGS_Float stpFrac, eps, lnEmid;
972  if (flu_s) { //Using log(E)
973  eps = 1 - exp(Ee-Eb);
974  /* 4th order series expansion of log([Eb+Ee]/2) */
975  lnEmid = 0.5*(Eb+Ee+0.25*eps*eps*(1+eps*(1+0.875*eps)));
976  }
977  else { //Using E
978  if (flu_stpwr == stpwrO5) {
979  eps = 1 - Ee/Eb;
980  }
981  lnEmid = log(0.5*(Eb+Ee));
982  }
983 
984  EGS_Float dedxmid_i = dedx_i[imed].interpolate(lnEmid);
985  // Used in cavity:
986  // EGS_Float dedxmid_i = 1./i_dedx[imed].interpolate(lnEmid);
987 #ifdef DEBUG
988  if (!isfinite(dedxmid_i)) {
989  if (isnan(dedxmid_i)) {
990  egsInformation("\n Is NaN? dedxmid_i = %g",dedxmid_i);
991  }
992  else {
993  egsInformation("\n Is infinite? dedxmid_i = %g",dedxmid_i);
994  }
995  }
996  else {
997  if (dedxmid_i<0) {
998  egsInformation("\n Is negative? dedxmid_i = %g Emid = %g lnEmid = %g index = %d",
999  dedxmid_i,exp(lnEmid),lnEmid, dedx_i[imed].getIndex(lnEmid));
1000  }
1001  if (dedxmid_i > 1.E10) {
1002  egsInformation("\n Is very large? dedxmid_i = %g Emid = %g lnEmid = %g",dedxmid_i,exp(lnEmid),lnEmid);
1003  }
1004 
1005  }
1006 #endif
1007  /* O(eps^3) approach */
1008  if (flu_stpwr == stpwr) {
1009  return dedxmid_i;
1010  }
1011 
1012  /* O(eps^5) approach */
1013  EGS_Float b = i_dedx[imed].get_b(i_dedx[imed].getIndexFast(lnEmid));
1014  EGS_Float aux = b*dedxmid_i;
1015  aux = aux*(1+2*aux)*pow(eps/(2-eps),2)/6;
1016  //aux = aux*(1+2*aux)*eps*eps/((2-eps)*(2-eps))*0.16666666667;
1017  stpFrac = dedxmid_i*(1+aux);
1018  return stpFrac;
1019  }
1020 
1021 
1022  void setCurrentCase(EGS_I64 ncase) {
1023  if (ncase != current_ncase) {
1024  current_ncase = ncase;
1025  fluT->setHistory(ncase);
1026  if (score_primaries) {
1027  fluT_p->setHistory(ncase);
1028  }
1029  if (score_spe) {
1030  for (int j = 0; j < nreg; j++) {
1031  if (is_sensitive[j]) {
1032  flu[j]->setHistory(ncase);
1033  }
1034  }
1035  if (score_primaries) {
1036  for (int j = 0; j < nreg; j++) {
1037  if (is_sensitive[j]) {
1038  flu_p[j]->setHistory(ncase);
1039  }
1040  }
1041  }
1042  }
1043  }
1044 #ifdef DEBUG
1045  binDist->setHistory(ncase);
1046  if (scoring_charge) {
1047  stepDist->setHistory(ncase);
1048  relStepDiff->setHistory(ncase);
1049  }
1050 #endif
1051 
1052  };
1053  void resetCounter() {
1054  current_ncase = 0;
1055  fluT->reset();
1056  if (score_primaries) {
1057  fluT_p->reset();
1058  }
1059  if (score_spe) {
1060  for (int j = 0; j < nreg; j++) {
1061  if (is_sensitive[j]) {
1062  flu[j]->reset();
1063  }
1064  }
1065 
1066  if (score_primaries) {
1067  for (int j = 0; j < nreg; j++) {
1068  if (is_sensitive[j]) {
1069  flu_p[j]->reset();
1070  }
1071  }
1072  }
1073  }
1074 #ifdef DEBUG
1075  binDist->reset();
1076  if (scoring_charge) {
1077  stepDist->reset();
1078  relStepDiff->reset();
1079  }
1080 #endif
1081  }
1082 
1083  bool storeState(ostream &data) const;
1084 
1085  bool setState(istream &data);
1086 
1087  bool addState(istream &data);
1088 
1089 private:
1090 
1091  /*******************************************/
1092  /* Charged particle fluence: Required data */
1093  /*******************************************/
1094  EGS_Interpolator *i_dedx; // stopping power for each medium
1095  EGS_Interpolator *dedx_i; // inverse stopping power for each medium
1096  EGS_Float *Lmid_i; // pre-computed inverse of bin midpoint stpwr
1097  eFluType flu_stpwr; // flurz => ave. stpwr = edep/tvstep,
1098  // stpwr => 3rd order in edep/Eb,
1099  // stpwrO5 => 5th order in edep/Eb
1100  /**************************************************************
1101  * Parameters required for calculations on a log-scale
1102  * The main issue here is that the bin width is not constant
1103  *************************************************************/
1104  EGS_Float r_const; // inverse of (Emax/Emin)**1/flu_nbin - 1 = exp(binwidth)-1
1105  EGS_Float *a_const; // constant needed to determine bin fractions on log scale
1106  EGS_Float *DE; // bin width of logarithmic scale
1107  /*****************************************************************/
1108 
1109  EGS_I64 eCases;
1110 
1111  vector<EGS_Float> volume; // volume of each scoring region
1112  /* Energy grid inputs */
1113  //EGS_Float flu_a_i;
1114  /* Auxiliary input variables*/
1115  vector <EGS_Float> vol_list; // Input list of region volumes
1116 
1117 #ifdef DEBUG
1118  /* Debugging information */
1119  int one_bin, multi_bin;
1120  EGS_ScoringArray *binDist;
1121  EGS_ScoringArray *stepDist;
1122  EGS_ScoringArray *relStepDiff; // Relative difference between tvstep and edep-derived step
1123  EGS_Float max_step;
1124  EGS_Float step_a, step_b;
1125  EGS_I32 n_step_bins;
1126 #endif
1127 
1128 };
1129 
1130 #endif
A class for scoring an array of quantities (e.g. a dose distribution) in a Monte Carlo simulation...
Definition: egs_scoring.h:219
ParticleType
EGS_AusgabObject interface class header file.
after a Compton scattering event
Ausgab object for scoring fluence at circular or rectangular fields.
AusgabCall
Possible calls to the user scoring function ausgab().
A class representing 3D vectors.
Definition: egs_vector.h:56
after a bremsstrahlung interaction
A structure holding the information of one particle.
after annihilation in flight
after an inelastic collision (e+)
user requested discard
after coherent scattering
after a photo-absorption event
Base class for fluence scoring.
EGS_InfoFunction EGS_EXPORT egsFatal
Always use this function for reporting fatal errors.
after an inelastic collision (e-)
EGS_InfoFunction EGS_EXPORT egsInformation
Always use this function for reporting the progress of a simulation and any other type of information...
A class for fast run-time interpolations.
An object factory.
Ausgab object for scoring fluence in arbitrary geometry regions.
EGS_AffineTransform and EGS_RotationMatrix class header file.
void score(int ireg, EGS_Float f)
Add f to the score in the element ireg.
Definition: egs_scoring.h:244
after pair production
EGS_Float x
x-component
Definition: egs_vector.h:60
after annihilation at rest
EGS_Float getStepPerEnergyLoss(const int &imed, const EGS_Float &Eb, const EGS_Float &Ee)
A class for storing information in a tree-like structure of key-value pairs. This class is used throu...
Definition: egs_input.h:182
EGS_ScoringSingle and EGS_ScoringArray class header file.
EGS_Interpolator class header file.
Base class for advanced EGSnrc C++ applications.