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 EGS_Float flu_Emin, flu_Emax;
138 int err_n = eGrid->
getInput(
"number of bins",flu_nbin);
139 int err_i = eGrid->
getInput(
"minimum kinetic energy",flu_Emin);
140 int err_f = eGrid->
getInput(
"maximum kinetic energy",flu_Emax);
141 if (err_n)
egsFatal(
"\n**** EGS_FluenceScoring::initScoring"
142 " Missing input: number of bins.\n"
144 if (err_i)
egsFatal(
"\n**** EGS_FluenceScoring::initScoring"
145 " Missing input: minimum kinetic energy.\n"
147 if (err_f)
egsFatal(
"\n**** EGS_FluenceScoring::initScoring"
148 " Missing input: maximum kinetic energy.\n"
152 int err_norm = inp->
getInput(
"normalization",norma);
160 vector<string> scale;
161 scale.push_back(
"linear");
162 scale.push_back(
"logarithmic");
163 flu_s = inp->
getInput(
"scale",scale,0);
169 flu_xmin = log(flu_Emin);
170 flu_xmax = log(flu_Emax);
173 flu_a /= (flu_xmax - flu_xmin);
174 flu_b = -flu_xmin*flu_a;
188 vector <int> s_start, s_stop;
195 if (inp->
getInput(
"source regions",s_regionsString) || s_regionsString.length()<=0) {
196 int err1 = inp->
getInput(
"start source region",s_start);
197 int err2 = inp->
getInput(
"stop source region",s_stop);
198 if (!err1 && !err2) {
199 if (s_start.size() == s_stop.size()) {
200 for (
int i=0; i<s_start.size(); i++) {
201 int ir = s_start[i], fr = s_stop[i];
203 egsFatal(
"\nEGS_FluenceScoring::initScoring: \n"
204 " Decreasing start (%d) / stop %d region in source region group %d\n"
205 " Aborting!\n\n", ir, fr, i);
206 for (
int ireg=ir; ireg<=fr; ireg++) {
207 s_region.push_back(ireg);
212 "\nEGS_FluenceScoring::initScoring: \n"
213 " Mismatch in number of start (%d) and stop (%d)\n"
214 " source region groups. Aborting!\n",
215 s_start.size(),s_stop.size());
221 void EGS_FluenceScoring::getSensitiveRegions(
EGS_Input *inp) {
223 string listLabel, startLabel, stopLabel;
225 if (
otype ==
"EGS_PlanarFluence") {
226 listLabel =
"contributing regions";
227 startLabel =
"start contributing region";
228 stopLabel =
"stop contributing region";
230 else if (
otype ==
"EGS_VolumetricFluence") {
231 listLabel =
"scoring regions";
232 startLabel =
"start region";
233 stopLabel =
"stop region";
236 egsFatal(
"\n*** Unknown fluence scoriung type! Aborting!\n\n");
240 if (!inp->
getInput(listLabel,f_regionsString) && f_regionsString.length()>0) {
242 if (f_regionsString ==
"ALL") {
243 score_in_all_regions =
true;
246 score_in_all_regions =
false;
250 int err1 = inp->
getInput(startLabel,f_start);
251 int err2 = inp->
getInput(stopLabel, f_stop);
252 if (!err1 && !err2) {
253 if (f_start.size() == f_stop.size()) {
254 for (
int i=0; i<f_start.size(); i++) {
255 int ir = f_start[i], fr = f_stop[i];
257 egsFatal(
"\nEGS_FluenceScoring::initScoring: \n"
258 " Decreasing start (%d) / stop (%d) in region group %d\n"
259 " Aborting!\n\n", ir, fr, i);
260 for (
int ireg=ir; ireg<=fr; ireg++) {
261 f_region.push_back(ireg);
264 score_in_all_regions =
false;
267 "\nEGS_FluenceScoring::initScoring: \n"
268 " Mismatch in number of start (%d) and stop (%d)\n"
269 " region groups. Aborting!\n",
270 f_start.size(),f_stop.size());
275 void EGS_FluenceScoring::getNumberRegions(
const string &str, vector<int> ®s) {
277 egsFatal(
"EGS_FluenceScoring::getNumberRegions\n"
278 " Undefined parent application! Aborting!\n");
283 void EGS_FluenceScoring::getLabelRegions(
const string &str, vector<int> ®s) {
285 egsFatal(
"EGS_FluenceScoring::getLabelRegions\n"
286 " Undefined parent application! Aborting!\n");
291 void EGS_FluenceScoring::setUpRegionFlags() {
293 if (s_regionsString.length() > 0 && !s_region.size()) {
294 getNumberRegions(s_regionsString, s_region);
295 getLabelRegions(s_regionsString, s_region);
298 n_source_regions = s_region.size() < nreg ? s_region.size() : nreg;
300 if (!score_in_all_regions) {
301 if (f_regionsString.length() > 0 && !f_region.size()) {
302 getNumberRegions(f_regionsString, f_region);
303 getLabelRegions(f_regionsString, f_region);
306 n_scoring_regions = f_region.size() < nreg ? f_region.size() : nreg;
308 else if (score_in_all_regions) {
309 n_scoring_regions = nreg;
310 for (
int j=0; j<nreg; j++) {
311 f_region.push_back(j);
315 if (n_source_regions == nreg && score_primaries)
316 egsWarning(
"=> Warning: Setting n_source_regions = nreg \n"
317 " effectively supresses classification\n"
318 " of primaries and secondaries!");
319 for (
int i = 0; i < n_source_regions; i++) {
320 is_source[s_region[i]] =
true;
323 for (
int i = 0; i < n_scoring_regions; i++) {
324 is_sensitive[f_region[i]] =
true;
325 if (f_region[i] > max_reg) {
326 max_reg = f_region[i];
331 void EGS_FluenceScoring::describeMe() {
336 if (n_scoring_regions == nreg) {
340 int start = 0, stop = 0, k = 0, entries = 0;
343 while (k < nreg && entries < REGIONS_ENTRIES) {
345 if (is_sensitive[k]) {
348 while (is_sensitive[k] && k < nreg) {
353 sprintf(buf,
"%d-%d",start,stop);
355 else if (k % REGIONS_PER_LINE) {
356 sprintf(buf,
" %d",start);
359 sprintf(buf,
" %d\n",start);
362 if (entries == REGIONS_ENTRIES) {
363 sprintf(buf,
"... %d\n",max_reg);
375 if (score_primaries) {
376 if (source_charge == unknown) {
377 source_charge = scoring_charge;
378 description +=
" - Unknown source charge due to multi-particle source\n";
379 description +=
" and no user input defining source particle type!\n";
385 sprintf(buf,
"%d\n",source_charge);
391 EGS_Float Emin = flu_s ? exp(flu_xmin):flu_xmin,
392 Emax = flu_s ? exp(flu_xmax):flu_xmax;
393 sprintf(buf,
"%g MeV and %g MeV energy range",Emin,Emax);
410 otype =
"EGS_PlanarFluence";
417 m_d = m_normal*m_midpoint;
424 for (
int j=0; j<Nx*Ny; j++) {
429 for (
int j=0; j<Nx*Ny; j++) {
449 if (source_charge == unknown) {
455 nreg =
app->getnRegions();
458 for (
int j=0; j<nreg; j++) {
460 if (!score_in_all_regions) {
461 is_sensitive.push_back(
false);
464 is_sensitive.push_back(
true);
467 is_source.push_back(
false);
477 for (
int j = 0; j < Nx*Ny; j++) {
482 if (score_primaries) {
486 for (
int j = 0; j < Nx*Ny; j++) {
495 void EGS_PlanarFluence::initScoring(
EGS_Input *inp) {
505 if (! pScoringInput) {
506 egsFatal(
"AO type %s: Missing planar scoring input?\n",
otype.c_str());
511 EGS_FluenceScoring::initScoring(inp);
514 score_in_all_regions =
true;
515 EGS_FluenceScoring::getSensitiveRegions(pScoringInput);
518 vector<EGS_Float> tmp_field;
519 int err2 = pScoringInput->
getInput(
"scoring circle",tmp_field);
521 int err3 = pScoringInput->
getInput(
"scoring rectangle",tmp_field);
522 if (err3 || tmp_field.size() != 4) {
524 "\n\n*** Wrong/missing 'scoring rectangle' input "
525 "setting it to 10 cm X 10 cm field at origin!\n\n");
529 field_type = rectangle;
533 EGS_Float xmin = tmp_field[0],xmax = tmp_field[1],
534 ymin = tmp_field[2],ymax = tmp_field[3];
536 m_midpoint =
EGS_Vector((xmax+xmin)/2.,(ymax+ymin)/2.,0);
554 int err4 = pScoringInput->
getInput(
"resolution",screen);
559 "\n\n*** Missing/wrong 'resolution' input "
560 " Scoring in the whole field\n\n");
563 else if (screen.size()==1) {
567 else if (screen.size()==2) {
571 else if (screen.size()> 2) {
575 "\n\n*** Too many 'resolution' inputs\n"
576 " Using first two entries\n\n");
584 field_type = rectangle;
588 else if (tmp_field.size() != 4) {
590 "\n\n*** Wrong/missing 'scoring circle' input "
591 "setting it to 10 cm diameter field at origin!\n\n");
599 vector<EGS_Float> tmp_normal;
600 int err1 = pScoringInput->
getInput(
"scoring plane normal",tmp_normal);
601 if (err1 || tmp_normal.size() != 3) {
603 "\n\n*** Wrong/missing 'scoring plane normal' input. "
604 "Set along positive z-axis\n\n");
608 m_normal =
EGS_Vector(tmp_normal[0],tmp_normal[1],
610 m_normal.normalize();
612 m_midpoint =
EGS_Vector(tmp_field[0],tmp_field[1],
615 m_R2 = tmp_field[3]*tmp_field[3];
620 m_d = m_normal*m_midpoint;
625 sprintf(buf,
"\nPlanar %s fluence scoring\n",particle_name.c_str());
627 description +=
"================================\n";
629 description +=
" - scoring field normal = ";
630 sprintf(buf,
"(%g %g %g)\n",m_normal.
x,m_normal.
y,m_normal.
z);
632 description +=
" - scoring field center = ";
633 sprintf(buf,
"(%g %g %g)\n",m_midpoint.
x,m_midpoint.
y,m_midpoint.
z);
635 if (field_type == circle) {
636 description +=
" - scoring field radius = ";
637 sprintf(buf,
"%g cm\n",m_R);
640 else if (field_type == rectangle) {
641 description +=
" - scoring field = ";
642 sprintf(buf,
"%g cm X %g cm\n",ax,ay);
644 description +=
" - scoring field resolution = ";
645 sprintf(buf,
"%d X %d\n",Nx,Ny);
648 description +=
" - scoring field distance from origin = ";
649 sprintf(buf,
"%g cm\n",m_d);
652 description +=
" - scoring from region(s): ";
654 EGS_FluenceScoring::describeMe();
658 void EGS_PlanarFluence::score(
const EGS_Particle &p,
const int &ivoxel) {
659 EGS_Float up = p.
u*m_normal, aup = fabs(up);
666 EGS_Float e = p.
q ? p.
E -
app->getRM() : p.
E;
672 EGS_Float auxp = p.
wt/aup;
674 fluT->
score(ivoxel,auxp);
675 if (score_primaries && !p.
latch) {
676 fluT_p->
score(ivoxel,auxp);
679 if (score_spe && e > flu_xmin && e <= flu_xmax) {
680 ae = flu_a*e + flu_b;
687 je = min((
int)ae,flu_nbin-1);
689 if (ivoxel < 0 || ivoxel > Nx*Ny) {
690 egsFatal(
"\n-> Scoring out of bounds, ivoxel = %d\n",ivoxel);
693 if (je < 0 || je >= flu_nbin) {
694 egsFatal(
"\n-> Scoring out of bounds, ibin = %d ae = %g E = %g MeV\n",je,ae,e);
697 if (score_primaries && !p.
latch) {
698 flu_p[ivoxel]->
score(je,auxp);
703 int EGS_PlanarFluence::hitsField(
const EGS_Particle &p, EGS_Float *dist) {
704 if (field_type==circle) {
705 EGS_Float xp = p.
x*m_normal, up = p.
u*m_normal;
706 if ((up > 0 && m_d > xp) ||
707 (up < 0 && m_d < xp)) {
708 EGS_Float t = (m_d - xp)/up;
713 return x1.length2() < m_R*m_R ? 0:-1;
717 else if (field_type == rectangle) {
718 EGS_Float xp = p.
x*m_normal, up = p.
u*m_normal;
719 if ((up > 0 && m_d > xp) || (up < 0 && m_d < xp)) {
720 EGS_Float t = (m_d - xp)/up;
722 EGS_Float xcomp = x1*ux;
723 EGS_Float ycomp = x1*uy;
724 xcomp = 2*xcomp + ax;
725 ycomp = 2*ycomp + ay;
726 if (xcomp > 0 && xcomp < 2*ax &&
727 ycomp > 0 && ycomp < 2*ay) {
728 int i = int(xcomp/(2*vx)),
729 j = int(ycomp/(2*vy)),
744 void EGS_PlanarFluence::ouputPlanarFluence(
EGS_ScoringArray *fT,
const double &norma) {
747 int ix_digits = getDigits(Nx);
748 int iy_digits = getDigits(Ny);
749 int xy_digits = getDigits(Nx*Ny);
751 if (field_type == circle) {
753 "-----------------------------------------------------\n");
757 "-----------------------------------------------------\n",
758 iy_digits,
"iy",ix_digits,
"ix",&count);
760 if (field_type == circle) {
770 egsInformation(
" %10.4le +/- %10.4le [%-7.3lf\%]\n",fe*norma,dfe*norma,dfer);
773 for (
int j=0; j<Ny; j++) {
774 for (
int i=0; i<Nx; i++) {
776 egsInformation(
" %*d %*d %*d ",iy_digits,j,ix_digits,i,xy_digits,k);
784 egsInformation(
" %10.4le +/- %10.4le [%-7.3lf\%]\n",fe*norma,dfe*norma,dfer);
790 void EGS_PlanarFluence::ouputResults() {
792 EGS_Float src_norm = 1.0,
793 Fsrc =
app->getFluence();
794 egsInformation(
"\n\n last case = %lld source particles or fluence = %g\n\n",
795 current_ncase, Fsrc);
798 src_norm = Fsrc/current_ncase;
801 string normLabel = src_norm == 1 ?
"history" :
"MeV-1 cm-2";
802 string src_type =
app->sourceType();
803 if (src_type ==
"EGS_BeamSource") {
804 normLabel =
"primary history";
805 egsInformation(
"\n\n %s normalization = %g (primary histories per particle)\n\n",
806 src_type.c_str(), src_norm);
808 else if (src_type ==
"EGS_CollimatedSource" ||
809 (src_type ==
"EGS_ParallelBeam" && src_norm != 1)) {
810 egsInformation(
"\n\n %s normalization = %g (fluence per particle)\n\n",
811 src_type.c_str(), src_norm);
814 egsInformation(
"\n\n %s normalization = %g (histories per particle)\n\n",
815 src_type.c_str(), src_norm);
820 double norm = 1.0/src_norm;
827 " ================\n\n");
830 ouputPlanarFluence(fluT, norm);
832 if (score_primaries) {
834 ouputPlanarFluence(fluT_p, norm);
839 string suffix =
"_" + particle_name +
".agr";
841 ofstream spe_output(spe_name.c_str(),ios::out);
843 egsFatal(
"\n EGS_PlanarFluence: Error: Failed to open file %s\n",spe_name.c_str());
847 spe_output <<
"# " << particle_name.c_str() <<
" fluence \n";
848 spe_output <<
"# \n";
849 spe_output <<
"@ legend 0.2, 0.8\n";
850 spe_output <<
"@ legend box linestyle 0\n";
851 spe_output <<
"@ legend font 4\n";
852 spe_output <<
"@ xaxis label \"energy / MeV\"\n";
853 spe_output <<
"@ xaxis label char size 1.560000\n";
854 spe_output <<
"@ xaxis label font 4\n";
855 spe_output <<
"@ xaxis ticklabel font 4\n";
856 spe_output <<
"@ yaxis label \"fluence / MeV\\S-1\\Ncm\\S-2\"\n";
857 spe_output <<
"@ yaxis label char size 1.560000\n";
858 spe_output <<
"@ yaxis label font 4\n";
859 spe_output <<
"@ yaxis ticklabel font 4\n";
860 spe_output <<
"@ title \""<< particle_name.c_str() <<
" fluence" <<
"\"\n";
861 spe_output <<
"@ title font 4\n";
862 spe_output <<
"@ title size 1.500000\n";
863 spe_output <<
"@ subtitle \"for each scoring region\"\n";
864 spe_output <<
"@ subtitle font 4\n";
865 spe_output <<
"@ subtitle size 1.000000\n";
868 " ====================\n\n");
872 for (
int j=0; j<Ny; j++) {
873 for (
int i=0; i<Nx; i++) {
878 spe_output<<
"@ s" << i_graph <<
" errorbar linestyle 0\n";
879 spe_output<<
"@ s" << i_graph <<
" legend \""<<
880 "Voxel # " << k <<
"\"\n";
881 spe_output<<
"@target G0.S"<< i_graph <<
"\n";
882 spe_output<<
"@type xydy\n";
886 "---------------------------------------------\n");
888 for (
int l=0; l<flu_nbin; l++) {
890 EGS_Float e = (l+0.5-flu_b)/flu_a;
894 spe_output<<e<<
" "<<fe *norm<<
" "<<dfe *norm<<
"\n";
900 if (score_primaries) {
904 "---------------------------------------------\n");
906 spe_output<<
"@ s" << ++i_graph <<
" errorbar linestyle 0\n";
907 spe_output<<
"@ s" << i_graph <<
" legend \""<<
908 "Voxel # " << k <<
" (primary)\"\n";
909 spe_output<<
"@target G0.S"<< i_graph <<
"\n";
910 spe_output<<
"@type xydy\n";
911 for (
int l=0; l<flu_nbin; l++) {
913 EGS_Float e = (l+0.5-flu_b)/flu_a;
917 spe_output<<e<<
" "<<fe *norm<<
" "<<dfe *norm<<
"\n";
931 void EGS_PlanarFluence::reportResults() {
934 egsInformation(
"======================================================\n");
935 egsInformation(
" Total %ss reaching field: %g\n",particle_name.c_str(),m_tot);
936 egsInformation(
" Primary %ss reaching field: %g\n",particle_name.c_str(),m_primary);
938 egsInformation(
"======================================================\n");
944 bool EGS_PlanarFluence::storeState(ostream &data)
const {
950 data << m_tot <<
" " << m_primary;
961 for (
int j=0; j<Nx*Ny; j++) {
962 if (!flu[j]->storeState(data)) {
968 if (score_primaries) {
973 for (
int j=0; j<Nx*Ny; j++) {
974 if (!flu_p[j]->storeState(data)) {
984 bool EGS_PlanarFluence::setState(istream &data) {
989 data >> m_tot >> m_primary;
999 for (
int j=0; j<Nx*Ny; j++) {
1000 if (!flu[j]->setState(data)) {
1006 if (score_primaries) {
1013 for (
int j=0; j<Nx*Ny; j++) {
1014 if (!flu_p[j]->setState(data)) {
1024 bool EGS_PlanarFluence::addState(istream &data) {
1029 current_ncase += tmp_case;
1033 EGS_Float tmp_tot, tmp_primary;
1034 data >> tmp_tot >> tmp_primary;
1038 m_primary += tmp_primary;
1045 if (!tgT.setState(data)) {
1052 for (
int j=0; j<Nx*Ny; j++) {
1053 if (!tg.setState(data)) {
1060 if (score_primaries) {
1063 if (!tgT_p.setState(data)) {
1070 for (
int j=0; j<Nx*Ny; j++) {
1071 if (!tg_p.setState(data)) {
1074 (*flu_p[j]) += tg_p;
1091 ,one_bin(0), multi_bin(0), max_step(-100.0), n_step_bins(10000)
1094 otype =
"EGS_VolumetricFluence";
1101 for (
int j=0; j<n_scoring_regions; j++) {
1106 for (
int j=0; j<n_scoring_regions; j++) {
1115 if (scoring_charge) {
1137 if (source_charge == unknown) {
1142 nreg =
app->getnRegions();
1145 for (
int j=0; j<nreg; j++) {
1146 is_sensitive.push_back(
false);
1147 is_source.push_back(
false);
1148 volume.push_back(vol_list[0]);
1155 for (
int i = 0; i < n_scoring_regions; i++) {
1156 if (i < vol_list.size()) {
1157 volume[f_region[i]] = vol_list[i];
1165 for (
int j = 0; j < nreg; j++) {
1166 if (is_sensitive[j]) {
1171 if (score_primaries) {
1175 for (
int j = 0; j < nreg; j++) {
1176 if (is_sensitive[j]) {
1187 EGS_Float flu_Emin = flu_s ? exp(flu_xmin) : flu_xmin,
1188 flu_Emax = flu_s ? exp(flu_xmax) : flu_xmax;
1189 EGS_Float bw = flu_s ?(log(flu_Emax / flu_Emin))/flu_nbin :
1190 (flu_Emax - flu_Emin) /flu_nbin;
1195 if (scoring_charge) {
1200 r_const = 1/(expbw-1);
1201 DE =
new EGS_Float [flu_nbin];
1202 a_const =
new EGS_Float [flu_nbin];
1203 for (
int i = 0; i < flu_nbin; i++) {
1204 DE[i] = flu_Emin*pow(expbw,i)*(expbw-1);
1205 a_const[i] = 1/flu_Emin*pow(1/expbw,i);
1209 if (flu_Emin < app->getEcut() -
app->getRM()) {
1210 flu_Emin =
app->getEcut() -
app->getRM() ;
1213 ceil((log(flu_Emax / flu_Emin))/bw) :
1214 ceil((flu_Emax - flu_Emin) /bw);
1220 int n_media =
app->getnMedia();
1222 EGS_Float lnE, lnEmin, lnEmax, lnEmid;
1226 for (
int j = 0; j < n_media; j++) {
1228 i_dedx[j] = *(
app->getDEDX(j, scoring_charge));
1229 EGS_Float Emin = i_dedx[j].
getXmin();
1230 EGS_Float Emax = i_dedx[j].
getXmax();
1231 int n = 1 + i_dedx[j].
getIndex(Emax);
1232 EGS_Float bwidth = (Emax - Emin)/n;
1234 egsInformation(
"---> stpwr in %s : Emin=%g Emax=%g n=%d bw=%g\n",
1235 app->getMediumName(j), exp(Emin), exp(Emax), n, bwidth);
1238 EGS_Float spwr_i[nbins];
1239 for (
int k = 0; k < nbins; k++) {
1240 spwr_i[k] = 1.0 / i_dedx[j].
interpolate(Emin+k*bwidth);
1242 dedx_i[j].
initialize(nbins, Emin, Emax, spwr_i);
1247 bwidth = (Emax - Emin)/n;
1248 egsInformation(
"---> 1/stpwr in %s : lnEmin=%g lnEmax=%g n=%d bw=%g index(Emax)=%d\n",
1249 app->getMediumName(j), Emin, Emax, n, bwidth, dedx_i[j].
getIndexFast(Emax));
1250 for (
int k = 0; k < nbins; k++) {
1253 i_dedx[j].interpolate(Emin + k*bwidth),
1254 dedx_i[j].interpolate(Emin + k*bwidth));
1260 lnEmin = flu_s ? log(0.5*flu_Emin*(expbw+1)) : 0;
1261 Lmid_i =
new EGS_Float [flu_nbin*n_media];
1262 for (
int j = 0; j < n_media; j++) {
1264 EGS_Float med_max_step = 0, logEmax, logEmin;
1266 for (
int i = 0; i < flu_nbin; i++) {
1267 lnEmid = flu_s ? lnEmin + i*bw : log(flu_Emin+bw*(i+0.5));
1268 Lmid_i[i+j*flu_nbin] = 1/i_dedx[j].
interpolate(lnEmid);
1273 logEmin = flu_s ? lnEmin + (i-1)*bw : log(flu_Emin+bw*(i-1));
1274 logEmax = flu_s ? lnEmin + i*bw : log(flu_Emin+bw*i);
1275 if (i_dedx[j].interpolate(logEmax) < i_dedx[j].interpolate(logEmin)) {
1276 med_max_step += 1.02*(exp(logEmax) - exp(logEmin))/i_dedx[j].interpolate(logEmax);
1279 med_max_step += 1.02*(exp(logEmax) - exp(logEmin))*i_dedx[j].interpolate(logEmin);
1285 if (med_max_step > max_step) {
1286 max_step = med_max_step;
1295 EGS_Float RCSDA = max_step;
1299 step_a = n_step_bins/max_step;
1304 egsInformation(
"\n===> RCSDA(%s) = %g cm for Emax = %g MeV, max_step = %g cm bin width = %g cm\n",
1305 app->getMediumName(imed_max_range), RCSDA,
1306 flu_s ? exp(flu_Emax) : flu_Emax, max_step, 1.0/step_a);
1315 void EGS_VolumetricFluence::initScoring(
EGS_Input *inp) {
1325 if (! vScoringInput) {
1326 egsFatal(
"AO type %s: Missing volumetric scoring input?\n",
otype.c_str());
1331 EGS_FluenceScoring::initScoring(inp);
1334 score_in_all_regions =
false;
1335 EGS_FluenceScoring::getSensitiveRegions(vScoringInput);
1338 vector <EGS_Float> v_in;
1339 vScoringInput->
getInput(
"volumes",v_in);
1347 if (! score_in_all_regions && v_in.size() == f_start.size()) {
1349 for (
int i=0; i<f_start.size(); i++) {
1350 int i_r = f_start[i], f_r = f_stop[i];
1351 for (
int ireg=i_r; ireg<=f_r; ireg++) {
1352 vol_list.push_back(v_in[i]);
1356 else if (v_in.size()) {
1360 vol_list.push_back(1.0);
1364 if (scoring_charge) {
1365 vector<string> method;
1366 method.push_back(
"flurz");
1367 method.push_back(
"stpwr");
1368 method.push_back(
"stpwrO5");
1377 sprintf(buf,
"\nVolumetric %s fluence scoring\n",particle_name.c_str());
1379 description +=
"===================================\n";
1381 description +=
" - scoring in region(s): ";
1383 EGS_FluenceScoring::describeMe();
1386 if (flu_stpwr == stpwr) {
1387 description +=
" O(eps^3) approach: accounts for change in stpwr\n";
1388 description +=
" along the step with eps=edep/Emid\n";
1390 else if (flu_stpwr == stpwrO5) {
1391 description +=
" O(eps^5) approach: accounts for change in stpwr\n";
1392 description +=
" along the step with eps=edep/Emid\n";
1396 description +=
" Fluence calculated a-la-FLURZ using Lave=EDEP/TVSTEP.\n";
1399 if (norm_u != 1.0) {
1400 description +=
"\n - Non-unity user-requested normalization = ";
1401 sprintf(buf,
"%g\n",norm_u);
1407 void EGS_VolumetricFluence::ouputVolumetricFluence(
EGS_ScoringArray *fT,
const double &norma) {
1409 double norm = norma;
1411 int ir_digits = getDigits(nreg);
1414 "-----------------------------------------------------\n");
1415 for (
int k=0; k<nreg; k++) {
1416 if (!is_sensitive[k]) {
1428 egsInformation(
" %10.4le +/- %10.4le [%-7.3lf%]\n",fe*norm,dfe*norm,dfer);
1432 void EGS_VolumetricFluence::ouputResults() {
1435 EGS_Float src_norm = 1.0,
1436 Fsrc =
app->getFluence();
1437 egsInformation(
"\n\n last case = %lld source particles or fluence = %g\n\n",
1438 current_ncase, Fsrc);
1441 src_norm = Fsrc/current_ncase;
1444 string normLabel = src_norm == 1 ?
"history" :
"MeV-1 cm-2";
1445 string src_type =
app->sourceType();
1446 if (src_type ==
"EGS_BeamSource") {
1447 normLabel =
"primary history";
1448 egsInformation(
"\n\n %s normalization = %g (primary histories per particle)\n\n",
1449 src_type.c_str(), src_norm);
1451 else if (src_type ==
"EGS_CollimatedSource" ||
1452 (src_type ==
"EGS_ParallelBeam" && src_norm != 1)) {
1453 egsInformation(
"\n\n %s normalization = %g (fluence per particle)\n\n",
1454 src_type.c_str(), src_norm);
1457 egsInformation(
"\n\n %s normalization = %g (histories per particle)\n\n",
1458 src_type.c_str(), src_norm);
1462 EGS_Float fbins, d_fbins;
1464 "--------------------------------------\n");
1466 int tot_bins = one_bin + multi_bin;
1467 egsInformation(
"\none_bin = %d [%-7.3lf\%] multi_bin = %d [%-7.3lf\%]\n",
1468 one_bin, 100.0*one_bin/tot_bins, multi_bin,100.0*multi_bin/tot_bins);
1471 int bdigits = getDigits(flu_nbin);
1472 for (
int i=0; i<flu_nbin; i++) {
1473 binDist->currentResult(i,fbins, d_fbins);
1475 d_fbins = 100.0*d_fbins/fbins;
1476 fbins = current_ncase*fbins;
1478 bdigits, i+1, fbins, d_fbins, 100.*fbins/tot_bins);
1482 if (scoring_charge) {
1483 egsInformation(
"\nDistribution of ratio between computed and taken steps\n"
1484 "------------------------------------------------------\n"
1485 " (Omitted bins with differences less than 0.01\%)\n");
1491 EGS_Float step_diff, step_diff_std, step_diff_err, stepMid;
1492 EGS_Float f_scores, f_scores_std;
1493 int idigits = getDigits(eCases);
1495 "---------------------------------------------------------\n");
1496 for (
int i=0; i < n_step_bins; i++) {
1497 stepDist->currentResult(i, f_scores, f_scores_std);
1499 stepMid = (i + 0.5 - step_b)/step_a;
1500 relStepDiff->currentResult(i, step_diff, step_diff_std);
1501 if (step_diff > 0) {
1502 step_diff_err = 100*step_diff_std/step_diff;
1505 step_diff_err = 100;
1507 if (abs(step_diff/f_scores - 1.0) > 0.0001D+0)
1509 stepMid, idigits,
int(f_scores*current_ncase), step_diff/f_scores, step_diff_err);
1517 EGS_Float norm = 1.0/src_norm;
1521 " =======================\n\n");
1523 egsInformation(
"\n\n Total %s fluence\n", particle_name.c_str());
1524 ouputVolumetricFluence(fluT, norm);
1526 if (score_primaries) {
1528 ouputVolumetricFluence(fluT_p, norm);
1536 string suffix =
"_" + particle_name +
".agr";
1538 ofstream spe_output(spe_name.c_str(),ios::out);
1540 egsFatal(
"\n EGS_VolumetricFluence: Error: Failed to open file %s\n",spe_name.c_str());
1544 spe_output <<
"# Volumetric " << particle_name.c_str() <<
" fluence \n";
1545 spe_output <<
"# \n";
1546 spe_output <<
"@ legend 0.2, 0.8\n";
1547 spe_output <<
"@ legend box linestyle 0\n";
1548 spe_output <<
"@ legend font 4\n";
1549 spe_output <<
"@ xaxis label \"energy / MeV\"\n";
1550 spe_output <<
"@ xaxis label char size 1.560000\n";
1551 spe_output <<
"@ xaxis label font 4\n";
1552 spe_output <<
"@ xaxis ticklabel font 4\n";
1553 if (src_norm == 1 || normLabel ==
"primary history") {
1554 spe_output <<
"@ yaxis label \"fluence / MeV\\S-1\\Ncm\\S-2\"\n";
1557 spe_output <<
"@ yaxis label \"fluence / MeV\\S-1\"\n";
1559 spe_output <<
"@ yaxis label char size 1.560000\n";
1560 spe_output <<
"@ yaxis label font 4\n";
1561 spe_output <<
"@ yaxis ticklabel font 4\n";
1562 spe_output <<
"@ title \""<< particle_name.c_str() <<
" fluence" <<
"\"\n";
1563 spe_output <<
"@ title font 4\n";
1564 spe_output <<
"@ title size 1.500000\n";
1565 spe_output <<
"@ subtitle \"for each scoring region\"\n";
1566 spe_output <<
"@ subtitle font 4\n";
1567 spe_output <<
"@ subtitle size 1.000000\n";
1571 " =============================\n\n");
1574 norm *= scoring_charge ? 1 : flu_a;
1576 for (
int j = 0; j < nreg; j++) {
1578 if (!is_sensitive[j]) {
1594 spe_output<<
"@ s"<< i_graph <<
" errorbar linestyle 0\n";
1595 spe_output<<
"@ s"<< i_graph <<
" legend \""<<
"total (ir # " << j <<
")\"\n";
1596 spe_output<<
"@target G0.S"<< i_graph <<
"\n";
1597 spe_output<<
"@type xydy\n";
1598 if (verbose)
egsInformation(
"\n Emid/MeV Flu/(MeV-1*cm-2) DFlu/(MeV-1*cm-2)\n"
1599 "---------------------------------------------------\n");
1600 for (
int i=0; i<flu_nbin; i++) {
1602 EGS_Float e = (i+0.5-flu_b)/flu_a;
1606 spe_output << e <<
" "<< fe *norm<<
" "<< dfe *norm<<
"\n";
1608 e, fe*norm, dfe*norm);
1610 spe_output <<
"&\n";
1612 if (score_primaries) {
1616 spe_output<<
"@ s"<< ++i_graph <<
" errorbar linestyle 0\n";
1617 spe_output<<
"@ s"<< i_graph <<
" legend \""<<
"primary (ir # " << j <<
")\"\n";
1618 spe_output<<
"@target G0.S"<< i_graph <<
"\n";
1619 spe_output<<
"@type xydy\n";
1620 if (verbose)
egsInformation(
"\n Emid/MeV Flu/(MeV-1*cm-2) DFlu/(MeV-1*cm-2)\n"
1621 "---------------------------------------------------\n");
1622 for (
int i=0; i<flu_nbin; i++) {
1624 EGS_Float e = (i+0.5-flu_b)/flu_a;
1628 spe_output << e <<
" "<< fe *norm<<
" "<< dfe *norm<<
"\n";
1630 e, fe*norm, dfe*norm);
1632 spe_output <<
"&\n";
1643 void EGS_VolumetricFluence::reportResults() {
1646 egsInformation(
"======================================================\n");
1652 bool EGS_VolumetricFluence::storeState(ostream &data)
const {
1663 if (scoring_charge) {
1664 if (!relStepDiff->storeState(data)) {
1667 if (!stepDist->storeState(data)) {
1677 for (
int j = 0; j < nreg; j++) {
1678 if (is_sensitive[j]) {
1679 if (!flu[j]->storeState(data)) {
1686 if (score_primaries) {
1691 for (
int j=0; j < nreg; j++) {
1692 if (is_sensitive[j]) {
1693 if (!flu_p[j]->storeState(data)) {
1704 bool EGS_VolumetricFluence::setState(istream &data) {
1715 if (scoring_charge) {
1716 if (!relStepDiff->setState(data)) {
1719 if (!stepDist->setState(data)) {
1729 for (
int j=0; j<nreg; j++) {
1730 if (is_sensitive[j]) {
1731 if (!flu[j]->setState(data)) {
1738 if (score_primaries) {
1743 for (
int j=0; j < nreg; j++) {
1744 if (is_sensitive[j]) {
1745 if (!flu_p[j]->setState(data)) {
1756 bool EGS_VolumetricFluence::addState(istream &data) {
1761 current_ncase += tmp_case;
1768 if (scoring_charge) {
1770 if (!tmpRelStepDiff.setState(data)) {
1773 (*relStepDiff) += tmpRelStepDiff;
1779 if (!tgT.setState(data)) {
1786 for (
int j = 0; j < nreg; j++) {
1787 if (is_sensitive[j]) {
1788 if (!tg.setState(data)) {
1796 if (score_primaries) {
1798 if (!tgT_p.setState(data)) {
1804 for (
int j=0; j < nreg; j++) {
1805 if (is_sensitive[j]) {
1806 if (!tg_p.setState(data)) {
1809 (*flu_p[j]) += tg_p;
1822 const static char *func =
"createAusgabObject(fluence_scoring)";
1829 int error = input->
getInput(
"type",type);
1830 if (!error && input->
compare(
"planar",type)) {
1833 result->initScoring(input);
1836 else if (!error && input->
compare(
"volumetric",type)) {
1839 result->initScoring(input);
1843 egsFatal(
"Invalid fluence type input?\n\n\n");
A class for scoring an array of quantities (e.g. a dose distribution) in a Monte Carlo simulation...
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.
EGS_Float E
particle energy in MeV
int getIndex(EGS_Float x) const
Get the interpolation index corresponding to x.
string description
A short ausgab object description.
void getNumberRegions(const string &str, vector< int > ®s)
Gets numbers out of str and pushes them onto regs.
void getLabelRegions(const string &str, vector< int > ®s)
Gets the regions for the labels in str and pushes onto regs.
Ausgab object for scoring fluence at circular or rectangular fields.
int getIndexFast(EGS_Float x) const
Get the interpolation index corresponding to x.
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.
A class representing 3D vectors.
A structure holding the information of one particle.
Global egspp functions header file.
bool setState(istream &data)
Sets the state fof the scoring array object from the data in the input stream data.
A fluence scoring object : header.
bool storeState(ostream &data)
Stores the state of the scoring array object into the data stream data.
Base class for fluence scoring.
EGS_InfoFunction EGS_EXPORT egsFatal
Always use this function for reporting fatal errors.
EGS_Float interpolate(EGS_Float x) const
Interpolate the function value at x.
EGS_Float getXmax() const
Get the upper interpolation interval limit.
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.
void currentResult(int ireg, double &r, double &dr)
Sets r to the result in region ireg and dr to its statistical uncertainty.
Ausgab object for scoring fluence in arbitrary geometry regions.
EGS_PlanarFluence(const string &Name="", EGS_ObjectFactory *f=0)
EGS_FluenceScoring(const string &Name="", EGS_ObjectFactory *f=0)
void score(int ireg, EGS_Float f)
Add f to the score in the element ireg.
string constructIOFileName(const char *extension, bool with_run_dir) const
Constructs and returns the name of an input/output file.
void initialize(int nbin, EGS_Float Xmin, EGS_Float Xmax, const EGS_Float *values)
Initialize the interpolator.
void setName(EGS_Input *inp)
Set the name of the object from the information provided by inp.
int latch
latch variable (useful as a flag on many occasions)
string name
The object name.
EGS_Float getXmin() const
Get the lower interpolation interval limit.
string otype
The object type.
EGS_Float wt
statistical weight
virtual void setApplication(EGS_Application *App)
Set the application this object belongs to.
void describeMe()
Sets fluence scoring object description.
EGS_VolumetricFluence(const string &Name="", EGS_ObjectFactory *f=0)
Base class for advanced EGSnrc C++ applications.
EGS_Application * app
The application this object belongs to.
void describeMe()
Sets fluence scoring object description.
EGS_InfoFunction EGS_EXPORT egsWarning
Always use this function for reporting warnings.