44 #define REGIONS_ENTRIES 100
45 #define REGIONS_PER_LINE 25
49 scoring_charge(photon), source_charge(unknown),
50 n_scoring_regions(0), n_source_regions(0),
51 max_reg(-1), active_region(-1),
52 flu_s(0), flu_nbin(128), flu_xmin(0.001), flu_xmax(1.0),
53 norm_u(1.0), flu(0), fluT(0), flu_p(0), fluT_p(0), current_ncase(0),
54 verbose(false), score_primaries(false), score_spe(false),
55 m_primary(0.0), m_tot(0.0) {
56 otype =
"EGS_FluenceScoring";
58 flu_a /= (flu_xmax - flu_xmin);
59 flu_b = -flu_xmin*flu_a;
78 void EGS_FluenceScoring::initScoring(
EGS_Input *inp) {
86 int the_selection = 0;
87 name.push_back(
"photon");
88 name.push_back(
"electron");
89 name.push_back(
"positron");
90 name.push_back(
"undefined");
91 the_selection = inp->
getInput(
"scoring particle",
name, 3);
92 switch (the_selection) {
94 particle_name=
"photon";
95 scoring_charge = photon;
98 particle_name=
"electron";
99 scoring_charge = electron;
102 particle_name=
"positron";
103 scoring_charge = positron;
106 egsFatal(
"\n******* ERROR *******\n"
107 " Undefined scoring charge!\n"
109 "************************\n");
112 the_selection = inp->
getInput(
"source particle",
name, 3);
113 switch (the_selection) {
115 source_charge = photon;
118 source_charge = electron;
121 source_charge = positron;
124 source_charge = unknown;
127 vector<string> choice;
128 choice.push_back(
"no");
129 choice.push_back(
"yes");
130 verbose = inp->
getInput(
"verbose", choice,0);
131 score_primaries = inp->
getInput(
"score primaries",choice,0);
132 score_spe = inp->
getInput(
"score spectrum", choice,0);
135 int err_norm = inp->
getInput(
"normalization",norma);
144 EGS_Float flu_Emin, flu_Emax;
147 int err_n = eGrid->
getInput(
"number of bins",flu_nbin);
148 int err_i = eGrid->
getInput(
"minimum kinetic energy",flu_Emin);
149 int err_f = eGrid->
getInput(
"maximum kinetic energy",flu_Emax);
150 if (err_n)
egsFatal(
"\n**** EGS_FluenceScoring::initScoring"
151 " Missing input: number of bins.\n"
153 if (err_i)
egsFatal(
"\n**** EGS_FluenceScoring::initScoring"
154 " Missing input: minimum kinetic energy.\n"
156 if (err_f)
egsFatal(
"\n**** EGS_FluenceScoring::initScoring"
157 " Missing input: maximum kinetic energy.\n"
161 vector<string> scale;
162 scale.push_back(
"linear");
163 scale.push_back(
"logarithmic");
164 flu_s = eGrid->
getInput(
"scale",scale,0);
170 flu_xmin = log(flu_Emin);
171 flu_xmax = log(flu_Emax);
174 flu_a /= (flu_xmax - flu_xmin);
175 flu_b = -flu_xmin*flu_a;
190 vector <int> s_start, s_stop;
197 if (inp->
getInput(
"source regions",s_regionsString) || s_regionsString.length()<=0) {
198 int err1 = inp->
getInput(
"start source region",s_start);
199 int err2 = inp->
getInput(
"stop source region",s_stop);
200 if (!err1 && !err2) {
201 if (s_start.size() == s_stop.size()) {
202 for (
int i=0; i<s_start.size(); i++) {
203 int ir = s_start[i], fr = s_stop[i];
205 egsFatal(
"\nEGS_FluenceScoring::initScoring: \n"
206 " Decreasing start (%d) / stop %d region in source region group %d\n"
207 " Aborting!\n\n", ir, fr, i);
208 for (
int ireg=ir; ireg<=fr; ireg++) {
209 s_region.push_back(ireg);
214 "\nEGS_FluenceScoring::initScoring: \n"
215 " Mismatch in number of start (%d) and stop (%d)\n"
216 " source region groups. Aborting!\n",
217 s_start.size(),s_stop.size());
223 void EGS_FluenceScoring::getSensitiveRegions(
EGS_Input *inp) {
225 string listLabel, startLabel, stopLabel;
227 if (
otype ==
"EGS_PlanarFluence") {
228 listLabel =
"contributing regions";
229 startLabel =
"start contributing region";
230 stopLabel =
"stop contributing region";
232 else if (
otype ==
"EGS_VolumetricFluence") {
233 listLabel =
"scoring regions";
234 startLabel =
"start region";
235 stopLabel =
"stop region";
238 egsFatal(
"\n*** Unknown fluence scoriung type! Aborting!\n\n");
242 if (!inp->
getInput(listLabel,f_regionsString) && f_regionsString.length()>0) {
244 if (f_regionsString ==
"ALL") {
245 score_in_all_regions =
true;
248 score_in_all_regions =
false;
252 int err1 = inp->
getInput(startLabel,f_start);
253 int err2 = inp->
getInput(stopLabel, f_stop);
254 if (!err1 && !err2) {
255 if (f_start.size() == f_stop.size()) {
256 for (
int i=0; i<f_start.size(); i++) {
257 int ir = f_start[i], fr = f_stop[i];
259 egsFatal(
"\nEGS_FluenceScoring::initScoring: \n"
260 " Decreasing start (%d) / stop (%d) in region group %d\n"
261 " Aborting!\n\n", ir, fr, i);
262 for (
int ireg=ir; ireg<=fr; ireg++) {
263 f_region.push_back(ireg);
266 score_in_all_regions =
false;
269 "\nEGS_FluenceScoring::initScoring: \n"
270 " Mismatch in number of start (%d) and stop (%d)\n"
271 " region groups. Aborting!\n",
272 f_start.size(),f_stop.size());
277 void EGS_FluenceScoring::getNumberRegions(
const string &str, vector<int> ®s) {
279 egsFatal(
"EGS_FluenceScoring::getNumberRegions\n"
280 " Undefined parent application! Aborting!\n");
285 void EGS_FluenceScoring::getLabelRegions(
const string &str, vector<int> ®s) {
287 egsFatal(
"EGS_FluenceScoring::getLabelRegions\n"
288 " Undefined parent application! Aborting!\n");
293 void EGS_FluenceScoring::setUpRegionFlags() {
295 if (s_regionsString.length() > 0 && !s_region.size()) {
296 getNumberRegions(s_regionsString, s_region);
297 getLabelRegions(s_regionsString, s_region);
300 n_source_regions = s_region.size() < nreg ? s_region.size() : nreg;
302 if (!score_in_all_regions) {
303 if (f_regionsString.length() > 0 && !f_region.size()) {
304 getNumberRegions(f_regionsString, f_region);
305 getLabelRegions(f_regionsString, f_region);
308 n_scoring_regions = f_region.size() < nreg ? f_region.size() : nreg;
310 else if (score_in_all_regions) {
311 n_scoring_regions = nreg;
312 for (
int j=0; j<nreg; j++) {
313 f_region.push_back(j);
317 if (n_source_regions == nreg && score_primaries)
318 egsWarning(
"=> Warning: Setting n_source_regions = nreg \n"
319 " effectively supresses classification\n"
320 " of primaries and secondaries!");
321 for (
int i = 0; i < n_source_regions; i++) {
322 is_source[s_region[i]] =
true;
325 for (
int i = 0; i < n_scoring_regions; i++) {
326 is_sensitive[f_region[i]] =
true;
327 if (f_region[i] > max_reg) {
328 max_reg = f_region[i];
333 void EGS_FluenceScoring::describeMe() {
338 if (n_scoring_regions == nreg) {
342 int start = 0, stop = 0, k = 0, entries = 0;
345 while (k < nreg && entries < REGIONS_ENTRIES) {
347 if (is_sensitive[k]) {
350 while (is_sensitive[k] && k < nreg) {
355 sprintf(buf,
"%d-%d",start,stop);
357 else if (k % REGIONS_PER_LINE) {
358 sprintf(buf,
" %d",start);
361 sprintf(buf,
" %d\n",start);
364 if (entries == REGIONS_ENTRIES) {
365 sprintf(buf,
"... %d\n",max_reg);
377 if (score_primaries) {
378 if (source_charge == unknown) {
379 source_charge = scoring_charge;
380 description +=
" - Unknown source charge due to multi-particle source\n";
381 description +=
" and no user input defining source particle type!\n";
387 sprintf(buf,
"%d\n",source_charge);
393 EGS_Float Emin = flu_s ? exp(flu_xmin):flu_xmin,
394 Emax = flu_s ? exp(flu_xmax):flu_xmax;
395 sprintf(buf,
"%g MeV and %g MeV energy range",Emin,Emax);
412 otype =
"EGS_PlanarFluence";
419 m_d = m_normal*m_midpoint;
426 for (
int j=0; j<Nx*Ny; j++) {
431 for (
int j=0; j<Nx*Ny; j++) {
451 if (source_charge == unknown) {
457 nreg =
app->getnRegions();
460 for (
int j=0; j<nreg; j++) {
462 if (!score_in_all_regions) {
463 is_sensitive.push_back(
false);
466 is_sensitive.push_back(
true);
469 is_source.push_back(
false);
479 for (
int j = 0; j < Nx*Ny; j++) {
484 if (score_primaries) {
488 for (
int j = 0; j < Nx*Ny; j++) {
497 void EGS_PlanarFluence::initScoring(
EGS_Input *inp) {
507 if (! pScoringInput) {
508 egsFatal(
"AO type %s: Missing planar scoring input?\n",
otype.c_str());
513 EGS_FluenceScoring::initScoring(inp);
516 score_in_all_regions =
true;
517 EGS_FluenceScoring::getSensitiveRegions(pScoringInput);
520 vector<EGS_Float> tmp_field;
521 int err2 = pScoringInput->
getInput(
"scoring circle",tmp_field);
523 int err3 = pScoringInput->
getInput(
"scoring rectangle",tmp_field);
524 if (err3 || tmp_field.size() != 4) {
526 "\n\n*** Wrong/missing 'scoring rectangle' input "
527 "setting it to 10 cm X 10 cm field at origin!\n\n");
531 field_type = rectangle;
535 EGS_Float xmin = tmp_field[0],xmax = tmp_field[1],
536 ymin = tmp_field[2],ymax = tmp_field[3];
538 m_midpoint =
EGS_Vector((xmax+xmin)/2.,(ymax+ymin)/2.,0);
556 int err4 = pScoringInput->
getInput(
"resolution",screen);
561 "\n\n*** Missing/wrong 'resolution' input "
562 " Scoring in the whole field\n\n");
565 else if (screen.size()==1) {
569 else if (screen.size()==2) {
573 else if (screen.size()> 2) {
577 "\n\n*** Too many 'resolution' inputs\n"
578 " Using first two entries\n\n");
586 field_type = rectangle;
590 else if (tmp_field.size() != 4) {
592 "\n\n*** Wrong/missing 'scoring circle' input "
593 "setting it to 10 cm diameter field at origin!\n\n");
601 vector<EGS_Float> tmp_normal;
602 int err1 = pScoringInput->
getInput(
"scoring plane normal",tmp_normal);
603 if (err1 || tmp_normal.size() != 3) {
605 "\n\n*** Wrong/missing 'scoring plane normal' input. "
606 "Set along positive z-axis\n\n");
610 m_normal =
EGS_Vector(tmp_normal[0],tmp_normal[1],
612 m_normal.normalize();
614 m_midpoint =
EGS_Vector(tmp_field[0],tmp_field[1],
617 m_R2 = tmp_field[3]*tmp_field[3];
622 m_d = m_normal*m_midpoint;
627 sprintf(buf,
"\nPlanar %s fluence scoring\n",particle_name.c_str());
629 description +=
"================================\n";
632 sprintf(buf,
"(%g %g %g)\n",m_normal.
x,m_normal.
y,m_normal.
z);
635 sprintf(buf,
"(%g %g %g)\n",m_midpoint.
x,m_midpoint.
y,m_midpoint.
z);
637 if (field_type == circle) {
639 sprintf(buf,
"%g cm\n",m_R);
642 else if (field_type == rectangle) {
644 sprintf(buf,
"%g cm X %g cm\n",ax,ay);
647 sprintf(buf,
"%d X %d\n",Nx,Ny);
650 description +=
" - scoring field distance from origin = ";
651 sprintf(buf,
"%g cm\n",m_d);
656 EGS_FluenceScoring::describeMe();
660 void EGS_PlanarFluence::score(
const EGS_Particle &p,
const int &ivoxel) {
661 EGS_Float up = p.
u*m_normal, aup = fabs(up);
668 EGS_Float e = p.
q ? p.
E -
app->getRM() : p.
E;
674 EGS_Float auxp = p.
wt/aup;
676 fluT->
score(ivoxel,auxp);
677 if (score_primaries && !p.
latch) {
678 fluT_p->
score(ivoxel,auxp);
681 if (score_spe && e > flu_xmin && e <= flu_xmax) {
682 ae = flu_a*e + flu_b;
689 je = min((
int)ae,flu_nbin-1);
691 if (ivoxel < 0 || ivoxel > Nx*Ny) {
692 egsFatal(
"\n-> Scoring out of bounds, ivoxel = %d\n",ivoxel);
695 if (je < 0 || je >= flu_nbin) {
696 egsFatal(
"\n-> Scoring out of bounds, ibin = %d ae = %g E = %g MeV\n",je,ae,e);
699 if (score_primaries && !p.
latch) {
700 flu_p[ivoxel]->
score(je,auxp);
705 int EGS_PlanarFluence::hitsField(
const EGS_Particle &p, EGS_Float *dist) {
706 if (field_type==circle) {
707 EGS_Float xp = p.
x*m_normal, up = p.
u*m_normal;
708 if ((up > 0 && m_d > xp) ||
709 (up < 0 && m_d < xp)) {
710 EGS_Float t = (m_d - xp)/up;
715 return x1.length2() < m_R*m_R ? 0:-1;
719 else if (field_type == rectangle) {
720 EGS_Float xp = p.
x*m_normal, up = p.
u*m_normal;
721 if ((up > 0 && m_d > xp) || (up < 0 && m_d < xp)) {
722 EGS_Float t = (m_d - xp)/up;
724 EGS_Float xcomp = x1*ux;
725 EGS_Float ycomp = x1*uy;
726 xcomp = 2*xcomp + ax;
727 ycomp = 2*ycomp + ay;
728 if (xcomp > 0 && xcomp < 2*ax &&
729 ycomp > 0 && ycomp < 2*ay) {
730 int i = int(xcomp/(2*vx)),
731 j = int(ycomp/(2*vy)),
746 void EGS_PlanarFluence::ouputPlanarFluence(
EGS_ScoringArray *fT,
const double &norma) {
749 int ix_digits = getDigits(Nx);
750 int iy_digits = getDigits(Ny);
751 int xy_digits = getDigits(Nx*Ny);
753 if (field_type == circle) {
755 "-----------------------------------------------------\n");
759 "-----------------------------------------------------\n",
760 iy_digits,
"iy",ix_digits,
"ix",&count);
762 if (field_type == circle) {
772 egsInformation(
" %10.4le +/- %10.4le [%-7.3lf\%]\n",fe*norma,dfe*norma,dfer);
775 for (
int j=0; j<Ny; j++) {
776 for (
int i=0; i<Nx; i++) {
778 egsInformation(
" %*d %*d %*d ",iy_digits,j,ix_digits,i,xy_digits,k);
786 egsInformation(
" %10.4le +/- %10.4le [%-7.3lf\%]\n",fe*norma,dfe*norma,dfer);
792 void EGS_PlanarFluence::ouputResults() {
794 EGS_Float src_norm = 1.0,
795 Fsrc =
app->getFluence();
796 egsInformation(
"\n\n last case = %lld source particles or fluence = %g\n\n",
797 current_ncase, Fsrc);
800 src_norm = Fsrc/current_ncase;
803 string normLabel = src_norm == 1 ?
"history" :
"MeV-1 cm-2";
804 string src_type =
app->sourceType();
805 if (src_type ==
"EGS_BeamSource") {
806 normLabel =
"primary history";
807 egsInformation(
"\n\n %s normalization = %g (primary histories per particle)\n\n",
808 src_type.c_str(), src_norm);
810 else if (src_type ==
"EGS_CollimatedSource" ||
811 (src_type ==
"EGS_ParallelBeam" && src_norm != 1)) {
812 egsInformation(
"\n\n %s normalization = %g (fluence per particle)\n\n",
813 src_type.c_str(), src_norm);
816 egsInformation(
"\n\n %s normalization = %g (histories per particle)\n\n",
817 src_type.c_str(), src_norm);
822 double norm = 1.0/src_norm;
829 " ================\n\n");
832 ouputPlanarFluence(fluT, norm);
834 if (score_primaries) {
836 ouputPlanarFluence(fluT_p, norm);
841 string suffix =
"_" + particle_name +
".agr";
843 ofstream spe_output(spe_name.c_str(),ios::out);
845 egsFatal(
"\n EGS_PlanarFluence: Error: Failed to open file %s\n",spe_name.c_str());
849 spe_output <<
"# " << particle_name.c_str() <<
" fluence \n";
850 spe_output <<
"# \n";
851 spe_output <<
"@ legend 0.2, 0.8\n";
852 spe_output <<
"@ legend box linestyle 0\n";
853 spe_output <<
"@ legend font 4\n";
854 spe_output <<
"@ xaxis label \"energy / MeV\"\n";
855 spe_output <<
"@ xaxis label char size 1.560000\n";
856 spe_output <<
"@ xaxis label font 4\n";
857 spe_output <<
"@ xaxis ticklabel font 4\n";
858 spe_output <<
"@ yaxis label \"fluence / MeV\\S-1\\Ncm\\S-2\"\n";
859 spe_output <<
"@ yaxis label char size 1.560000\n";
860 spe_output <<
"@ yaxis label font 4\n";
861 spe_output <<
"@ yaxis ticklabel font 4\n";
862 spe_output <<
"@ title \""<< particle_name.c_str() <<
" fluence" <<
"\"\n";
863 spe_output <<
"@ title font 4\n";
864 spe_output <<
"@ title size 1.500000\n";
865 spe_output <<
"@ subtitle \"for each scoring region\"\n";
866 spe_output <<
"@ subtitle font 4\n";
867 spe_output <<
"@ subtitle size 1.000000\n";
870 " ====================\n\n");
874 for (
int j=0; j<Ny; j++) {
875 for (
int i=0; i<Nx; i++) {
880 spe_output<<
"@ s" << i_graph <<
" errorbar linestyle 0\n";
881 spe_output<<
"@ s" << i_graph <<
" legend \""<<
882 "Voxel # " << k <<
"\"\n";
883 spe_output<<
"@target G0.S"<< i_graph <<
"\n";
884 spe_output<<
"@type xydy\n";
888 "---------------------------------------------\n");
890 for (
int l=0; l<flu_nbin; l++) {
892 EGS_Float e = (l+0.5-flu_b)/flu_a;
896 spe_output<<e<<
" "<<fe *norm<<
" "<<dfe *norm<<
"\n";
902 if (score_primaries) {
906 "---------------------------------------------\n");
908 spe_output<<
"@ s" << ++i_graph <<
" errorbar linestyle 0\n";
909 spe_output<<
"@ s" << i_graph <<
" legend \""<<
910 "Voxel # " << k <<
" (primary)\"\n";
911 spe_output<<
"@target G0.S"<< i_graph <<
"\n";
912 spe_output<<
"@type xydy\n";
913 for (
int l=0; l<flu_nbin; l++) {
915 EGS_Float e = (l+0.5-flu_b)/flu_a;
919 spe_output<<e<<
" "<<fe *norm<<
" "<<dfe *norm<<
"\n";
933 void EGS_PlanarFluence::reportResults() {
936 egsInformation(
"======================================================\n");
937 egsInformation(
" Total %ss reaching field: %g\n",particle_name.c_str(),m_tot);
938 egsInformation(
" Primary %ss reaching field: %g\n",particle_name.c_str(),m_primary);
940 egsInformation(
"======================================================\n");
946 bool EGS_PlanarFluence::storeState(ostream &data)
const {
952 data << m_tot <<
" " << m_primary;
963 for (
int j=0; j<Nx*Ny; j++) {
964 if (!flu[j]->storeState(data)) {
970 if (score_primaries) {
975 for (
int j=0; j<Nx*Ny; j++) {
976 if (!flu_p[j]->storeState(data)) {
986 bool EGS_PlanarFluence::setState(istream &data) {
991 data >> m_tot >> m_primary;
1001 for (
int j=0; j<Nx*Ny; j++) {
1002 if (!flu[j]->setState(data)) {
1008 if (score_primaries) {
1015 for (
int j=0; j<Nx*Ny; j++) {
1016 if (!flu_p[j]->setState(data)) {
1026 bool EGS_PlanarFluence::addState(istream &data) {
1031 current_ncase += tmp_case;
1035 EGS_Float tmp_tot, tmp_primary;
1036 data >> tmp_tot >> tmp_primary;
1040 m_primary += tmp_primary;
1047 if (!tgT.setState(data)) {
1054 for (
int j=0; j<Nx*Ny; j++) {
1055 if (!tg.setState(data)) {
1062 if (score_primaries) {
1065 if (!tgT_p.setState(data)) {
1072 for (
int j=0; j<Nx*Ny; j++) {
1073 if (!tg_p.setState(data)) {
1076 (*flu_p[j]) += tg_p;
1093 ,one_bin(0), multi_bin(0), max_step(-100.0), n_step_bins(10000)
1096 otype =
"EGS_VolumetricFluence";
1103 for (
int j=0; j<n_scoring_regions; j++) {
1108 for (
int j=0; j<n_scoring_regions; j++) {
1117 if (scoring_charge) {
1139 if (source_charge == unknown) {
1144 nreg =
app->getnRegions();
1147 for (
int j=0; j<nreg; j++) {
1148 is_sensitive.push_back(
false);
1149 is_source.push_back(
false);
1150 volume.push_back(vol_list[0]);
1157 for (
int i = 0; i < n_scoring_regions; i++) {
1158 if (i < vol_list.size()) {
1159 volume[f_region[i]] = vol_list[i];
1167 for (
int j = 0; j < nreg; j++) {
1168 if (is_sensitive[j]) {
1173 if (score_primaries) {
1177 for (
int j = 0; j < nreg; j++) {
1178 if (is_sensitive[j]) {
1189 EGS_Float flu_Emin = flu_s ? exp(flu_xmin) : flu_xmin,
1190 flu_Emax = flu_s ? exp(flu_xmax) : flu_xmax;
1191 EGS_Float bw = flu_s ?(log(flu_Emax / flu_Emin))/flu_nbin :
1192 (flu_Emax - flu_Emin) /flu_nbin;
1197 if (scoring_charge) {
1202 r_const = 1/(expbw-1);
1203 DE =
new EGS_Float [flu_nbin];
1204 a_const =
new EGS_Float [flu_nbin];
1205 for (
int i = 0; i < flu_nbin; i++) {
1206 DE[i] = flu_Emin*pow(expbw,i)*(expbw-1);
1207 a_const[i] = 1/flu_Emin*pow(1/expbw,i);
1211 if (flu_Emin < app->getEcut() -
app->getRM()) {
1212 flu_Emin =
app->getEcut() -
app->getRM() ;
1215 ceil((log(flu_Emax / flu_Emin))/bw) :
1216 ceil((flu_Emax - flu_Emin) /bw);
1222 int n_media =
app->getnMedia();
1224 EGS_Float lnE, lnEmin, lnEmax, lnEmid;
1228 for (
int j = 0; j < n_media; j++) {
1230 i_dedx[j] = *(
app->getDEDX(j, scoring_charge));
1231 EGS_Float Emin = i_dedx[j].
getXmin();
1232 EGS_Float Emax = i_dedx[j].
getXmax();
1233 int n = 1 + i_dedx[j].
getIndex(Emax);
1234 EGS_Float bwidth = (Emax - Emin)/n;
1236 egsInformation(
"---> stpwr in %s : Emin=%g Emax=%g n=%d bw=%g\n",
1237 app->getMediumName(j), exp(Emin), exp(Emax), n, bwidth);
1240 EGS_Float spwr_i[nbins];
1241 for (
int k = 0; k < nbins; k++) {
1242 spwr_i[k] = 1.0 / i_dedx[j].
interpolate(Emin+k*bwidth);
1244 dedx_i[j].
initialize(nbins, Emin, Emax, spwr_i);
1249 bwidth = (Emax - Emin)/n;
1250 egsInformation(
"---> 1/stpwr in %s : lnEmin=%g lnEmax=%g n=%d bw=%g index(Emax)=%d\n",
1251 app->getMediumName(j), Emin, Emax, n, bwidth, dedx_i[j].getIndexFast(Emax));
1252 for (
int k = 0; k < nbins; k++) {
1255 i_dedx[j].interpolate(Emin + k*bwidth),
1256 dedx_i[j].interpolate(Emin + k*bwidth));
1262 lnEmin = flu_s ? log(0.5*flu_Emin*(expbw+1)) : 0;
1263 Lmid_i =
new EGS_Float [flu_nbin*n_media];
1264 for (
int j = 0; j < n_media; j++) {
1266 EGS_Float med_max_step = 0, logEmax, logEmin;
1268 for (
int i = 0; i < flu_nbin; i++) {
1269 lnEmid = flu_s ? lnEmin + i*bw : log(flu_Emin+bw*(i+0.5));
1270 Lmid_i[i+j*flu_nbin] = 1/i_dedx[j].
interpolate(lnEmid);
1275 logEmin = flu_s ? lnEmin + (i-1)*bw : log(flu_Emin+bw*(i-1));
1276 logEmax = flu_s ? lnEmin + i*bw : log(flu_Emin+bw*i);
1277 if (i_dedx[j].interpolate(logEmax) < i_dedx[j].interpolate(logEmin)) {
1278 med_max_step += 1.02*(exp(logEmax) - exp(logEmin))/i_dedx[j].interpolate(logEmax);
1281 med_max_step += 1.02*(exp(logEmax) - exp(logEmin))*i_dedx[j].interpolate(logEmin);
1287 if (med_max_step > max_step) {
1288 max_step = med_max_step;
1297 EGS_Float RCSDA = max_step;
1301 step_a = n_step_bins/max_step;
1306 egsInformation(
"\n===> RCSDA(%s) = %g cm for Emax = %g MeV, max_step = %g cm bin width = %g cm\n",
1307 app->getMediumName(imed_max_range), RCSDA,
1308 flu_s ? exp(flu_Emax) : flu_Emax, max_step, 1.0/step_a);
1317 void EGS_VolumetricFluence::initScoring(
EGS_Input *inp) {
1327 if (! vScoringInput) {
1328 egsFatal(
"AO type %s: Missing volumetric scoring input?\n",
otype.c_str());
1333 EGS_FluenceScoring::initScoring(inp);
1336 score_in_all_regions =
false;
1337 EGS_FluenceScoring::getSensitiveRegions(vScoringInput);
1340 vector <EGS_Float> v_in;
1341 vScoringInput->
getInput(
"volumes",v_in);
1349 if (! score_in_all_regions && v_in.size() == f_start.size()) {
1351 for (
int i=0; i<f_start.size(); i++) {
1352 int i_r = f_start[i], f_r = f_stop[i];
1353 for (
int ireg=i_r; ireg<=f_r; ireg++) {
1354 vol_list.push_back(v_in[i]);
1358 else if (v_in.size()) {
1362 vol_list.push_back(1.0);
1366 if (scoring_charge) {
1367 vector<string> method;
1368 method.push_back(
"flurz");
1369 method.push_back(
"stpwr");
1370 method.push_back(
"stpwrO5");
1379 sprintf(buf,
"\nVolumetric %s fluence scoring\n",particle_name.c_str());
1381 description +=
"===================================\n";
1385 EGS_FluenceScoring::describeMe();
1387 if (scoring_charge) {
1389 if (flu_stpwr == stpwr) {
1390 description +=
" O(eps^3) approach: accounts for change in stpwr\n";
1391 description +=
" along the step with eps=edep/Emid\n";
1393 else if (flu_stpwr == stpwrO5) {
1394 description +=
" O(eps^5) approach: accounts for change in stpwr\n";
1395 description +=
" along the step with eps=edep/Emid\n";
1399 description +=
" Fluence calculated a-la-FLURZ using Lave=EDEP/TVSTEP.\n";
1403 if (norm_u != 1.0) {
1404 description +=
"\n - Non-unity user-requested normalization = ";
1405 sprintf(buf,
"%g\n",norm_u);
1411 void EGS_VolumetricFluence::ouputVolumetricFluence(
EGS_ScoringArray *fT,
const double &norma) {
1414 int ir_digits = getDigits(nreg);
1419 "-----------------------------------------------------\n");
1420 for (
int k=0; k<nreg; k++) {
1421 if (!is_sensitive[k]) {
1424 double norm = norma/volume[k];
1434 egsInformation(
" %10.4le +/- %10.4le [%-7.3lf%]\n",fe*norm,dfe*norm,dfer);
1438 void EGS_VolumetricFluence::ouputResults() {
1441 EGS_Float src_norm = 1.0,
1442 Fsrc =
app->getFluence();
1443 egsInformation(
"\n\n last case = %lld source particles or fluence = %g\n\n",
1444 current_ncase, Fsrc);
1447 src_norm = Fsrc/current_ncase;
1450 string normLabel = src_norm == 1 ?
"history" :
"MeV-1 cm-2";
1451 string src_type =
app->sourceType();
1452 if (src_type ==
"EGS_BeamSource") {
1453 normLabel =
"primary history";
1454 egsInformation(
"\n\n %s normalization = %g (primary histories per particle)\n\n",
1455 src_type.c_str(), src_norm);
1457 else if (src_type ==
"EGS_CollimatedSource" ||
1458 (src_type ==
"EGS_ParallelBeam" && src_norm != 1)) {
1459 egsInformation(
"\n\n %s normalization = %g (fluence per particle)\n\n",
1460 src_type.c_str(), src_norm);
1463 egsInformation(
"\n\n %s normalization = %g (histories per particle)\n\n",
1464 src_type.c_str(), src_norm);
1468 EGS_Float fbins, d_fbins;
1470 "--------------------------------------\n");
1472 int tot_bins = one_bin + multi_bin;
1473 egsInformation(
"\none_bin = %d [%-7.3lf\%] multi_bin = %d [%-7.3lf\%]\n",
1474 one_bin, 100.0*one_bin/tot_bins, multi_bin,100.0*multi_bin/tot_bins);
1477 int bdigits = getDigits(flu_nbin);
1478 for (
int i=0; i<flu_nbin; i++) {
1479 binDist->currentResult(i,fbins, d_fbins);
1481 d_fbins = 100.0*d_fbins/fbins;
1482 fbins = current_ncase*fbins;
1484 bdigits, i+1, fbins, d_fbins, 100.*fbins/tot_bins);
1488 if (scoring_charge) {
1489 egsInformation(
"\nDistribution of ratio between computed and taken steps\n"
1490 "------------------------------------------------------\n"
1491 " (Omitted bins with differences less than 0.01\%)\n");
1497 EGS_Float step_diff, step_diff_std, step_diff_err, stepMid;
1498 EGS_Float f_scores, f_scores_std;
1499 int idigits = getDigits(eCases);
1501 "---------------------------------------------------------\n");
1502 for (
int i=0; i < n_step_bins; i++) {
1503 stepDist->currentResult(i, f_scores, f_scores_std);
1505 stepMid = (i + 0.5 - step_b)/step_a;
1506 relStepDiff->currentResult(i, step_diff, step_diff_std);
1507 if (step_diff > 0) {
1508 step_diff_err = 100*step_diff_std/step_diff;
1511 step_diff_err = 100;
1513 if (abs(step_diff/f_scores - 1.0) > 0.0001D+0)
1515 stepMid, idigits,
int(f_scores*current_ncase), step_diff/f_scores, step_diff_err);
1523 EGS_Float norm = 1.0/src_norm;
1527 " =======================\n\n");
1529 egsInformation(
"\n\n Total %s fluence\n", particle_name.c_str());
1530 ouputVolumetricFluence(fluT, norm);
1532 if (score_primaries) {
1534 ouputVolumetricFluence(fluT_p, norm);
1542 string suffix =
"_" + particle_name +
".agr";
1544 ofstream spe_output(spe_name.c_str(),ios::out);
1546 egsFatal(
"\n EGS_VolumetricFluence: Error: Failed to open file %s\n",spe_name.c_str());
1550 spe_output <<
"# Volumetric " << particle_name.c_str() <<
" fluence \n";
1551 spe_output <<
"# \n";
1552 spe_output <<
"@ legend 0.2, 0.8\n";
1553 spe_output <<
"@ legend box linestyle 0\n";
1554 spe_output <<
"@ legend font 4\n";
1555 spe_output <<
"@ xaxis label \"energy / MeV\"\n";
1556 spe_output <<
"@ xaxis label char size 1.560000\n";
1557 spe_output <<
"@ xaxis label font 4\n";
1558 spe_output <<
"@ xaxis ticklabel font 4\n";
1559 if (src_norm == 1 || normLabel ==
"primary history") {
1560 spe_output <<
"@ yaxis label \"fluence / MeV\\S-1\\Ncm\\S-2\"\n";
1563 spe_output <<
"@ yaxis label \"fluence / MeV\\S-1\"\n";
1565 spe_output <<
"@ yaxis label char size 1.560000\n";
1566 spe_output <<
"@ yaxis label font 4\n";
1567 spe_output <<
"@ yaxis ticklabel font 4\n";
1568 spe_output <<
"@ title \""<< particle_name.c_str() <<
" fluence" <<
"\"\n";
1569 spe_output <<
"@ title font 4\n";
1570 spe_output <<
"@ title size 1.500000\n";
1571 spe_output <<
"@ subtitle \"for each scoring region\"\n";
1572 spe_output <<
"@ subtitle font 4\n";
1573 spe_output <<
"@ subtitle size 1.000000\n";
1577 " =============================\n\n");
1580 norm *= scoring_charge ? 1 : flu_a;
1582 for (
int j = 0; j < nreg; j++) {
1584 if (!is_sensitive[j]) {
1588 double norma = norm/volume[j];
1603 spe_output<<
"@ s"<< i_graph <<
" errorbar linestyle 0\n";
1604 spe_output<<
"@ s"<< i_graph <<
" legend \""<<
"total (ir # " << j <<
")\"\n";
1605 spe_output<<
"@target G0.S"<< i_graph <<
"\n";
1606 spe_output<<
"@type xydy\n";
1607 if (verbose)
egsInformation(
"\n Emid/MeV Flu/(MeV-1*cm-2) DFlu/(MeV-1*cm-2)\n"
1608 "---------------------------------------------------\n");
1609 for (
int i=0; i<flu_nbin; i++) {
1611 EGS_Float e = (i+0.5-flu_b)/flu_a;
1615 spe_output << e <<
" "<< fe *norma <<
" "<< dfe *norma <<
"\n";
1617 e, fe*norma, dfe*norma);
1619 spe_output <<
"&\n";
1621 if (score_primaries) {
1625 spe_output<<
"@ s"<< ++i_graph <<
" errorbar linestyle 0\n";
1626 spe_output<<
"@ s"<< i_graph <<
" legend \""<<
"primary (ir # " << j <<
")\"\n";
1627 spe_output<<
"@target G0.S"<< i_graph <<
"\n";
1628 spe_output<<
"@type xydy\n";
1629 if (verbose)
egsInformation(
"\n Emid/MeV Flu/(MeV-1*cm-2) DFlu/(MeV-1*cm-2)\n"
1630 "---------------------------------------------------\n");
1631 for (
int i=0; i<flu_nbin; i++) {
1633 EGS_Float e = (i+0.5-flu_b)/flu_a;
1637 spe_output << e <<
" "<< fe *norma <<
" "<< dfe *norma <<
"\n";
1639 e, fe*norma, dfe*norma);
1641 spe_output <<
"&\n";
1652 void EGS_VolumetricFluence::reportResults() {
1655 egsInformation(
"======================================================\n");
1661 bool EGS_VolumetricFluence::storeState(ostream &data)
const {
1672 if (scoring_charge) {
1673 if (!relStepDiff->storeState(data)) {
1676 if (!stepDist->storeState(data)) {
1686 for (
int j = 0; j < nreg; j++) {
1687 if (is_sensitive[j]) {
1688 if (!flu[j]->storeState(data)) {
1695 if (score_primaries) {
1700 for (
int j=0; j < nreg; j++) {
1701 if (is_sensitive[j]) {
1702 if (!flu_p[j]->storeState(data)) {
1713 bool EGS_VolumetricFluence::setState(istream &data) {
1724 if (scoring_charge) {
1725 if (!relStepDiff->setState(data)) {
1728 if (!stepDist->setState(data)) {
1738 for (
int j=0; j<nreg; j++) {
1739 if (is_sensitive[j]) {
1740 if (!flu[j]->setState(data)) {
1747 if (score_primaries) {
1752 for (
int j=0; j < nreg; j++) {
1753 if (is_sensitive[j]) {
1754 if (!flu_p[j]->setState(data)) {
1765 bool EGS_VolumetricFluence::addState(istream &data) {
1770 current_ncase += tmp_case;
1777 if (scoring_charge) {
1779 if (!tmpRelStepDiff.setState(data)) {
1782 (*relStepDiff) += tmpRelStepDiff;
1788 if (!tgT.setState(data)) {
1795 for (
int j = 0; j < nreg; j++) {
1796 if (is_sensitive[j]) {
1797 if (!tg.setState(data)) {
1805 if (score_primaries) {
1807 if (!tgT_p.setState(data)) {
1813 for (
int j=0; j < nreg; j++) {
1814 if (is_sensitive[j]) {
1815 if (!tg_p.setState(data)) {
1818 (*flu_p[j]) += tg_p;
1831 const static char *func =
"createAusgabObject(fluence_scoring)";
1838 int error = input->
getInput(
"type",type);
1839 if (!error && input->
compare(
"planar",type)) {
1842 result->initScoring(input);
1845 else if (!error && input->
compare(
"volumetric",type)) {
1848 result->initScoring(input);
1852 egsFatal(
"Invalid fluence type input?\n\n\n");
Base class for advanced EGSnrc C++ applications.
void getLabelRegions(const string &str, vector< int > ®s)
Gets the regions for the labels in str and pushes onto regs.
void getNumberRegions(const string &str, vector< int > ®s)
Gets numbers out of str and pushes them onto regs.
string constructIOFileName(const char *extension, bool with_run_dir) const
Constructs and returns the name of an input/output file.
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 class for fluence scoring.
EGS_FluenceScoring(const string &Name="", EGS_ObjectFactory *f=0)
A class for fast run-time interpolations.
int getIndex(EGS_Float x) const
Get the interpolation index corresponding to x.
void initialize(int nbin, EGS_Float Xmin, EGS_Float Xmax, const EGS_Float *values)
Initialize the interpolator.
EGS_Float interpolate(EGS_Float x) const
Interpolate the function value at x.
EGS_Float getXmax() const
Get the upper interpolation interval limit.
EGS_Float getXmin() const
Get the lower interpolation interval limit.
void setName(EGS_Input *inp)
Set the name of the object from the information provided by inp.
string otype
The object type.
string name
The object name.
Ausgab object for scoring fluence at circular or rectangular fields.
EGS_PlanarFluence(const string &Name="", EGS_ObjectFactory *f=0)
void describeMe()
Sets fluence scoring object description.
A class for scoring an array of quantities (e.g. a dose distribution) in a Monte Carlo simulation.
bool storeState(ostream &data)
Stores the state of the scoring array object into the data stream data.
void score(int ireg, EGS_Float f)
Add f to the score in the element ireg.
void currentResult(int ireg, double &r, double &dr)
Sets r to the result in region ireg and dr to its statistical uncertainty.
bool setState(istream &data)
Sets the state fof the scoring array object from the data in the input stream data.
A class representing 3D vectors.
Ausgab object for scoring fluence in arbitrary geometry regions.
void describeMe()
Sets fluence scoring object description.
EGS_VolumetricFluence(const string &Name="", EGS_ObjectFactory *f=0)
A fluence scoring object : header.
Global egspp functions header file.
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,...
EGS_InfoFunction EGS_EXPORT egsWarning
Always use this function for reporting warnings.
A structure holding the information of one particle.
EGS_Float E
particle energy in MeV
int latch
latch variable (useful as a flag on many occasions)
EGS_Float wt
statistical weight