18void frame(TCanvas* c,
double xmin,
double ymin,
double xmax,
double ymax,
19 const std::string& xtitle,
const std::string& ytitle) {
20 c->Range(340.8701, -0.1167765, 1233.468, 4.061288);
28 c->SetRightMargin(0.018);
29 c->SetLeftMargin(0.098);
30 c->SetTopMargin(0.015);
31 c->SetBottomMargin(0.09);
32 c->SetFrameLineWidth(2);
33 c->SetFrameBorderMode(0);
34 c->SetFrameBorderSize(12);
35 c->SetFrameLineWidth(2);
36 c->SetFrameBorderMode(0);
37 c->SetFrameBorderSize(12);
38 TH1* hframe =
new TH1F(
"hframe",
"", 10, xmin, xmax);
39 hframe->SetMinimum(ymin);
40 hframe->SetMaximum(ymax);
41 hframe->SetDirectory(0);
43 hframe->GetXaxis()->SetTitle(xtitle.c_str());
44 hframe->GetXaxis()->SetLabelFont(22);
45 hframe->GetXaxis()->SetLabelOffset(0.007);
46 hframe->GetXaxis()->SetLabelSize(0.038);
47 hframe->GetXaxis()->SetTitleSize(0.044);
48 hframe->GetXaxis()->SetTickLength(0.035);
49 hframe->GetXaxis()->SetTitleOffset(0.9);
50 hframe->GetXaxis()->SetTitleFont(22);
51 hframe->GetYaxis()->SetTitle(ytitle.c_str());
52 hframe->GetYaxis()->SetLabelFont(22);
53 hframe->GetYaxis()->SetLabelOffset(0.01);
54 hframe->GetYaxis()->SetLabelSize(0.038);
55 hframe->GetYaxis()->SetTitleSize(0.044);
56 hframe->GetYaxis()->SetTickLength(0.035);
57 hframe->GetYaxis()->SetTitleOffset(0.9);
58 hframe->GetYaxis()->SetTitleFont(22);
62double StepVavilov(
const double rkappa) {
67 }
else if (rkappa < 1) {
69 }
else if (rkappa < 2) {
71 }
else if (rkappa < 3) {
73 }
else if (rkappa < 4) {
75 }
else if (rkappa < 5) {
77 }
else if (rkappa < 6) {
79 }
else if (rkappa < 7) {
81 }
else if (rkappa < 8) {
87double Interpolate(
const double x,
const std::vector<double>& xtab,
88 const std::vector<double>& ytab) {
92 }
else if (x > xtab.back()) {
98void PrintSettings(
const std::string& hdr,
99 const double de,
const double step,
const double ekin,
100 const double beta2,
const double gamma,
101 const double agas,
const double zgas,
const double density,
102 const double qpart,
const double mpart,
const double emax,
103 const double xi,
const double kappa) {
105 std::cout << hdr <<
"Settings:\n"
106 <<
" dE = " << de <<
" MeV,\n"
107 <<
" step = " << step <<
" cm.\n"
108 <<
" Ekin = " << ekin <<
" MeV,\n"
109 <<
" beta2 = " << beta2 <<
",\n"
110 <<
" gamma = " << gamma <<
".\n"
111 <<
" Agas = " << agas <<
", Zgas = " << zgas <<
",\n"
112 <<
" density = " << density <<
" g/cm3.\n"
113 <<
" Qpart = " << qpart <<
", mpart = " << mpart <<
" MeV.\n"
114 <<
" Emax = " << emax <<
" MeV,\n"
115 <<
" xi = " << xi <<
" MeV,\n"
116 <<
" kappa = " << kappa <<
".\n";
124 m_precisevavilov(false),
125 m_useTransStraggle(true),
126 m_useLongStraggle(false),
143 const std::string hdr =
m_className +
"::ReadFile:\n ";
146 fsrim.open(file.c_str(), std::ios::in);
148 std::cerr << hdr <<
"Could not open SRIM file " << file
149 <<
" for reading.\n The file perhaps does not exist.\n";
152 unsigned int nread = 0;
156 std::cout << hdr <<
"SRIM header records from file " << file <<
"\n";
158 const int size = 100;
160 while (fsrim.getline(line, 100,
'\n')) {
162 if (strstr(line,
"SRIM version") != NULL) {
163 if (
m_debug) std::cout <<
"\t" << line <<
"\n";
164 }
else if (strstr(line,
"Calc. date") != NULL) {
165 if (
m_debug) std::cout <<
"\t" << line <<
"\n";
166 }
else if (strstr(line,
"Ion =") != NULL) {
173 token = strtok(line,
" []=");
174 token = strtok(NULL,
" []=");
175 token = strtok(NULL,
" []=");
177 m_q = std::atof(token);
179 token = strtok(NULL,
" []=");
180 token = strtok(NULL,
" []=");
181 token = strtok(NULL,
" []=");
183 m_mass = std::atof(token) * AtomicMassUnitElectronVolt;
186 if (!fsrim.getline(line, 100,
'\n')) {
187 std::cerr << hdr <<
"Premature EOF looking for target density (line "
192 if (!fsrim.getline(line, 100,
'\n')) {
193 std::cerr << hdr <<
"Premature EOF looking for target density (line "
198 token = strtok(line,
" ");
199 token = strtok(NULL,
" ");
200 token = strtok(NULL,
" ");
201 token = strtok(NULL,
" ");
205 while (fsrim.getline(line, 100,
'\n')) {
207 if (strstr(line,
"Stopping Units") == NULL)
continue;
208 if (strstr(line,
"Stopping Units = MeV / (mg/cm2)") != NULL) {
210 std::cout << hdr <<
"Stopping units: MeV / (mg/cm2) as expected.\n";
214 std::cerr << hdr <<
"Unknown stopping units. Aborting (line " << nread
220 while (fsrim.getline(line, 100,
'\n')) {
222 if (strstr(line,
"-----------") != NULL)
break;
232 unsigned int ntable = 0;
233 while (fsrim.getline(line, 100,
'\n')) {
235 if (strstr(line,
"-----------") != NULL)
break;
237 token = strtok(line,
" ");
238 m_ekin.push_back(atof(token));
239 token = strtok(NULL,
" ");
240 if (strcmp(token,
"eV") == 0) {
242 }
else if (strcmp(token,
"keV") == 0) {
244 }
else if (strcmp(token,
"GeV") == 0) {
246 }
else if (strcmp(token,
"MeV") != 0) {
247 std::cerr << hdr <<
"Unknown energy unit " << token <<
"; aborting\n";
251 token = strtok(NULL,
" ");
254 token = strtok(NULL,
" ");
257 token = strtok(NULL,
" ");
258 m_range.push_back(atof(token));
259 token = strtok(NULL,
" ");
260 if (strcmp(token,
"A") == 0) {
262 }
else if (strcmp(token,
"um") == 0) {
264 }
else if (strcmp(token,
"mm") == 0) {
266 }
else if (strcmp(token,
"m") == 0) {
268 }
else if (strcmp(token,
"km") == 0) {
270 }
else if (strcmp(token,
"cm") != 0) {
271 std::cerr << hdr <<
"Unknown distance unit " << token <<
"; aborting\n";
275 token = strtok(NULL,
" ");
277 token = strtok(NULL,
" ");
278 if (strcmp(token,
"A") == 0) {
280 }
else if (strcmp(token,
"um") == 0) {
282 }
else if (strcmp(token,
"mm") == 0) {
284 }
else if (strcmp(token,
"m") == 0) {
286 }
else if (strcmp(token,
"km") == 0) {
288 }
else if (strcmp(token,
"cm") != 0) {
289 std::cerr << hdr <<
"Unknown distance unit " << token <<
"; aborting\n";
293 token = strtok(NULL,
" ");
295 token = strtok(NULL,
" ");
296 if (strcmp(token,
"A") == 0) {
298 }
else if (strcmp(token,
"um") == 0) {
300 }
else if (strcmp(token,
"mm") == 0) {
302 }
else if (strcmp(token,
"m") == 0) {
304 }
else if (strcmp(token,
"km") == 0) {
306 }
else if (strcmp(token,
"cm") != 0) {
307 std::cerr << hdr <<
"Unknown distance unit " << token <<
"; aborting\n";
317 while (fsrim.getline(line, 100,
'\n')) {
319 if (strstr(line,
"=============") != NULL) {
321 }
else if (strstr(line,
"MeV / (mg/cm2)") != NULL ||
322 strstr(line,
"MeV/(mg/cm2)") != NULL) {
323 token = strtok(line,
" ");
324 scale = std::atof(token);
328 std::cerr << hdr <<
"Did not find stopping unit scaling; aborting.\n";
332 for (
unsigned int i = 0; i < ntable; ++i) {
339 std::cout << hdr <<
"Successfully read " << file <<
"(" << nread
347 std::cout <<
"TrackSrim::Print:\n SRIM energy loss table\n\n"
348 <<
" Energy EM Loss HD loss Range "
349 <<
"l straggle t straggle\n"
350 <<
" [MeV] [MeV/cm] [MeV/cm] [cm] "
352 const unsigned int nPoints =
m_emloss.size();
353 for (
unsigned int i = 0; i < nPoints; ++i) {
354 printf(
"%10g %10g %10g %10g %10g %10g\n",
m_ekin[i],
359 printf(
" Work function: %g eV\n",
m_work);
360 printf(
" Fano factor: %g\n",
m_fano);
361 printf(
" Ion charge: %g\n",
m_q);
362 printf(
" Mass: %g MeV\n", 1.e-6 *
m_mass);
363 printf(
" Density: %g g/cm3\n",
m_density);
364 printf(
" A, Z: %g, %g\n",
m_a,
m_z);
370 double xmin = 0., xmax = 0.;
371 double ymin = 0., ymax = 0.;
372 const unsigned int nPoints =
m_ekin.size();
373 TGraph* grem =
new TGraph(nPoints);
374 TGraph* grhd =
new TGraph(nPoints);
375 TGraph* grtot =
new TGraph(nPoints);
376 for (
unsigned int i = 0; i < nPoints; ++i) {
377 const double eplot =
m_ekin[i];
378 if (eplot < xmin) xmin = eplot;
379 if (eplot > xmax) xmax = eplot;
382 const double totplot = emplot + hdplot;
383 if (totplot < ymin) ymin = totplot;
384 if (totplot > ymax) ymax = totplot;
385 grem->SetPoint(i, eplot, emplot);
386 grhd->SetPoint(i, eplot, hdplot);
387 grtot->SetPoint(i, eplot, totplot);
391 TCanvas* celoss =
new TCanvas();
393 frame(celoss, xmin, 0.0, xmax, ymax * 1.05,
"Ion energy [MeV]",
394 "Energy loss [MeV/cm]");
395 TLegend* legend =
new TLegend(0.65, 0.75, 0.94, 0.95);
396 legend->SetShadowColor(0);
397 legend->SetTextFont(22);
398 legend->SetTextSize(0.044);
399 legend->SetFillColor(kWhite);
400 legend->SetBorderSize(1);
402 grem->SetLineColor(kBlue);
403 grem->SetLineStyle(kSolid);
404 grem->SetLineWidth(2.0);
405 grem->SetMarkerStyle(21);
406 grem->SetMarkerColor(kBlack);
408 legend->AddEntry(grem,
"EM energy loss",
"l");
410 grhd->SetLineColor(kGreen + 2);
411 grhd->SetLineStyle(kSolid);
412 grhd->SetLineWidth(2.0);
413 grhd->SetMarkerStyle(21);
414 grhd->SetMarkerColor(kBlack);
416 legend->AddEntry(grhd,
"HD energy loss",
"l");
418 grtot->SetLineColor(kOrange);
419 grtot->SetLineStyle(kSolid);
420 grtot->SetLineWidth(2.0);
421 grtot->SetMarkerStyle(21);
422 grtot->SetMarkerColor(kBlack);
424 legend->AddEntry(grtot,
"Total energy loss",
"l");
432 double xmin = 0., xmax = 0.;
433 double ymin = 0., ymax = 0.;
434 const unsigned int nPoints =
m_ekin.size();
435 TGraph* grrange =
new TGraph(nPoints);
436 for (
unsigned int i = 0; i < nPoints; ++i) {
437 const double eplot =
m_ekin[i];
438 if (eplot < xmin) xmin = eplot;
439 if (eplot > xmax) xmax = eplot;
440 const double rangeplot =
m_range[i];
441 if (rangeplot < ymin) ymin = rangeplot;
442 if (rangeplot > ymax) ymax = rangeplot;
443 grrange->SetPoint(i, eplot, rangeplot);
447 TCanvas* crange =
new TCanvas();
449 frame(crange, xmin, 0.0, xmax, ymax * 1.05,
"Ion energy [MeV]",
450 "Projected range [cm]");
452 grrange->SetLineColor(kOrange);
453 grrange->SetLineStyle(kSolid);
454 grrange->SetLineWidth(2.0);
455 grrange->SetMarkerStyle(21);
456 grrange->SetMarkerColor(kBlack);
457 grrange->Draw(
"SAME");
463 double xmin = 0., xmax = 0.;
464 double ymin = 0., ymax = 0.;
465 const unsigned int nPoints =
m_ekin.size();
466 TGraph* grlong =
new TGraph(nPoints);
467 TGraph* grtrans =
new TGraph(nPoints);
468 for (
unsigned int i = 0; i < nPoints; ++i) {
469 const double eplot =
m_ekin[i];
470 if (eplot < xmin) xmin = eplot;
471 if (eplot > xmax) xmax = eplot;
474 if (longplot < ymin) ymin = longplot;
475 if (longplot > ymax) ymax = longplot;
476 if (transplot < ymin) ymin = transplot;
477 if (transplot > ymax) ymax = transplot;
478 grlong->SetPoint(i, eplot, longplot);
479 grtrans->SetPoint(i, eplot, transplot);
483 TCanvas* cstraggle =
new TCanvas();
484 cstraggle->SetLogx();
485 frame(cstraggle, xmin, 0.0, xmax, ymax * 1.05,
"Ion energy [MeV]",
487 TLegend* legend =
new TLegend(0.15, 0.75, 0.44, 0.95);
488 legend->SetShadowColor(0);
489 legend->SetTextFont(22);
490 legend->SetTextSize(0.044);
491 legend->SetFillColor(kWhite);
492 legend->SetBorderSize(1);
494 grlong->SetLineColor(kOrange);
495 grlong->SetLineStyle(kSolid);
496 grlong->SetLineWidth(2.0);
497 grlong->SetMarkerStyle(21);
498 grlong->SetMarkerColor(kBlack);
499 grlong->Draw(
"SAME");
500 legend->AddEntry(grlong,
"Longitudinal",
"l");
502 grtrans->SetLineColor(kGreen + 2);
503 grtrans->SetLineStyle(kSolid);
504 grtrans->SetLineWidth(2.0);
505 grtrans->SetMarkerStyle(21);
506 grtrans->SetMarkerColor(kBlack);
507 grtrans->Draw(
"SAME");
508 legend->AddEntry(grtrans,
"Transversal",
"l");
522 double& deem,
double& dehd)
const {
525 const std::string hdr =
m_className +
"::PreciseLoss: ";
528 std::cout << hdr <<
"\n"
529 <<
" Initial energy: " << estart <<
" MeV\n"
530 <<
" Step: " << step <<
" cm\n";
533 const double eps = 1.0e-2;
535 unsigned int ndiv = 1;
537 const unsigned int nMaxIter = 10;
538 bool converged =
false;
539 for (
unsigned int iter = 0; iter < nMaxIter; ++iter) {
545 const double s =
m_density * step / ndiv;
546 for (
unsigned int i = 0; i < ndiv; i++) {
548 const double em21 = s *
DedxEM(e2);
549 const double hd21 = s *
DedxHD(e2);
550 const double de21 = em21 + hd21;
552 const double em22 = s *
DedxEM(e2 - 0.5 * de21);
553 const double hd22 = s *
DedxHD(e2 - 0.5 * de21);
557 const double em41 = s *
DedxEM(e4);
558 const double hd41 = s *
DedxHD(e4);
559 const double de41 = em41 + hd41;
561 const double em42 = s *
DedxEM(e4 - 0.5 * de41);
562 const double hd42 = s *
DedxHD(e4 - 0.5 * de41);
563 const double de42 = em42 + hd42;
565 const double em43 = s *
DedxEM(e4 - 0.5 * de42);
566 const double hd43 = s *
DedxHD(e4 - 0.5 * de42);
567 const double de43 = em43 + hd43;
569 const double em44 = s *
DedxEM(e4 - de43);
570 const double hd44 = s *
DedxHD(e4 - de43);
571 const double de44 = em44 + hd44;
573 deem += (em41 + em44) / 6. + (em42 + em43) / 3.;
574 dehd += (hd41 + hd44) / 6. + (hd42 + hd43) / 3.;
576 e4 -= (de41 + de44) / 6. + (de42 + de43) / 3.;
579 std::cout << hdr <<
"\n Iteration " << iter <<
" has " << ndiv
580 <<
" division(s). Losses:\n";
581 printf(
"\tde4 = %12g, de2 = %12g MeV\n", estart - e2, estart - e4);
582 printf(
"\tem4 = %12g, hd4 = %12g MeV\n", deem, dehd);
585 if (fabs(e2 - e4) > eps * (fabs(e2) + fabs(e4) + fabs(estart))) {
595 std::cerr << hdr <<
"No convergence achieved integrating energy loss.\n";
597 std::cout << hdr <<
"Convergence at eps = " << eps <<
"\n";
610 const std::string hdr =
m_className +
"::EstimateRange: ";
616 double deem = 0., dehd = 0.;
618 double de1 = deem + dehd;
621 if (
m_debug) std::cout << hdr <<
"Initial step OK.\n";
625 double st2 = 0.5 * step;
627 const unsigned int nMaxIter = 20;
628 for (
unsigned int iter = 0; iter < nMaxIter; ++iter) {
633 if (de2 < ekin)
break;
640 std::cerr << hdr <<
"\n Did not find a smaller step in " << nMaxIter
641 <<
" iterations. Abandoned.\n";
642 stpmax = 0.5 * (st1 + st2);
646 printf(
"\tstep 1 = %g cm, de 1 = %g MeV\n\tstep 2 = %g cm, de 2 = %g MeV\n",
647 st1, de1 - ekin, st2, de2 - ekin);
650 for (
unsigned int iter = 0; iter < nMaxIter; ++iter) {
654 std::cerr << hdr <<
"Bisection failed due to equal energy loss for "
655 <<
"two step sizes. Abandoned.\n";
657 stpmax = 0.5 * (st1 + st2);
662 if ((fabs(de1 - ekin) < 0.01 * fabs(de2 - de1)) ||
663 (fabs(de1 - ekin) > 0.99 * fabs(de2 - de1))) {
664 st3 = 0.5 * (st1 + st2);
666 st3 = st1 - (st2 - st1) * (de1 - ekin) / (de2 - de1);
670 const double de3 = deem + dehd;
671 if (
m_debug) printf(
"\tStep 1 = %g cm, dE 1 = %g MeV\n", st1, de1 - ekin);
672 if (
m_debug) printf(
"\tStep 2 = %g cm, dE 2 = %g MeV\n", st2, de2 - ekin);
673 if (
m_debug) printf(
"\tStep 3 = %g cm, dE 3 = %g MeV\n", st3, de3 - ekin);
683 if (fabs(de3 - ekin) < 1e-3 * (fabs(de3) + fabs(ekin)) ||
684 fabs(st1 - st2) < 1e-3 * (fabs(st1) + fabs(st2))) {
685 stpmax = st1 - (st2 - st1) * (de1 - ekin) / (de2 - de1);
690 std::cout << hdr <<
"Bisection did not converge in " << nMaxIter
691 <<
" steps. Abandoned.\n";
693 stpmax = st1 - (st2 - st1) * (de1 - ekin) / (de2 - de1);
699 const double t0,
const double dx0,
const double dy0,
704 const std::string hdr =
m_className +
"::NewTrack: ";
708 std::cerr << hdr <<
"\n Sensor is not defined.\n";
713 double xmin = 0., ymin = 0., zmin = 0.;
714 double xmax = 0., ymax = 0., zmax = 0.;
716 std::cerr << hdr <<
"\n Drift area is not set.\n";
718 }
else if (x0 < xmin || x0 > xmax ||
719 y0 < ymin || y0 > ymax || z0 < zmin || z0 > zmax) {
720 std::cerr << hdr <<
"\n Initial position outside bounding box.\n";
727 std::cerr << hdr <<
"\n No medium at initial position.\n";
730 std::cerr << hdr <<
"\n Medium at initial position is not ionisable.\n";
735 const double normdir = sqrt(dx0 * dx0 + dy0 * dy0 + dz0 * dz0);
739 if (normdir < Small) {
741 std::cout << hdr <<
"\n Direction vector has zero norm.\n"
742 <<
" Initial direction is randomized.\n";
755 std::cerr << hdr <<
"\n Particle mass not set.\n";
758 std::cerr << hdr <<
"\n Particle charge not set.\n";
761 std::cerr << hdr <<
"\n Initial particle energy not set.\n";
763 }
else if (
m_work < Small) {
764 std::cerr << hdr <<
"\n Work function not set.\n";
766 }
else if (
m_a < Small ||
m_z < Small) {
767 std::cerr << hdr <<
"\n A and/or Z not set.\n";
772 if (ekin0 < 1.e-14 *
m_mass || ekin0 < 1.e-3 *
m_work) {
774 std::cout << hdr <<
"Initial kinetic energy E = " << ekin0
775 <<
" MeV such that beta2 = 0 or E << W; particle stopped.\n";
781 const double tracklength = 10 * Interpolate(ekin0,
m_ekin,
m_range);
785 std::cout << hdr <<
"Track generation with the following parameters:\n";
786 const unsigned int nTable =
m_ekin.size();
787 printf(
" Table size %u\n", nTable);
788 printf(
" Particle kin. energy %g MeV\n", ekin0);
789 printf(
" Particle mass %g MeV\n", 1.e-6 *
m_mass);
790 printf(
" Particle charge %g\n",
m_q);
791 printf(
" Work function %g eV\n",
m_work);
793 printf(
" Fano factor %g\n",
m_fano);
795 std::cout <<
" Fano factor Not set\n";
800 printf(
" Cluster size %d\n",
m_nsize);
835 std::cout << hdr <<
"\n Energy = " << e <<
" MeV,\n dEdx em, hd = "
836 << dedxem <<
", " << dedxhd <<
" MeV/cm,\n e-/cm = "
837 << 1.e6 * dedxem /
m_work <<
".\n Straggling long/lat: "
838 << strlon <<
", " << strlat <<
" cm\n";
846 step = ekin0 / (ncls * (dedxem + dedxhd));
851 double deem = 0., dehd = 0.;
855 if (deem + dehd > e) {
859 deem = e * deem / (dehd + deem);
862 if (
m_debug) std::cout << hdr <<
"Finish raised. Track length reached.\n";
864 stpmax = tracklength - dsum;
870 std::cerr << hdr <<
"\n Failure computing the minimum step size."
871 <<
"\n Clustering abandoned.\n";
876 if (stpmin > stpmax) {
878 if (
m_debug) std::cout << hdr <<
"stpmin > stpmax. Deposit all energy.\n";
880 if (e - eloss - dehd < 0) eloss = e - dehd;
882 if (
m_debug) std::cout << hdr <<
"Finish raised. Single deposit.\n";
883 }
else if (step < stpmin) {
885 if (
m_debug) std::cout << hdr <<
"Enlarging step size.\n";
888 if (deem + dehd > e) {
889 if (
m_debug) std::cout << hdr <<
"Excess loss. Recomputing stpmax.\n";
893 deem = e * deem / (dehd + deem);
901 if (
m_debug) std::cout << hdr <<
"Using existing step size.\n";
906 if (
m_debug) std::cout << hdr <<
"Truncating negative energy loss.\n";
908 }
else if (eloss > e - dehd) {
909 if (
m_debug) std::cout << hdr <<
"Excess energy loss, using mean.\n";
911 if (e - eloss - dehd < 0) {
914 if (
m_debug) std::cout << hdr <<
"Finish raised. Using mean energy.\n";
918 std::cout << hdr <<
"\n Step length = " << step <<
" cm.\n "
919 <<
"Mean loss = " << deem <<
" MeV.\n "
920 <<
"Actual loss = " << eloss <<
" MeV.\n";
926 std::cout << hdr <<
"No medium at position ("
927 << x <<
"," << y <<
"," << z <<
").\n";
932 std::cout << hdr <<
"Medium at ("
933 << x <<
"," << y <<
"," << z <<
") is not ionisable.\n";
938 std::cout << hdr <<
"Cluster at ("
939 << x <<
"," << y <<
"," << z <<
") outside bounding box.\n";
954 double ecl = 1.e6 * (eloss + epool);
960 if (ernd1 > ecl)
break;
962 newcluster.
ec += ernd1;
967 std::cout << hdr <<
"EM + pool: " << 1.e6 * (eloss + epool)
968 <<
" eV, W: " <<
m_work <<
" eV, E/w: "
969 << (eloss + epool) / (1.0e-6 *
m_work) <<
", n: "
973 epool += eloss - 1.e-6 * newcluster.
ec;
975 std::cout << hdr <<
"Cluster " <<
m_clusters.size() <<
"\n at ("
976 << newcluster.
x <<
", " << newcluster.
y <<
", " << newcluster.
z
977 <<
"),\n e = " << newcluster.
ec <<
",\n n = "
979 << epool <<
" MeV.\n";
988 if (
m_debug) std::cout << hdr <<
"Finishing flag raised.\n";
990 }
else if (e < ekin0 * 1.e-9) {
992 if (
m_debug) std::cout << hdr <<
"Energy exhausted.\n";
996 const double scale = sqrt(step / prange);
1000 if (
m_debug) std::cout << hdr <<
"sigma l, t1, t2: "
1001 << sigl <<
", " << sigt1 <<
", " << sigt2 <<
"\n";
1004 if (xdir * xdir + zdir * zdir <= 0) {
1007 }
else if (ydir > 0) {
1010 std::cerr << hdr <<
"\n Zero step length; clustering abandoned.\n";
1015 phi = atan2(xdir, zdir);
1016 theta = atan2(ydir, sqrt(xdir * xdir + zdir * zdir));
1020 const double cp = cos(phi);
1021 const double ct = cos(theta);
1022 const double sp = sin(phi);
1023 const double st = sin(theta);
1024 x += step * xdir + cp * sigt1 - sp * st * sigt2 + sp * ct * sigl;
1025 y += step * ydir + ct * sigt2 + st * sigl;
1026 z += step * zdir - sp * sigt1 - cp * st * sigt2 + cp * ct * sigl;
1030 xdir = step * xdir + cp * sigt1 - sp * st * sigt2 + sp * ct * sigl;
1031 ydir = step * ydir + ct * sigt2 + st * sigl;
1032 zdir = step * zdir - sp * sigt1 - cp * st * sigt2 + cp * ct * sigl;
1033 double dnorm = sqrt(xdir * xdir + ydir * ydir + zdir * zdir);
1035 std::cerr << hdr <<
"\n Zero step length; clustering abandoned.\n";
1038 xdir = xdir / dnorm;
1039 ydir = ydir / dnorm;
1040 zdir = zdir / dnorm;
1046 std::cerr << hdr <<
"Exceeded maximum number of clusters.\n";
1058 const std::string hdr =
m_className +
"::SmallestStep: ";
1059 const double expmax = 30;
1064 if (ekin <= 0 || de <= 0 || step <= 0) {
1065 std::cerr << hdr <<
"\n Input parameters not valid.\n Ekin = "
1066 << ekin <<
" MeV, dE = " << de <<
" MeV, step length = "
1067 << step <<
" cm.\n";
1069 }
else if (
m_mass <= 0 || fabs(
m_q) <= 0) {
1070 std::cerr << hdr <<
"\n Track parameters not valid.\n Mass = "
1071 <<
m_mass <<
" eV, charge = " <<
m_q <<
".\n";
1074 std::cerr << hdr <<
"\n Gas parameters not valid.\n A = " <<
m_a
1075 <<
", Z = " <<
m_z <<
" density = " <<
m_density <<
" g/cm3.\n";
1080 const double rkin = 1.e6 * ekin /
m_mass;
1081 const double gamma = 1. + rkin;
1082 const double beta2 = rkin > 1.e-5 ? 1. - 1. / (gamma * gamma) : 2. * rkin;
1085 const double rm = ElectronMass /
m_mass;
1086 const double emax = 2 * ElectronMass * 1.e-6 * beta2 * gamma * gamma /
1087 (1. + 2 * gamma * rm + rm * rm);
1089 const double fconst = 0.1534;
1092 double rkappa = xi / emax;
1095 double stpnow = step;
1096 const unsigned int nMaxIter = 10;
1097 for (
unsigned int iter = 0; iter < nMaxIter; ++iter) {
1101 PrintSettings(hdr, denow, stpnow, ekin, beta2, gamma,
m_a,
m_z,
m_density,
1105 double rknew = rkappa;
1106 if (m_model <= 0 || m_model > 4) {
1111 const double xlmin = -3.;
1112 const double exponent = -xlmin - 1. + Gamma - beta2 - denow / xi;
1113 const double rklim = exponent < -expmax ? 0. : exp(exponent);
1114 stpmin = stpnow * (rklim / rkappa);
1116 std::cout << hdr <<
"Landau distribution is imposed.\n kappa_min = "
1117 << rklim <<
", d_min = " << stpmin <<
" cm.\n";
1121 const double xlmin = StepVavilov(rkappa);
1122 const double exponent = -xlmin - 1. + Gamma - beta2 - denow / xi;
1123 const double rklim = exponent < -expmax ? 0. : exp(exponent);
1124 stpmin = stpnow * (rklim / rkappa);
1126 rknew = xinew / emax;
1128 std::cout << hdr <<
"Vavilov distribution is imposed.\n kappa_min = "
1129 << rklim <<
", d_min = " << stpmin <<
" cm\n kappa_new = "
1130 << rknew <<
", xi_new = " << xinew <<
" MeV.\n";
1132 if (stpmin > stpnow * 1.1) {
1133 if (
m_debug) std::cout << hdr <<
"Step size increase. New pass.\n";
1138 stpmin = stpnow * 16 * xi * emax * (1 - 0.5 * beta2) / (denow * denow);
1140 std::cout << hdr <<
"Gaussian distribution is imposed.\n";
1141 printf(
"\td_min = %g cm.\n\tsigma/mu_old = %g, sigma/mu_min = %g\n",
1142 stpmin, sqrt(xi * emax * (1 - 0.5 * beta2)) / de,
1145 emax * (1 - 0.5 * beta2)) /
1146 (stpmin * denow / stpnow));
1148 }
else if (rkappa < 0.05) {
1150 const double xlmin = -3.;
1151 const double exponent = -xlmin - 1. + Gamma - beta2 - denow / xi;
1152 const double rklim = exponent < -expmax ? 0. : exp(exponent);
1153 stpmin = stpnow * (rklim / rkappa);
1155 rknew = xinew / emax;
1157 std::cout << hdr <<
"Landau distribution automatic.\n kappa_min = "
1158 << rklim <<
", d_min = " << stpmin <<
" cm.\n";
1160 if (rknew > 0.05 || stpmin > stpnow * 1.1) {
1163 std::cout << hdr <<
"Model change or step increase. New pass.\n";
1166 }
else if (rkappa < 5) {
1168 const double xlmin = StepVavilov(rkappa);
1169 const double exponent = -xlmin - 1. + Gamma - beta2 - denow / xi;
1170 const double rklim = exponent < -expmax ? 0. : exp(exponent);
1171 stpmin = stpnow * (rklim / rkappa);
1173 rknew = xinew / emax;
1175 std::cout << hdr <<
"Vavilov distribution automatic.\n kappa_min = "
1176 << rklim <<
", d_min = " << stpmin <<
" cm\n kappa_new = "
1177 << rknew <<
", xi_new = " << xinew <<
" MeV.\n";
1179 if (rknew > 5 || stpmin > stpnow * 1.1) {
1182 std::cout << hdr <<
"Model change or step increase. New pass.\n";
1187 stpmin = stpnow * 16 * xi * emax * (1 - 0.5 * beta2) / (denow * denow);
1189 std::cout << hdr <<
"Gaussian distribution automatic.\n";
1190 printf(
"\td_min = %g cm.\n\tsigma/mu_old = %g, sigma/mu_min = %g\n",
1191 stpmin, sqrt(xi * emax * (1 - 0.5 * beta2)) / de,
1194 emax * (1 - 0.5 * beta2)) /
1195 (stpmin * denow / stpnow));
1199 if (stpnow > stpmin) {
1201 std::cout << hdr <<
"Step size ok, minimum: " << stpmin <<
" cm\n";
1207 std::cerr << hdr <<
"\nStep size must be increased to "
1208 << stpmin <<
"cm.\n";
1215 denow *= stpmin / stpnow;
1217 if (
m_debug) std::cout << hdr <<
"Iteration " << iter <<
"\n";
1218 if (iter == nMaxIter - 1) {
1220 std::cerr << hdr <<
"\n No convergence reached on step size.\n";
1227 const double step)
const {
1240 const std::string hdr =
"TrackSrim::RndmEnergyLoss: ";
1242 if (ekin <= 0 || de <= 0 || step <= 0) {
1243 std::cerr << hdr <<
"\n Input parameters not valid.\n Ekin = "
1244 << ekin <<
" MeV, dE = " << de <<
" MeV, step length = "
1245 << step <<
" cm.\n";
1247 }
else if (
m_mass <= 0 || fabs(
m_q) <= 0) {
1248 std::cerr << hdr <<
"\n Track parameters not valid.\n Mass = "
1249 <<
m_mass <<
" MeV, charge = " <<
m_q <<
".\n";
1252 std::cerr << hdr <<
"\n Material parameters not valid.\n A = " <<
m_a
1253 <<
", Z = " <<
m_z <<
", density = " <<
m_density <<
" g/cm3.\n";
1257 const double rkin = 1.e6 * ekin /
m_mass;
1258 const double gamma = 1. + rkin;
1259 const double beta2 = rkin > 1.e-5 ? 1. - 1. / (gamma * gamma) : 2. * rkin;
1262 const double rm = ElectronMass /
m_mass;
1263 const double emax = 2 * ElectronMass * 1.e-6 * beta2 * gamma * gamma /
1264 (1. + 2 * gamma * rm + rm * rm);
1266 const double fconst = 0.1534;
1269 const double rkappa = xi / emax;
1272 PrintSettings(hdr, de, step, ekin, beta2, gamma,
m_a,
m_z,
m_density,
m_q,
1273 m_mass, emax, xi, rkappa);
1276 if (m_model <= 0 || m_model > 4) {
1278 if (
m_debug) std::cout << hdr <<
"Fixed energy loss.\n";
1281 if (
m_debug) std::cout << hdr <<
"Landau imposed.\n";
1282 const double xlmean = -(log(rkappa) + beta2 + 1. - Gamma);
1286 if (
m_debug) std::cout << hdr <<
"Vavilov imposed.\n";
1287 if (rkappa > 0.01 && rkappa < 12) {
1289 rndde += xi * (xvav + log(rkappa) + beta2 + (1 - Gamma));
1293 if (
m_debug) std::cout << hdr <<
"Gaussian imposed.\n";
1294 rndde +=
RndmGaussian(0., sqrt(xi * emax * (1 - 0.5 * beta2)));
1295 }
else if (rkappa < 0.05) {
1297 if (
m_debug) std::cout << hdr <<
"Landau automatic.\n";
1298 const double xlmean = -(log(rkappa) + beta2 + (1 - Gamma));
1299 const double par[] = {0.50884, 1.26116, 0.0346688, 1.46314,
1300 0.15088e-2, 1.00324, -0.13049e-3};
1301 const double xlmax = par[0] + par[1] * xlmean + par[2] * xlmean * xlmean +
1302 par[6] * xlmean * xlmean * xlmean +
1303 (par[3] + xlmean * par[4]) * exp(par[5] * xlmean);
1305 for (
unsigned int iter = 0; iter < 100; ++iter) {
1306 if (xlan < xlmax)
break;
1309 rndde += xi * (xlan - xlmean);
1310 }
else if (rkappa < 5) {
1316 if (
m_debug) std::cout << hdr <<
"Vavilov fast automatic.\n";
1318 rndde += xi * (xvav + log(rkappa) + beta2 + (1 - Gamma));
1321 if (
m_debug) std::cout << hdr <<
"Gaussian automatic.\n";
1322 rndde =
RndmGaussian(de, sqrt(xi * emax * (1 - 0.5 * beta2)));
1326 std::cout << hdr <<
"Energy loss generated = " << rndde <<
" MeV.\n";
1331 double& tcls,
int& n,
double& e,
double& extra) {
1333 printf(
"Current cluster: %d, array size: %ld",
Abstract base class for media.
bool IsInArea(const double x, const double y, const double z)
Check if a point is inside the user area.
bool GetMedium(const double x, const double y, const double z, Medium *&medium)
Get the medium at (x, y, z).
bool GetArea(double &xmin, double &ymin, double &zmin, double &xmax, double &ymax, double &zmax)
Return the current user area.
std::vector< double > m_longstraggle
Longitudinal straggling [cm].
double RndmEnergyLoss(const double ekin, const double de, const double step) const
virtual bool NewTrack(const double x0, const double y0, const double z0, const double t0, const double dx0, const double dy0, const double dz0)
unsigned int m_currcluster
Index of the next cluster to be returned.
std::vector< double > m_hdloss
Hadronic energy loss [MeV cm2/g].
void SetDensity(const double density)
Set/get the density [g/cm3] of the target medium.
std::vector< double > m_range
Projected range [cm].
double DedxHD(const double e) const
std::vector< cluster > m_clusters
std::vector< double > m_emloss
EM energy loss [MeV cm2/g].
virtual bool GetCluster(double &xcls, double &ycls, double &zcls, double &tcls, int &n, double &e, double &extra)
double m_mass
Mass of ion [MeV].
bool m_chargeset
Charge gas been defined.
bool SmallestStep(double ekin, double de, double step, double &stpmin)
double m_fano
Fano factor [-].
bool PreciseLoss(const double step, const double estart, double &deem, double &dehd) const
double m_work
Work function [eV].
double m_density
Density [g/cm3].
bool m_useTransStraggle
Include transverse straggling.
int m_nsize
Targeted cluster size.
std::vector< double > m_ekin
Energy in energy loss table [MeV].
std::vector< double > m_transstraggle
Transverse straggling [cm].
bool EstimateRange(const double ekin, const double step, double &stpmax)
bool m_useLongStraggle
Include longitudinal straggling.
double m_a
A and Z of the gas.
int m_maxclusters
Maximum number of clusters allowed (infinite if 0)
double DedxEM(const double e) const
bool ReadFile(const std::string &file)
Abstract base class for track generation.
double GetKineticEnergy() const
double Divdif(const std::vector< double > &f, const std::vector< double > &a, int nn, double x, int mm)
double RndmHeedWF(const double w, const double f)
double RndmVavilov(const double rkappa, const double beta2)
Draw a random number from a Vavilov distribution.
void RndmDirection(double &dx, double &dy, double &dz, const double length=1.)
Draw a random (isotropic) direction vector.
double RndmGaussian()
Draw a Gaussian random variate with mean zero and standard deviation one.
double RndmLandau()
Draw a random number from a Landau distribution.