68 const double t0,
const double dx0,
const double dy0,
75 std::cerr <<
m_className <<
"::NewTrack: Sensor is not defined.\n";
82 std::cerr <<
m_className <<
"::NewTrack: No medium at initial position.\n";
98 std::cout <<
" Ionisation potential: " << eMinIon <<
" eV.\n";
109 const double dp = sqrt(dxp * dxp + dyp * dyp + dzp * dzp);
114 const double scale = 1. / dp;
129 <<
" Particle energy: " << ep <<
" eV\n"
130 <<
" Collision rate: " << tcf <<
" / ns\n"
131 <<
" Collisions / cm: "
132 << tcf / (SpeedOfLight * beta) <<
"\n";
138 const double step = SpeedOfLight * beta * dt;
145 double cthetap = -99.;
146 double sthetap = -99.;
169 int64_t ionmodel = 0;
172 &an, &ps, &wklm, &nc0, &ec0, &ng1, &eg1, &ng2, &eg2,
173 &dstfl, &ipn, &kg1, &lg1, &igshel, &ionmodel, &ilvl);
176 double eout = 0., egamma = 0.;
177 double dxe = 0., dye = 0., dze = 0.;
178 double dxg = 0., dyg = 0., dzg = 0.;
179 Degrade::brems(&izbr, &ep, &dxp, &dyp, &dzp, &eout, &dxe, &dye, &dze,
180 &egamma, &dxg, &dyg, &dzg);
188 if (ia == 2 || ia == 7 || ia == 12 || ia == 17 ||
189 ia == 22 || ia == 27) {
196 double esec = wpl * tan(
RndmUniform() * atan((ep - ein) / (2. * wpl)));
197 esec = wpl * pow(esec / wpl, 0.9524);
203 }
else if (index == 2) {
205 cthetap = (ctheta0 + ps) / (1. + ps * ctheta0);
209 sthetap = sin(acos(cthetap));
210 const double gammas = (ElectronMass + esec) / ElectronMass;
212 const double sthetas = std::min(sthetap * sqrt(ep / esec) *
214 double thetas = asin(sthetas);
218 double dxs = 0., dys = 0., dzs = 0.;
219 Degrade::drcos(&dxp, &dyp, &dzp, &thetas, &phis, &dxs, &dys, &dzs);
222 MakeElectron(esec, xp, yp, zp, tp, dxs, dys, dzs));
227 const double eavg = eg2 / ng2;
228 for (int64_t j = 0; j < ng2; ++j) {
231 const double stheta = sin(acos(ctheta));
233 const double dx = cos(phi) * stheta;
234 const double dy = sin(phi) * stheta;
235 const double dz = ctheta;
237 MakeElectron(eavg, xp, yp, zp, tp, dx, dy, dz));
241 const double eavg = eg1 / ng1;
244 for (int64_t j = 0; j < ng1; ++j) {
247 const double stheta = sin(acos(ctheta));
249 const double dx = cos(phi) * stheta;
250 const double dy = sin(phi) * stheta;
251 const double dz = ctheta;
253 const double sthetafl = sin(acos(cthetafl));
255 const double xs = dfl * sthetafl * cos(phifl);
256 const double ys = dfl * sthetafl * sin(phifl);
257 const double zs = dfl * cthetafl;
258 const double ts = dfl / SpeedOfLight;
260 MakeElectron(eavg, xs, ys, zs, ts, dx, dy, dz));
265 const double eavg = ec0 / nc0;
266 for (int64_t j = 0; j < nc0; ++j) {
269 const double stheta = sin(acos(ctheta));
271 const double dx = cos(phi) * stheta;
272 const double dy = sin(phi) * stheta;
273 const double dz = ctheta;
275 MakeElectron(eavg, xp, yp, zp, tp, dx, dy, dz));
279 }
else if (ia == 4 || ia == 9 || ia == 14 || ia == 19 ||
280 ia == 24 || ia == 29) {
282 const double eExc = rgas * ein;
285 if (igas <= 0 || igas >= 6) {
287 <<
"Could not retrieve gas index.\n";
294 constexpr double penfra3 = 0.;
295 const bool penning =
m_penning && eExc > eMinIon &&
296 penfra1 > 0. &&
m_nGas > 1;
306 const double stheta = sin(acos(ctheta));
308 const double dx = cos(phi) * stheta;
309 const double dy = sin(phi) * stheta;
310 const double dz = ctheta;
322 MakeElectron(4., xs, ys, zs, ts, dx, dy, dz));
332 MakeExcitation(eExc, xp, yp, zp, tp));
337 double s1 = 1. + gamma * (rgas - 1.);
338 double s2 = (s1 * s1) / (s1 - 1.);
344 }
else if (index == 2) {
347 cthetap = (ctheta0 + ps) / (1. + ps * ctheta0);
352 sthetap = sin(acos(cthetap));
355 double sphi0 = sin(phi0);
356 double cphi0 = cos(phi0);
357 if (ep < ein) ein = 0.;
358 double arg1 = std::max(1. - s1 * ein / ep, 1.e-20);
359 const double d = 1. - cthetap * sqrt(arg1);
360 double e1 = std::max(ep * (1. - ein / (s1 * ep) - 2. * d / s2), 1.e-20);
361 const double q = std::min(sqrt((ep / e1) * arg1) / s1, 1.);
362 const double theta = asin(q * sthetap);
363 double ctheta = cos(theta);
365 const double u = (s1 - 1.) * (s1 - 1.) / arg1;
366 if (cthetap * cthetap > u) ctheta = -ctheta;
368 const double stheta = sin(theta);
371 double dz1 = std::min(dzp, 1.);
372 double argz = sqrt(dx1 * dx1 + dy1 * dy1);
375 dxp = cphi0 * stheta;
376 dyp = sphi0 * stheta;
378 dzp = dz1 * ctheta + argz * stheta * sphi0;
379 dyp = dy1 * ctheta + (stheta / argz) * (dx1 * cphi0 - dy1 * dz1 * sphi0);
380 dxp = dx1 * ctheta - (stheta / argz) * (dy1 * cphi0 + dx1 * dz1 * sphi0);
387 for (
const auto& delta : cluster.deltaElectrons) {
389 delta.t, delta.energy,
390 delta.dx, delta.dy, delta.dz);
391 cluster.electrons.insert(cluster.electrons.end(),
392 secondaries.first.begin(),
393 secondaries.first.end());
394 cluster.excitations.insert(cluster.excitations.end(),
395 secondaries.second.begin(),
396 secondaries.second.end());
420 std::cerr <<
m_className <<
"::Initialise: Null pointer.\n";
423 if (!medium->
IsGas()) {
424 std::cerr <<
m_className <<
"::Initialise: Medium "
425 << medium->
GetName() <<
" is not a gas.\n";
433 std::array<int64_t, 6> ngas;
434 std::array<double, 6> frac;
436 if (nComponents < 1) {
437 std::cerr <<
m_className <<
"::Initialise: Invalid gas mixture.\n";
440 std::vector<unsigned int> notdone = {
441 13, 17, 20, 22, 24, 26, 27, 28, 32, 33, 37, 38, 39, 40, 41, 42, 43,
442 50, 51, 53, 54, 55, 56, 57};
443 for (
unsigned int i = 0; i < nComponents; ++i) {
448 if (std::find(notdone.begin(), notdone.end(), ngas[i]) != notdone.end()) {
450 <<
" Cross-sections for " << name
451 <<
" are not yet implemented.\n";
457 int64_t ng = nComponents;
473 int64_t iverb = verbose ? 1 : 0;
475 &ngas[0], &ngas[1], &ngas[2], &ngas[3], &ngas[4], &ngas[5],
476 &frac[0], &frac[1], &frac[2], &frac[3], &frac[4], &frac[5],
477 &temperature, &pressure, &etot, &btot, &bang,
478 &jcmp, &jray, &jpap, &jbrm, &jecasc, &iverb);
517 const double x0,
const double y0,
const double z0,
const double t0,
518 const double e0,
const double dx0,
const double dy0,
const double dz0) {
521 std::vector<Electron> thermalisedElectrons;
522 std::vector<Excitation> excitations;
525 std::cerr <<
m_className <<
"::TransportDeltaElectron: "
526 <<
"Sensor is not defined.\n";
527 return std::make_pair(thermalisedElectrons, excitations);
532 std::cout <<
" Ionisation potential: " << eMinIon <<
" eV.\n";
537 for (int64_t j = 1; j <= 20000; ++j) {
540 flim = std::max(flim, tcf + tcfn);
544 std::vector<Electron> deltas;
545 deltas.emplace_back(MakeElectron(e0, x0, y0, z0, t0, dx0, dy0, dz0));
546 std::vector<Electron> newDeltas;
548 while (!deltas.empty()) {
549 for (
const auto& delta : deltas) {
554 double e1 = delta.energy;
555 double dx1 = delta.dx;
556 double dy1 = delta.dy;
557 double dz1 = delta.dz;
559 bool attached =
false;
563 bool ionised =
false;
568 const double gamma1 = (ElectronMass + e1) / ElectronMass;
569 const double beta1 = sqrt(1. - 1. / (gamma1 * gamma1));
573 if (e2 < 0.) e2 = 0.001;
580 if (r5 > tcf / flim) {
588 const double gamma2 = (ElectronMass + e2) / ElectronMass;
590 const double beta2 = sqrt(1. - 1. / (gamma2 * gamma2));
591 const double c6 = beta1 / beta2;
592 double dx2 = dx1 * c6;
593 double dy2 = dy1 * c6;
594 double dz2 = dz1 * c6;
595 const double a = dt * SpeedOfLight * beta1;
596 double x2 = x1 + dx1 * a;
597 double y2 = y1 + dy1 * a;
598 double z2 = z1 + dz1 * a;
632 int64_t ionmodel = 0;
635 &an, &ps, &wklm, &nc0, &ec0, &ng1, &eg1, &ng2, &eg2,
636 &dstfl, &ipn, &kg1, &lg1, &igshel, &ionmodel,
641 for (kg = 1; kg <= 6; ++kg) {
642 if (ia == (kg * 5) - 1)
break;
645 double dxe = 0., dye = 0., dze = 0.;
646 double dxg = 0., dyg = 0., dzg = 0.;
647 double eout = 0., egamma = 0.;
649 &dxe, &dye, &dze, &egamma, &dxg, &dyg, &dzg);
662 &dxg, &dyg, &dzg, &ilow);
666 for (int64_t k = 0; k <= 400; ++k) {
668 double ee = 0., xe = 0., ye = 0., ze = 0., te = 0.;
670 &dxe, &dye, &dze, &iok);
672 newDeltas.emplace_back(
673 MakeElectron(ee, xe, ye, ze, te, dxe, dye, dze));
678 if (e2 < ein) ein = e2 - 0.0001;
683 }
else if (ipn == 0) {
685 const double eExc = rgas * ein;
688 if (igas <= 0 || igas >= 6) {
689 std::cerr <<
m_className <<
"::TransportDeltaElectron: "
690 <<
"Could not retrieve gas index.\n";
697 constexpr double penfra3 = 0.;
698 const bool penning =
m_penning && eExc > eMinIon &&
699 penfra1 > 0. &&
m_nGas > 1;
716 newDeltas.emplace_back(
717 MakeElectron(1., xs, ys, zs, ts, dx1, dy1, dz1));
722 excitations.emplace_back(
723 MakeExcitation(eExc, x2, y2, z2, t2));
727 }
else if (ipn == 1) {
728 const double eistr = ein;
735 esec = wpl * tan(
RndmUniform() * atan((e2 - ein) / (2. * wpl)));
736 esec = wpl * pow(esec / wpl, 0.9524);
740 newDeltas.emplace_back(
741 MakeElectron(esec, x2, y2, z2, t2, dx2, dy2, dz2));
743 jsec = newDeltas.size() - 1;
750 for (int64_t k = 1; k <= 400; ++k) {
752 double ee = 0., xe = 0., ye = 0., ze = 0., te = 0.;
753 double dxe = 0., dye = 0., dze = 0.;
755 &dxe, &dye, &dze, &iok);
757 newDeltas.emplace_back(
758 MakeElectron(ee, xe, ye, ze, te, dxe, dye, dze));
767 const double eav = eg2 / ng2;
768 for (int64_t j = 0; j < ng2; ++j) {
770 const double stheta = sin(acos(ctheta));
772 const double dx = cos(phi) * stheta;
773 const double dy = sin(phi) * stheta;
774 const double dz = ctheta;
775 newDeltas.emplace_back(
776 MakeElectron(eav, x2, y2, z2, t2, dx, dy, dz));
780 const double eav = eg1 / ng1;
782 for (int64_t j = 0; j < ng1; ++j) {
784 const double sthetafl = sin(acos(cthetafl));
786 const double xs = x2 + dfl * sthetafl * cos(phifl);
787 const double ys = y2 + dfl * sthetafl * sin(phifl);
788 const double zs = z2 + dfl * cthetafl;
789 const double ts = t2;
791 const double stheta = sin(acos(ctheta));
793 const double dx = cos(phi) * stheta;
794 const double dy = sin(phi) * stheta;
795 const double dz = ctheta;
796 newDeltas.emplace_back(
797 MakeElectron(eav, xs, ys, zs, ts, dx, dy, dz));
802 const double eav = ec0 / nc0;
803 for (int64_t j = 0; j < nc0; ++j) {
805 const double stheta = sin(acos(ctheta));
807 const double dx = cos(phi) * stheta;
808 const double dy = sin(phi) * stheta;
809 const double dz = ctheta;
810 newDeltas.emplace_back(
811 MakeElectron(eav, x2, y2, z2, t2, dx, dy, dz));
818 const double s1 = 1. + gamma2 * (rgas - 1.);
819 const double s2 = (s1 * s1) / (s1 - 1.);
825 }
else if (index == 2) {
828 ctheta0 = (ctheta0 + ps) / (1. + ps * ctheta0);
833 const double theta0 = acos(ctheta0);
835 const double sphi0 = sin(phi0);
836 const double cphi0 = cos(phi0);
837 if (e2 < ein) ein = 0.;
838 const double arg1 = std::max(1. - s1 * ein / e2, 1.e-20);
839 const double d = 1. - ctheta0 * sqrt(arg1);
841 e1 = std::max(e2 * (1. - ein / (s1 * e2) - 2. * d / s2), 1.e-20);
842 const double q = std::min(sqrt((e2/ e1) * arg1) / s1, 1.);
843 const double theta = asin(q * sin(theta0));
844 double ctheta = cos(theta);
846 const double u = (s1 - 1.) * (s1 - 1.) / arg1;
847 if (ctheta0 * ctheta0 > u) ctheta = -ctheta;
849 double stheta = sin(theta);
850 dz2 = std::min(dz2, 1.);
851 const double argz = sqrt(dx2 * dx2 + dy2 * dy2);
853 dz1 = dz2 * ctheta + argz * stheta * sphi0;
854 dy1 = dy2 * ctheta + (stheta / argz) * (dx2 * cphi0 - dy2 * dz2 * sphi0);
855 dx1 = dx2 * ctheta - (stheta / argz) * (dy2 * cphi0 + dx2 * dz2 * sphi0);
858 double sthetas = std::min(stheta * sqrt(e1 / esec), 1.);
859 double cthetas = cos(asin(sthetas));
860 if (ctheta < 0.0) cthetas = -cthetas;
861 double phis = phi0 + Pi;
862 if (phis > TwoPi) phis = phi0 - TwoPi;
863 const double sphis = sin(phis);
864 const double cphis = cos(phis);
865 newDeltas[jsec].dz = dz2 * cthetas + argz * sthetas * sphis;
866 newDeltas[jsec].dy = dy2 * cthetas +
867 (sthetas / argz) * (dx2 * cphis - dy2 * dz2 * sphis);
868 newDeltas[jsec].dx = dx2 * cthetas -
869 (sthetas / argz) * (dy2 * cphis + dx2 * dz2 * sphis);
873 dx1 = cphi0 * stheta;
874 dy1 = sphi0 * stheta;
877 double sthetas = std::min(stheta * sqrt(e1 / esec), 1.);
878 double cthetas = cos(asin(sthetas));
879 if (ctheta < 0.) cthetas = -cthetas;
880 double phis = phi0 + Pi;
881 if (phis > TwoPi) phis = phi0 - TwoPi;
882 newDeltas[jsec].dz = cthetas;
883 newDeltas[jsec].dx = cos(phis) * sthetas;
884 newDeltas[jsec].dy = sin(phis) * sthetas;
888 if (attached)
continue;
889 thermalisedElectrons.emplace_back(
890 MakeElectron(e1, x1, y1, z1, t1, dx1, dy1, dz1));
892 deltas.swap(newDeltas);
895 return std::make_pair(thermalisedElectrons, excitations);
void deginit(int64_t *ng, int64_t *nevt, int64_t *mip, int64_t *idvec, int32_t *iseed, double *e0, double *et, double *ec, int64_t *ngas1, int64_t *ngas2, int64_t *ngas3, int64_t *ngas4, int64_t *ngas5, int64_t *ngas6, double *frac1, double *frac2, double *frac3, double *frac4, double *frac5, double *frac6, double *t0, double *p0, double *etot, double *btot, double *bang, int64_t *jcmp, int64_t *jray, int64_t *jpap, int64_t *jbrm, int64_t *jecasc, int64_t *iverb)