EGSnrc C++ class library  Report PIRS-898 (2021)
Iwan Kawrakow, Ernesto Mainegra-Hing, Frederic Tessier, Reid Townson and Blake Walters
beam_dose_scoring.cpp
Go to the documentation of this file.
1 /*
2 ###############################################################################
3 #
4 # EGSnrc egs++ beampp dose 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, 2014
25 #
26 # Contributors:
27 #
28 ###############################################################################
29 #
30 # A dose scoring ausgab object for beampp: Allows the user to score dose in
31 # specified CMs on a region-by-region and/or medium-by-medium basis. Volumes
32 # of all regions are assumed to be 1 cm^3 unless explicitly specified by the
33 # user.
34 #
35 ###############################################################################
36 */
37 
38 
44 #include <fstream>
45 #include <string>
46 
47 #include "beam_dose_scoring.h"
48 #include "egs_input.h"
49 #include "egs_functions.h"
50 
51 BEAM_DoseScoring::BEAM_DoseScoring(const string &Name,
52  EGS_ObjectFactory *f) :
53  EGS_AusgabObject(Name,f), nreg(0), m_lastCase(-1), nmedia(0),
54  dose(0), doseM(0), max_dreg(-1), max_medl(0),
55  score_medium_dose(false), score_region_dose(false) {
56  otype = "BEAM_DoseScoring";
57 }
58 
59 BEAM_DoseScoring::~BEAM_DoseScoring() {
60  if (dose) {
61  delete dose;
62  }
63  if (doseM) {
64  delete doseM;
65  }
66 }
67 
68 void BEAM_DoseScoring::setApplication(EGS_Application *App) {
69 
70  app=App;
71  bapp = dynamic_cast<BEAMpp_Application *>(app);
72  if (!bapp) {
73  return;
74  }
75  // Get the number of regions in the geometry.
76  nreg = app->getnRegions();
77  // Get the number of media in the input file
78  nmedia = app->getnMedia();
79  // Get list of regions for which to score dose;
80  int d_start,d_end;
81  // first, clear the array of media indices in the dose CMs
82  for (int i=0; i<d_cms.size(); i++) {
83  vector <int> med_ind;
84  for (int j=0; j<nmedia; j++) {
85  med_ind.push_back(-1);
86  }
87  cm_med.push_back(med_ind);
88  }
89  for (int i=0; i<d_cms.size(); i++) {
90  if (d_cms[i]==0) {
91  d_start = 0;
92  }
93  else {
94  d_start = bapp->CM_reg_end(d_cms[i]-1)+1;
95  }
96  d_end = bapp->CM_reg_end(d_cms[i]);
97  for (int j=d_start; j<=d_end; j++) {
98  //note we need to use IsRegionReal instead of isRealRegion because
99  //the latter registers virtual regions as real in beampp
100  if (bapp->IsRegionReal(j)) {
101  d_region.push_back(j);
102  cm_med[i][app->getMedium(j)]=1;
103  }
104  }
105  }
106  // determine maximum medium name length
107  char buf[32];
108  int count = 0;
109  int imed=0;
110  for (imed=0; imed < nmedia; imed++) {
111  sprintf(buf,"%s%n",app->getMediumName(imed),&count);
112  if (count > max_medl) {
113  max_medl = count;
114  }
115  }
116  // Flag dose scoring regions in geometry
117  // and set their volume.
118  if (d_region.size()) { // specific dose regions provided
119  // Get maximum dose scoring region
120  for (vector<int>::iterator it = d_region.begin(); it < d_region.end(); it++) {
121  if (*it > max_dreg) {
122  max_dreg = *it;
123  }
124  }
125  for (int j=0; j<nreg; j++) {
126  d_reg_index.push_back(-1);
127  d_reg_cm_ind.push_back(-1);
128  vol.push_back(1.0);// set to 1.0
129  }
130  for (int i=0; i<d_region.size(); i++) {
131  d_reg_index[d_region[i]]=i;
132  if (d_region[i] < vol_list.size()) { //check to make sure we won't exceed array size
133  vol[d_region[i]] = vol_list[d_region[i]];
134  }
135  for (int j=0; j<d_cms.size(); j++) {
136  if (d_region[i]<=bapp->CM_reg_end(d_cms[j])) {
137  d_reg_cm_ind[d_region[i]]=j;
138  break;
139  }
140  }
141  }
142  if (score_region_dose) {
143  dose = new EGS_ScoringArray(d_region.size());
144  }
145  }
146  // If requested request memory for medium dose in each CM
147  if (score_medium_dose) {
148  doseM = new EGS_ScoringArray(nmedia*d_cms.size());
149  }
150 
151  description = "\n*******************************************\n";
152  description += "BEAM Dose Scoring Object (";
153  description += name;
154  description += ")\n";
155  description += "*******************************************\n";
156  description +="\n Dose will be calculated in CM no.'s (start region - end region):\n";
157  for (int i=0; i<d_cms.size(); i++) {
158  if (d_cms[i]==0) {
159  sprintf(buf,"%d (0 - %d)\n",d_cms[i],bapp->CM_reg_end(d_cms[i]));
160  }
161  else {
162  sprintf(buf,"%d (%d - %d)\n",d_cms[i],bapp->CM_reg_end(d_cms[i]-1)+1,bapp->CM_reg_end(d_cms[i]));
163  }
164  description += buf;
165  }
166  description += "\n";
167  if (dose) {
168  description += " - Region dose will be calculated\n";
169  }
170  if (doseM) {
171  description += " - Medium dose will be calculated\n";
172  }
173  description += "\n--------------------------------------\n";
174  sprintf(buf,"%*s %*s rho/[g/cm**3]\n",max_medl/2,"medium",max_medl/2," ");
175  description += buf;
176  description += "--------------------------------------\n";
177  for (imed=0; imed < nmedia; imed++) {
178  sprintf(buf,"%-*s",max_medl,app->getMediumName(imed));
179  description += buf;
180  description += " ";
181  sprintf(buf,"%5.2f",app->getMediumRho(imed));
182  description += buf;
183  description += "\n";
184  }
185  description += "\n*******************************************\n\n";
186  if (d_region.size()) {
187  d_region.clear();
188  }
189 }
190 
191 void BEAM_DoseScoring::reportResults() {
192  egsInformation("\n======================================================\n");
193  egsInformation("BEAM Dose Scoring Object(%s)\n",name.c_str());
194  egsInformation("======================================================\n");
195  EGS_Float normD = 1., normE=1.;
196  int count = 0;
197  EGS_Float F = app->getFluence();
198  egsInformation("=> last case = %lld fluence = %g\n", m_lastCase, F);
199  /* Normalize to actual source fluence */
200  egsInformation("\n Dose output for CM no.'s:\n");
201  for (int i=0; i<d_cms.size(); i++) {
202  egsInformation(" %d \n",d_cms[i]);
203  }
204  normE = m_lastCase/F;
205  normD = 1.602e-10*normE;
206  int irmax_digits = getDigits(max_dreg);
207  string line;
208  double r,dr;
209  if (dose) {
210  if (normE==1) {
211  egsInformation("\n\n==> Summary of region dosimetry (per particle)\n");
213  "CM %-*s %-*s %-*s rho/[g/cm3] V/cm3 Edep/[MeV] D/[Gy] %n\n",
214  irmax_digits,"ir",irmax_digits,"CM reg.",max_medl,"medium",&count);
215  }
216  else {
217  egsInformation("\n==> Summary of region dosimetry (per fluence)\n");
219  "CM %-*s %-*s %-*s rho/[g/cm3] V/cm3 Edep/[MeV*cm2] D/[Gy*cm2] %n\n",
220  irmax_digits,"ir",irmax_digits,"CM reg.",max_medl,"medium",&count);
221  }
222  line.append(count,'-');
223  egsInformation("%s\n",line.c_str());
224  /* Compute deposited energy and dose */
225  int ir_cm,fr_cm;
226  for (int i=0; i<d_cms.size(); i++) {
227  if (d_cms[i]==0) {
228  ir_cm=0;
229  }
230  else {
231  ir_cm = bapp->CM_reg_end(d_cms[i]-1)+1;
232  }
233  fr_cm = bapp->CM_reg_end(d_cms[i]);
234  for (int ireg = ir_cm; ireg <= fr_cm; ireg++) {
235  if (d_reg_index[ireg]>=0) {
236  if (!(app->isRealRegion(ireg))) {
237  continue;
238  }
239  int imed = app->getMedium(ireg);
240  EGS_Float rho = app->getMediumRho(imed);
241  EGS_Float mass = vol[ireg]*rho;
242  dose->currentResult(d_reg_index[ireg],r,dr);
243  if (r > 0) {
244  dr = dr/r;
245  }
246  else {
247  dr=1;
248  }
249  egsInformation("%-2d %-*d %-*d %-*s %7.3f %7.3f %10.4e +/- %-7.3f%% %10.4e +/- %-7.3f%%\n",
250  d_cms[i],max(irmax_digits,2),ireg,max(irmax_digits,7),ireg-ir_cm,max_medl,app->getMediumName(imed),rho,vol[ireg],r*normE,dr*100.,r*normD/mass,dr*100.);
251  }
252  }
253  egsInformation("%s\n",line.c_str());
254  }
255  }
256  if (doseM) {
257  vector<EGS_Float> massM(d_cms.size()*nmedia,0);
258  int imed = 0;
259  for (int ir=0; ir<nreg; ir++) {
260  if (d_reg_index[ir]>=0) {
261  imed = app->getMedium(ir);
262  massM[imed+d_reg_cm_ind[ir]*nmedia] += app->getMediumRho(imed)*vol[ir];
263  }
264  }
265  if (normE==1) {
266  egsInformation("\n\n==> Summary of media dosimetry (per particle)\n");
268  "CM %*s %*s Edep/[MeV] D/[Gy] %n\n",
269  max_medl/2,"medium",max_medl/2," ",&count);
270  }
271  else {
272  egsInformation("\n\n==> Summary of media dosimetry (per fluence)\n");
274  "CM %*s %*s Edep/[MeV*cm2] D/[Gy*cm2] %n\n",
275  max_medl/2,"medium",max_medl/2," ",&count);
276  }
277  line="";
278  line.append(count,'-');
279  egsInformation("%s\n",line.c_str());
280  /* Compute deposited energy in medium (MeV)*/
281  for (int i=0; i<d_cms.size(); i++) {
282  for (int im=0; im<nmedia; im++) {
283  doseM->currentResult(im+i*nmedia,r,dr);
284  if (cm_med[i][im] >= 0) {
285  if (r > 0) {
286  dr = dr/r;
287  }
288  else {
289  dr=1;
290  }
292  "%-2d %-*s %10.4e +/- %-7.3f%% %10.4e +/- %-7.3f%%\n",
293  d_cms[i],max_medl,app->getMediumName(im),r*normE,dr*100.,r*normD/massM[im+i*nmedia],dr*100.);
294  }
295  }
296  egsInformation("%s\n",line.c_str());
297  }
298  }
299  egsInformation("\n======================================================\n");
300 }
301 
302 bool BEAM_DoseScoring::storeState(ostream &data) const {
303  //egsInformation("Storing BEAM_DoseScoring...\n");
304  if (!egsStoreI64(data,m_lastCase)) {
305  return false;
306  }
307  data << endl;
308  if (dose && !dose->storeState(data)) {
309  return false;
310  }
311  if (doseM && !doseM->storeState(data)) {
312  return false;
313  }
314  return true;
315 }
316 
317 bool BEAM_DoseScoring::setState(istream &data) {
318  if (!egsGetI64(data,m_lastCase)) {
319  return false;
320  }
321  if (dose && !dose->setState(data)) {
322  return false;
323  }
324  if (doseM && !doseM->setState(data)) {
325  return false;
326  }
327  return true;
328 }
329 
330 bool BEAM_DoseScoring::addState(istream &data) {
331  int err = addTheStates(data);
332  if (err) {
333  egsInformation("Error code: %d",err);
334  return false;
335  }
336  return true;
337 }
338 
339 int BEAM_DoseScoring::addTheStates(istream &data) {
340  EGS_I64 tmp_case;
341  if (!egsGetI64(data,tmp_case)) {
342  return 4401;
343  }
344  m_lastCase += tmp_case;
345  if (dose) {
346  EGS_ScoringArray tmp(nreg);
347  if (!tmp.setState(data)) {
348  return 4402;
349  }
350  (*dose) += tmp;
351  }
352  if (doseM) {
353  EGS_ScoringArray tmpM(nmedia);
354  if (!tmpM.setState(data)) {
355  return 4403;
356  }
357  (*doseM) += tmpM;
358  }
359  return 0;
360 }
361 
362 void BEAM_DoseScoring::resetCounter() {
363  m_lastCase = 0;
364  if (dose) {
365  dose->reset();
366  }
367  if (doseM) {
368  doseM->reset();
369  }
370 }
371 
372 
373 extern "C" {
374 
375  BEAM_DOSE_SCORING_EXPORT EGS_AusgabObject *createAusgabObject(EGS_Input *input,
376  EGS_ObjectFactory *f) {
377  const static char *func = "createAusgabObject(beam_dose_scoring)";
378  if (!input) {
379  egsWarning("%s: null input?\n",func);
380  return 0;
381  }
382  /* get CMs to score dose in */
383  vector <int> d_cms;
384  int err1=input->getInput("dose CMs",d_cms);
385  if (err1) {
386  egsWarning("%s: No CMs input. Dose will not be scored.\n",func);
387  return 0;
388  }
389  /* get dose scoring mode: region dose, medium dose or both */
390  vector<string> allowed_mode;
391  allowed_mode.push_back("no");
392  allowed_mode.push_back("yes");
393  int d_in_medium = input->getInput("medium dose",allowed_mode,0);
394  int d_in_region = input->getInput("region dose",allowed_mode,1);
395  if (d_in_medium == 0 && d_in_region == 0) {
396  egsWarning("%s: Neither dose in regions nor dose in medium specified. Dose will not be scored.\n",func);
397  return 0;
398  }
399  vector <int> vreg_start,vreg_stop;
400  vector <EGS_Float> v_in,volin;
401  //give the user the option to input volumes of regions if they know them
402  int err2 = input->getInput("start volume region",vreg_start);
403  int err3 = input->getInput("stop volume region",vreg_stop);
404  int err4 = input->getInput("volume",v_in);
405  if (err4) {
406  egsWarning("%s: No dose zone volumes input. Will assume 1 cm^3 for all regions.\n",func);
407  }
408  else {
409  if (!err2 && !err3) {
410  if (vreg_start.size()==vreg_stop.size()) {
411  if (v_in.size()<vreg_start.size()) {
412  egsWarning("%s: No volumes input for region groups %d to %d.\n Will use last input volume for remaining groups.\n",func,v_in.size()+1,vreg_start.size());
413  for (int i=v_in.size()+1; i<vreg_start.size(); i++) {
414  v_in.push_back(v_in[v_in.size()-1]);
415  }
416  }
417  for (int i=0; i<vreg_start.size(); i++) {
418  if (volin.size()<=vreg_stop[i]) {
419  //enlarge to volin array
420  for (int j=volin.size(); j<=vreg_stop[i]; j++) {
421  volin.push_back(1.0);
422  }
423  }
424  for (int j=vreg_start[i]; j<=vreg_stop[i]; j++) {
425  volin[j]=v_in[i];
426  }
427  }
428  }
429  else {
430  egsWarning("%s: Unequal number of start and stop regions. Will assume 1 cm^3 for all regions.\n",func);
431  }
432  }
433  }
434  //=================================================
435 
436  /* Setup dose scoring object with input parameters */
437  BEAM_DoseScoring *result = new BEAM_DoseScoring("",f);
438  if (volin.size()) {
439  result->setVol(volin);
440  }
441  else {
442  result->setVol(1.0);
443  }
444  result->setDoseCMs(d_cms);
445  if (d_in_medium) {
446  result->setMediumScoring(true);
447  }
448  if (d_in_region) {
449  result->setRegionScoring(true);
450  }
451  result->setName(input);
452  return result;
453  }
454 
455 }
456 
EGS_ScoringArray * dose
Scoring in each dose scoring region.
A class for scoring an array of quantities (e.g. a dose distribution) in a Monte Carlo simulation...
Definition: egs_scoring.h:219
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, false on failure.
string description
A short ausgab object description.
EGS_Input class header file.
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, false on failure.
Global egspp functions header file.
EGS_ScoringArray * doseM
Scoring dose in each medium.
bool setState(istream &data)
Sets the state fof the scoring array object from the data in the input stream data.
Definition: egs_scoring.h:340
bool storeState(ostream &data)
Stores the state of the scoring array object into the data stream data.
Definition: egs_scoring.h:316
bool isRealRegion(int ireg)
Returns true if ireg is a real region, false otherwise.
A dose scoring object: header.
EGS_InfoFunction EGS_EXPORT egsInformation
Always use this function for reporting the progress of a simulation and any other type of information...
An object factory.
void reset()
Reset the scoring array to a pristine state.
Definition: egs_scoring.h:368
void currentResult(int ireg, double &r, double &dr)
Sets r to the result in region ireg and dr to its statistical uncertainty.
Definition: egs_scoring.h:280
A dose scoring ausgab object for beampp.
int getMedium(int ireg)
Returns the medium index in region ireg using C-style indexing.
EGS_I64 m_lastCase
The event set via setCurrentCase()
void setName(EGS_Input *inp)
Set the name of the object from the information provided by inp.
string name
The object 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:338
Base class for advanced EGSnrc C++ applications.
EGS_Application * app
The application this object belongs to.
EGS_InfoFunction EGS_EXPORT egsWarning
Always use this function for reporting warnings.