13double AvalancheMC::c1 = ElectronMass / (SpeedOfLight * SpeedOfLight);
22 m_hasTimeWindow(false),
28 m_nEndpointsElectrons(0),
34 m_useInducedCharge(false),
35 m_useEquilibration(true),
37 m_useAttachment(false),
40 m_withElectrons(true),
42 m_scaleElectronSignal(1.),
43 m_scaleHoleSignal(1.),
47 m_className =
"AvalancheMC";
49 m_drift.reserve(10000);
55 std::cerr << m_className <<
"::SetSensor:\n";
56 std::cerr <<
" Sensor pointer is null.\n";
66 std::cerr << m_className <<
"::EnablePlotting:\n";
67 std::cerr <<
" Viewer pointer is null.\n";
78 m_usePlotting =
false;
85 std::cerr << m_className <<
"::SetTimeSteps:\n";
86 std::cerr <<
" Specified step size is too small.\n";
87 std::cerr <<
" Using default (20 ps) instead.\n";
91 std::cout << m_className <<
"::SetTimeSteps:\n";
92 std::cout <<
" Step size set to " << d <<
" ns.\n";
102 std::cerr << m_className <<
"::SetDistanceSteps:\n";
103 std::cerr <<
" Specified step size is too small.\n";
104 std::cerr <<
" Using default (10 um) instead.\n";
108 std::cout << m_className <<
"::SetDistanceSteps:\n";
109 std::cout <<
" Step size set to " << d <<
" cm.\n";
119 std::cerr << m_className <<
"::SetCollisionSteps:\n";
120 std::cerr <<
" Number of collisions to be skipped set to "
121 <<
" default value (100).\n";
125 std::cout << m_className <<
"::SetCollisionSteps:\n";
126 std::cout <<
" Number of collisions to be skipped set to " << n
135 if (
fabs(t1 - t0) < Small) {
136 std::cerr << m_className <<
"::SetTimeWindow:\n";
137 std::cerr <<
" Time interval must be greater than zero.\n";
141 m_tMin = std::min(t0, t1);
142 m_tMax = std::max(t0, t1);
143 m_hasTimeWindow =
true;
149 double& z,
double& t) {
152 std::cerr << m_className <<
"::GetDriftLinePoint:\n";
153 std::cerr <<
" Index is outside the range.\n";
164 double& z0,
double& t0,
double& x1,
165 double& y1,
double& z1,
double& t1,
168 if (i >= m_nEndpointsHoles) {
169 std::cerr << m_className <<
"::GetHoleEndpoint:\n";
170 std::cerr <<
" Endpoint " << i <<
" does not exist.\n";
174 x0 = m_endpointsHoles[i].x0;
175 x1 = m_endpointsHoles[i].x1;
176 y0 = m_endpointsHoles[i].y0;
177 y1 = m_endpointsHoles[i].y1;
178 z0 = m_endpointsHoles[i].z0;
179 z1 = m_endpointsHoles[i].z1;
180 t0 = m_endpointsHoles[i].t0;
181 t1 = m_endpointsHoles[i].t1;
182 status = m_endpointsHoles[i].status;
186 double& z0,
double& t0,
double& x1,
double& y1,
187 double& z1,
double& t1,
int& status)
const {
189 if (i >= m_nEndpointsIons) {
190 std::cerr << m_className <<
"::GetIonEndpoint:\n";
191 std::cerr <<
" Endpoint " << i <<
" does not exist.\n";
195 x0 = m_endpointsIons[i].x0;
196 x1 = m_endpointsIons[i].x1;
197 y0 = m_endpointsIons[i].y0;
198 y1 = m_endpointsIons[i].y1;
199 z0 = m_endpointsIons[i].z0;
200 z1 = m_endpointsIons[i].z1;
201 t0 = m_endpointsIons[i].t0;
202 t1 = m_endpointsIons[i].t1;
203 status = m_endpointsIons[i].status;
207 double& x0,
double& y0,
208 double& z0,
double& t0,
double& x1,
209 double& y1,
double& z1,
double& t1,
212 if (i >= m_nEndpointsElectrons) {
213 std::cerr << m_className <<
"::GetElectronEndpoint:\n";
214 std::cerr <<
" Endpoint " << i <<
" does not exist.\n";
218 x0 = m_endpointsElectrons[i].x0;
219 x1 = m_endpointsElectrons[i].x1;
220 y0 = m_endpointsElectrons[i].y0;
221 y1 = m_endpointsElectrons[i].y1;
222 z0 = m_endpointsElectrons[i].z0;
223 z1 = m_endpointsElectrons[i].z1;
224 t0 = m_endpointsElectrons[i].t0;
225 t1 = m_endpointsElectrons[i].t1;
226 status = m_endpointsElectrons[i].status;
230 const double z0,
const double t0) {
233 std::cerr << m_className <<
"::DriftElectron:\n";
234 std::cerr <<
" Sensor is not defined.\n";
238 m_endpointsElectrons.clear();
239 m_endpointsHoles.clear();
240 m_endpointsIons.clear();
241 m_nEndpointsElectrons = 0;
242 m_nEndpointsHoles = 0;
243 m_nEndpointsIons = 0;
249 if (!DriftLine(x0, y0, z0, t0, -1))
return false;
255 const double z0,
const double t0) {
258 std::cerr << m_className <<
"::DriftHole:\n";
259 std::cerr <<
" Sensor is not defined.\n";
263 m_endpointsElectrons.clear();
264 m_endpointsHoles.clear();
265 m_endpointsIons.clear();
266 m_nEndpointsElectrons = 0;
267 m_nEndpointsHoles = 0;
268 m_nEndpointsIons = 0;
274 if (!DriftLine(x0, y0, z0, t0, 1))
return false;
280 const double z0,
const double t0) {
283 std::cerr << m_className <<
"::DriftIon:\n";
284 std::cerr <<
" Sensor is not defined.\n";
288 m_endpointsElectrons.clear();
289 m_endpointsHoles.clear();
290 m_endpointsIons.clear();
291 m_nEndpointsElectrons = 0;
292 m_nEndpointsHoles = 0;
293 m_nEndpointsIons = 0;
299 if (!DriftLine(x0, y0, z0, t0, 2))
return false;
304bool AvalancheMC::DriftLine(
const double x0,
const double y0,
305 const double z0,
const double t0,
306 const int type,
const bool aval) {
309 double x = x0, y = y0, z = z0;
316 double ex = 0., ey = 0., ez = 0.;
318 double bx = 0., by = 0., bz = 0.;
320 double vx = 0., vy = 0., vz = 0., v = 0., vt = 0.;
322 double dl = 0., dt = 0.;
324 double dx = 0., dy = 0., dz = 0., d = 0.;
326 double phi, cphi, sphi;
327 double theta, ctheta, stheta;
342 m_drift.push_back(
point);
346 bool trapped =
false;
347 bool validAlphaEta =
false;
350 if (m_hasTimeWindow && (t0 < m_tMin || t0 > m_tMax)) {
351 std::cerr << m_className <<
"::DriftLine:\n";
352 std::cerr <<
" Starting time " << t0 <<
" is outside the specified\n";
353 std::cerr <<
" time window (" << m_tMin <<
", " << m_tMax <<
").\n";
355 abortReason = StatusOutsideTimeWindow;
359 m_sensor->
ElectricField(x, y, z, ex, ey, ez, medium, status);
362 std::cerr << m_className <<
"::DriftLine:\n";
363 std::cerr <<
" No drift medium at initial position (" << x <<
", " << y
364 <<
", " << z <<
").\n";
366 abortReason = StatusLeftDriftMedium;
369 double e =
sqrt(ex * ex + ey * ey + ez * ez);
371 std::cerr << m_className <<
"::DriftLine:\n";
372 std::cerr <<
" Electric field at initial position is too small:\n";
373 std::cerr <<
" ex = " << ex <<
" V/cm\n";
374 std::cerr <<
" ey = " << ey <<
" V/cm\n";
375 std::cerr <<
" ez = " << ez <<
" V/cm\n";
377 abortReason = StatusCalculationAbandoned;
382 bx *= Tesla2Internal;
383 by *= Tesla2Internal;
384 bz *= Tesla2Internal;
393 std::cerr << m_className <<
"::DriftLine:\n";
394 std::cerr <<
" Error calculating electron"
395 <<
" velocity or diffusion\n";
396 std::cerr <<
" at (" << x <<
", " << y <<
", " << z <<
")\n";
398 abortReason = StatusCalculationAbandoned;
401 }
else if (type == 1) {
404 std::cerr << m_className <<
"::DriftLine:\n";
405 std::cerr <<
" Error calculating hole"
406 <<
" velocity or diffusion\n";
407 std::cerr <<
" at (" << x <<
", " << y <<
", " << z <<
")\n";
409 abortReason = StatusCalculationAbandoned;
412 }
else if (type == 2) {
415 std::cerr << m_className <<
"::DriftLine:\n";
416 std::cerr <<
" Error calculating ion"
417 <<
" velocity or diffusion\n";
418 std::cerr <<
" at (" << x <<
", " << y <<
", " << z <<
")\n";
420 abortReason = StatusCalculationAbandoned;
424 std::cerr << m_className <<
"::DriftLine:\n";
425 std::cerr <<
" Unknown drift line type (" << type <<
").\n";
426 std::cerr <<
" Program bug!\n";
428 abortReason = StatusCalculationAbandoned;
432 std::cout << m_className <<
"::DriftLine:\n";
433 std::cout <<
" Drift velocity at " << x <<
", " << y <<
", " << z
434 <<
": " << vx <<
", " << vy <<
", " << vz <<
"\n";
436 v =
sqrt(vx * vx + vy * vy + vz * vz);
438 std::cerr << m_className <<
"::DriftLine:\n";
439 std::cerr <<
" Drift velocity at (" << x <<
", " << y <<
", " << z
440 <<
") is too small:\n";
441 std::cerr <<
" vx = " << vx <<
" cm/ns\n";
442 std::cerr <<
" vy = " << vy <<
" cm/ns\n";
443 std::cerr <<
" vz = " << vz <<
" cm/ns\n";
445 abortReason = StatusCalculationAbandoned;
450 switch (m_stepModel) {
465 std::cerr << m_className <<
"::DriftLine:\n";
466 std::cerr <<
" Unknown stepping model.\n";
471 if (m_useDiffusion) {
478 std::cout << m_className <<
"::DriftLine:\n";
479 std::cout <<
" Adding diffusion step "
480 << dx <<
", " << dy <<
", " << dz <<
"\n";
484 vt =
sqrt(vx * vx + vy * vy);
491 theta = atan2(vz, vt);
499 x += delta * vx + cphi * ctheta * dx - sphi * dy - cphi * stheta * dz;
500 y += delta * vy + sphi * ctheta * dx + cphi * dy - sphi * stheta * dz;
501 z += delta * vz + stheta * dx + ctheta * dz;
504 std::cout << m_className <<
"::DriftLine:\n";
505 std::cout <<
" New point: "
506 << x <<
", " << y <<
", " << z <<
"\n";
509 m_sensor->
ElectricField(x, y, z, ex, ey, ez, medium, status);
518 d =
sqrt(dx * dx + dy * dy + dz * dz);
524 while (d > BoundaryDistance) {
527 x =
point.x + dx * d;
528 y =
point.y + dy * d;
529 z =
point.z + dz * d;
531 m_sensor->
ElectricField(x, y, z, ex, ey, ez, medium, status);
543 m_drift.push_back(
point);
545 abortReason = StatusLeftDriftMedium;
547 std::cout << m_className <<
"::DriftLine:\n";
548 std::cout <<
" Particle left the drift medium.\n";
562 d =
sqrt(dx * dx + dy * dy + dz * dz);
568 while (d > BoundaryDistance) {
571 x =
point.x + dx * d;
572 y =
point.y + dy * d;
573 z =
point.z + dz * d;
586 m_drift.push_back(
point);
588 abortReason = StatusLeftDriftArea;
590 std::cout << m_className <<
"::DriftLine:\n";
591 std::cout <<
" Particle left the drift area.\n";
610 m_drift.push_back(
point);
612 abortReason = StatusLeftDriftMedium;
614 std::cout << m_className <<
"::DriftLine:\n";
615 std::cout <<
" Particle hit a wire.\n";
616 std::cout <<
" At " << xCross <<
", " << yCross <<
", " << zCross
622 e =
sqrt(ex * ex + ey * ey + ez * ez);
624 std::cerr << m_className <<
"::DriftLine:\n";
625 std::cerr <<
" Electric field at (" << x <<
", " << y <<
", " << z
626 <<
") is too small:\n";
627 std::cerr <<
" ex = " << ex <<
" V/cm\n";
628 std::cerr <<
" ey = " << ey <<
" V/cm\n";
629 std::cerr <<
" ez = " << ez <<
" V/cm\n";
631 abortReason = StatusCalculationAbandoned;
639 m_drift.push_back(
point);
643 if (m_hasTimeWindow &&
point.t > m_tMax) {
644 abortReason = StatusOutsideTimeWindow;
650 bx *= Tesla2Internal;
651 by *= Tesla2Internal;
652 bz *= Tesla2Internal;
657 unsigned int nElectronsOld = m_nElectrons;
658 unsigned int nHolesOld = m_nHoles;
659 unsigned int nIonsOld = m_nIons;
660 if ((type == -1 || type == 1) && (aval || m_useAttachment)) {
662 validAlphaEta = ComputeAlphaEta(type);
663 if (ok) ok = validAlphaEta;
665 const double probth = 0.01;
670 for (
unsigned int i = 0; i < m_nDrift - 1; ++i) {
677 int nDiv = int((m_drift[i].alpha + m_drift[i].eta) / probth);
678 if (nDiv < 1) nDiv = 1;
680 const double alpha = std::max(m_drift[i].alpha / nDiv, 0.);
681 const double eta = std::max(m_drift[i].eta / nDiv, 0.);
683 int neInit = ne, niInit = ni;
685 for (
int j = 0; j < nDiv; ++j) {
688 const int gain = int(
696 for (
int k = ne; k--;) {
711 }
else if (type == 1) {
717 m_drift[m_nDrift - 1].x = 0.5 * (m_drift[i].x + m_drift[i + 1].x);
718 m_drift[m_nDrift - 1].y = 0.5 * (m_drift[i].y + m_drift[i + 1].y);
719 m_drift[m_nDrift - 1].z = 0.5 * (m_drift[i].z + m_drift[i + 1].z);
725 if (ne - neInit >= 1) {
727 m_drift[i].ne = ne - neInit;
728 m_nElectrons += ne - neInit;
729 }
else if (type == 1) {
730 m_drift[i].nh = ne - neInit;
731 m_nHoles += ne - neInit;
733 m_drift[i].ni = ne - neInit;
734 m_nIons += ne - neInit;
737 if (ni - niInit >= 1) {
740 m_drift[i].ni = ni - niInit;
741 m_nIons += ni - niInit;
743 m_drift[i].nh = ni - niInit;
744 m_nHoles += ni - niInit;
747 m_drift[i].ne = ni - niInit;
748 m_nElectrons += ni - niInit;
753 abortReason = StatusAttached;
755 std::cout << m_className <<
"::DriftLine:\n";
756 std::cout <<
" Particle attached.\n";
757 std::cout <<
" At " << m_drift[m_nDrift - 1].x <<
", "
758 << m_drift[m_nDrift - 1].y <<
", " << m_drift[m_nDrift - 1].z
773 endPoint.status = abortReason;
775 endPoint.x1 = m_drift[m_nDrift - 1].x;
776 endPoint.y1 = m_drift[m_nDrift - 1].y;
777 endPoint.z1 = m_drift[m_nDrift - 1].z;
778 endPoint.t1 = m_drift[m_nDrift - 1].t;
781 const int nNewElectrons = m_nElectrons - nElectronsOld;
782 const int nNewHoles = m_nHoles - nHolesOld;
783 const int nNewIons = m_nIons - nIonsOld;
784 std::cout << m_className <<
"::DriftLine:\n";
785 std::cout <<
" Produced\n"
786 <<
" " << nNewElectrons <<
" electrons,\n"
787 <<
" " << nNewHoles <<
" holes, and\n"
788 <<
" " << nNewIons <<
" ions\n"
789 <<
" along the drift line from \n"
790 <<
" (" << endPoint.x0 <<
", " << endPoint.y0 <<
", "
791 << endPoint.z0 <<
") to \n"
792 <<
" (" << endPoint.x1 <<
", " << endPoint.y1 <<
", "
793 << endPoint.z1 <<
").\n";
797 m_endpointsElectrons.push_back(endPoint);
798 ++m_nEndpointsElectrons;
799 }
else if (type == 1) {
800 m_endpointsHoles.push_back(endPoint);
802 }
else if (type == 2) {
803 m_endpointsIons.push_back(endPoint);
810 ComputeSignal(1. * m_scaleIonSignal);
811 }
else if (type == 1) {
812 ComputeSignal(1. * m_scaleHoleSignal);
813 }
else if (type < 0) {
814 ComputeSignal(-1. * m_scaleElectronSignal);
817 if (m_useInducedCharge) {
819 ComputeInducedCharge(1. * m_scaleIonSignal);
820 }
else if (type == 1) {
821 ComputeInducedCharge(1. * m_scaleHoleSignal);
822 }
else if (type < 0) {
823 ComputeInducedCharge(-1. * m_scaleElectronSignal);
828 if (m_usePlotting && m_nDrift > 0) {
833 }
else if (type == 1) {
834 m_viewer->
NewHoleDriftLine(m_nDrift, jL, m_drift[0].x, m_drift[0].y, m_drift[0].z);
836 m_viewer->
NewIonDriftLine(m_nDrift, jL, m_drift[0].x, m_drift[0].y, m_drift[0].z);
838 for (
unsigned int iP = 0; iP < m_nDrift; ++iP) {
839 m_viewer->
SetDriftLinePoint(jL, iP, m_drift[iP].x, m_drift[iP].y, m_drift[iP].z);
843 if (!ok)
return false;
849 const double z0,
const double t0,
862 m_aval.push_back(
point);
864 m_endpointsElectrons.clear();
865 m_endpointsHoles.clear();
866 m_endpointsIons.clear();
867 m_nEndpointsElectrons = 0;
868 m_nEndpointsHoles = 0;
869 m_nEndpointsIons = 0;
880 const double z0,
const double t0,
881 const bool electrons) {
893 m_aval.push_back(
point);
895 m_endpointsElectrons.clear();
896 m_endpointsHoles.clear();
897 m_endpointsIons.clear();
898 m_nEndpointsElectrons = 0;
899 m_nEndpointsHoles = 0;
900 m_nEndpointsIons = 0;
906 m_withElectrons = electrons;
911 const double z0,
const double t0) {
923 m_aval.push_back(
point);
925 m_endpointsElectrons.clear();
926 m_endpointsHoles.clear();
927 m_endpointsIons.clear();
928 m_nEndpointsElectrons = 0;
929 m_nEndpointsHoles = 0;
930 m_nEndpointsIons = 0;
936 m_withElectrons = m_withHoles =
true;
940bool AvalancheMC::Avalanche() {
944 std::cerr << m_className <<
"::Avalanche:\n";
945 std::cerr <<
" Sensor is not defined.\n";
951 if (!m_withHoles && !m_withElectrons) {
952 std::cerr << m_className <<
"::Avalanche:\n";
953 std::cerr <<
" Neither electron nor hole/ion component"
954 <<
" are activated.\n";
957 int nAval = m_aval.size();
959 for (
int iAval = nAval; iAval--;) {
960 if (m_withElectrons) {
962 for (
int iE = m_aval[iAval].ne; iE--;) {
964 if (!DriftLine(m_aval[iAval].x, m_aval[iAval].y, m_aval[iAval].z,
965 m_aval[iAval].t, -1,
true)) {
969 for (
unsigned int iDrift = 0; iDrift < m_nDrift - 2; ++iDrift) {
970 if (m_drift[iDrift].ne > 0 || m_drift[iDrift].nh > 0 ||
971 m_drift[iDrift].ni > 0) {
973 point.x = m_drift[iDrift + 1].x;
974 point.y = m_drift[iDrift + 1].y;
975 point.z = m_drift[iDrift + 1].z;
976 point.t = m_drift[iDrift + 1].t;
977 point.ne = m_drift[iDrift].ne;
978 point.nh = m_drift[iDrift].nh;
979 point.ni = m_drift[iDrift].ni;
980 m_aval.push_back(
point);
988 for (
int iI = 0; iI < m_aval[iAval].ni; ++iI) {
990 DriftLine(m_aval[iAval].x, m_aval[iAval].y, m_aval[iAval].z, m_aval[iAval].t,
996 for (
int iH = 0; iH < m_aval[iAval].nh; ++iH) {
998 if (!DriftLine(m_aval[iAval].x, m_aval[iAval].y, m_aval[iAval].z,
999 m_aval[iAval].t, +1,
true))
1002 for (
unsigned int iDrift = 0; iDrift < m_nDrift - 1; ++iDrift) {
1003 if (m_drift[iDrift].ne > 0 || m_drift[iDrift].nh > 0 ||
1004 m_drift[iDrift].ni > 0) {
1006 point.x = m_drift[iDrift + 1].x;
1007 point.y = m_drift[iDrift + 1].y;
1008 point.z = m_drift[iDrift + 1].z;
1009 point.t = m_drift[iDrift + 1].t;
1010 point.ne = m_drift[iDrift].ne;
1011 point.nh = m_drift[iDrift].nh;
1012 point.ni = m_drift[iDrift].ni;
1013 m_aval.push_back(
point);
1019 m_aval.erase(m_aval.begin() + iAval);
1021 nAval = m_aval.size();
1026bool AvalancheMC::ComputeAlphaEta(
const int type) {
1029 const double tg[6] = {-0.932469514203152028, -0.661209386466264514,
1030 -0.238619186083196909, 0.238619186083196909,
1031 0.661209386466264514, 0.932469514203152028};
1032 const double wg[6] = {0.171324492379170345, 0.360761573048138608,
1033 0.467913934572691047, 0.467913934572691047,
1034 0.360761573048138608, 0.171324492379170345};
1042 double ex = 0., ey = 0., ez = 0.;
1044 double bx = 0., by = 0., bz = 0.;
1046 double vx = 0., vy = 0., vz = 0.;
1048 double alpha = 0., eta = 0.;
1051 double vdx = 0., vdy = 0., vdz = 0.;
1054 for (
int i = m_nDrift - 1; i--;) {
1056 const double delx = m_drift[i + 1].x - m_drift[i].x;
1057 const double dely = m_drift[i + 1].y - m_drift[i].y;
1058 const double delz = m_drift[i + 1].z - m_drift[i].z;
1059 const double del =
sqrt(delx * delx + dely * dely + delz * delz);
1062 vdx = 0., vdy = 0., vdz = 0.;
1063 m_drift[i].alpha = 0.;
1064 m_drift[i].eta = 0.;
1065 for (
int j = 6; j--;) {
1066 x = m_drift[i].x + 0.5 * (1. + tg[j]) * delx;
1067 y = m_drift[i].y + 0.5 * (1. + tg[j]) * dely;
1068 z = m_drift[i].z + 0.5 * (1. + tg[j]) * delz;
1069 m_sensor->
ElectricField(x, y, z, ex, ey, ez, medium, status);
1073 const int lastButOne = m_nDrift - 2;
1074 if (i < lastButOne) {
1075 std::cerr << m_className <<
"::ComputeAlphaEta:\n";
1076 std::cerr <<
" Got status value " << status <<
" at segment "
1077 << j + 1 <<
"/6, drift point " << i + 1 <<
"/" << m_nDrift
1085 bx *= Tesla2Internal;
1086 by *= Tesla2Internal;
1087 bz *= Tesla2Internal;
1101 m_drift[i].alpha += wg[j] *
alpha;
1102 m_drift[i].eta += wg[j] * eta;
1106 if (m_useEquilibration) {
1107 const double vd =
sqrt(vdx * vdx + vdy * vdy + vdz * vdz);
1108 if (vd * del <= 0.) {
1111 const double dinv = delx * vdx + dely * vdy + delz * vdz;
1115 scale = (delx * vdx + dely * vdy + delz * vdz) / (vd * del);
1119 m_drift[i].alpha *= 0.5 * del * scale;
1120 m_drift[i].eta *= 0.5 * del * scale;
1124 if (!m_useEquilibration)
return true;
1126 double sub1 = 0., sub2 = 0.;
1127 bool try1 =
false, try2 =
false, done =
false;
1129 for (
unsigned int i = 0; i < m_nDrift - 1; ++i) {
1130 if (m_drift[i].alpha < 0.) {
1132 sub1 = sub2 = -m_drift[i].alpha / 2.;
1133 try1 = try2 =
false;
1135 for (
unsigned int j = 0; j < i - 1; ++j) {
1136 if (m_drift[i - j].alpha > sub1) {
1137 m_drift[i - j].alpha -= sub1;
1138 m_drift[i].alpha += sub1;
1142 }
else if (m_drift[i - j].alpha > 0.) {
1143 m_drift[i].alpha += m_drift[i - j].alpha;
1144 sub1 -= m_drift[i - j].alpha;
1145 m_drift[i - j].alpha = 0.;
1149 for (
unsigned int j = 0; j < m_nDrift - i - 1; ++j) {
1150 if (m_drift[i + j].alpha > sub2) {
1151 m_drift[i + j].alpha -= sub2;
1152 m_drift[i].alpha += sub2;
1156 }
else if (m_drift[i + j].alpha > 0.) {
1157 m_drift[i].alpha += m_drift[i + j].alpha;
1158 sub2 -= m_drift[i + j].alpha;
1159 m_drift[i + j].alpha = 0.;
1168 sub1 = -m_drift[i].alpha;
1169 for (
unsigned int j = 0; j < i - 1; ++j) {
1170 if (m_drift[i - j].alpha > sub1) {
1171 m_drift[i - j].alpha -= sub1;
1172 m_drift[i].alpha += sub1;
1176 }
else if (m_drift[i - j].alpha > 0.) {
1177 m_drift[i].alpha += m_drift[i - j].alpha;
1178 sub1 -= m_drift[i - j].alpha;
1179 m_drift[i - j].alpha = 0.;
1184 sub2 = -m_drift[i].alpha;
1185 for (
unsigned int j = 0; j < m_nDrift - i - 1; ++j) {
1186 if (m_drift[i + j].alpha > sub2) {
1187 m_drift[i + j].alpha -= sub2;
1188 m_drift[i].alpha += sub2;
1192 }
else if (m_drift[i + j].alpha > 0.) {
1193 m_drift[i].alpha += m_drift[i + j].alpha;
1194 sub2 -= m_drift[i + j].alpha;
1195 m_drift[i + j].alpha = 0.;
1202 std::cerr << m_className <<
"::ComputeAlphaEta:\n";
1203 std::cerr <<
" Unable to even out backwards alpha steps.\n";
1204 std::cerr <<
" Calculation is probably inaccurate.\n";
1212 for (
unsigned int i = 0; i < m_nDrift - 1; ++i) {
1213 if (m_drift[i].eta < 0.) {
1215 sub1 = -m_drift[i].eta / 2.;
1216 sub2 = -m_drift[i].eta / 2.;
1220 for (
unsigned int j = 0; j < i - 1; ++j) {
1221 if (m_drift[i - j].eta > sub1) {
1222 m_drift[i - j].eta -= sub1;
1223 m_drift[i].eta += sub1;
1227 }
else if (m_drift[i - j].eta > 0.) {
1228 m_drift[i].eta += m_drift[i - j].eta;
1229 sub1 -= m_drift[i - j].eta;
1230 m_drift[i - j].eta = 0.;
1234 for (
unsigned int j = 0; j < m_nDrift - i - 1; ++j) {
1235 if (m_drift[i + j].eta > sub2) {
1236 m_drift[i + j].eta -= sub2;
1237 m_drift[i].eta += sub2;
1241 }
else if (m_drift[i + j].eta > 0.) {
1242 m_drift[i].eta += m_drift[i + j].eta;
1243 sub2 -= m_drift[i + j].eta;
1244 m_drift[i + j].eta = 0.;
1252 sub1 = -m_drift[i].eta;
1253 for (
unsigned int j = 0; j < i - 1; ++j) {
1254 if (m_drift[i - j].eta > sub1) {
1255 m_drift[i - j].eta -= sub1;
1256 m_drift[i].eta += sub1;
1260 }
else if (m_drift[i - j].eta > 0.) {
1261 m_drift[i].eta += m_drift[i - j].eta;
1262 sub1 -= m_drift[i - j].eta;
1263 m_drift[i - j].eta = 0.;
1268 sub2 = -m_drift[i].eta;
1269 for (
unsigned int j = 0; j < m_nDrift - i - 1; ++j) {
1270 if (m_drift[i + j].eta > sub2) {
1271 m_drift[i + j].eta -= sub2;
1272 m_drift[i].eta += sub2;
1276 }
else if (m_drift[i + j].eta > 0.) {
1277 m_drift[i].eta += m_drift[i + j].eta;
1278 sub2 -= m_drift[i + j].eta;
1279 m_drift[i + j].eta = 0.;
1285 std::cerr << m_className <<
"::ComputeAlphaEta:\n";
1286 std::cerr <<
" Unable to even out backwards eta steps.\n";
1287 std::cerr <<
" Calculation is probably inaccurate.\n";
1298void AvalancheMC::ComputeSignal(
const double q) {
1300 if (m_nDrift < 2)
return;
1301 double dt, dx, dy, dz;
1302 for (
unsigned int i = 0; i < m_nDrift - 1; ++i) {
1303 dt = m_drift[i + 1].t - m_drift[i].t;
1304 dx = m_drift[i + 1].x - m_drift[i].x;
1305 dy = m_drift[i + 1].y - m_drift[i].y;
1306 dz = m_drift[i + 1].z - m_drift[i].z;
1307 m_sensor->
AddSignal(q, m_drift[i].t, dt, m_drift[i].x + 0.5 * dx,
1308 m_drift[i].y + 0.5 * dy, m_drift[i].z + 0.5 * dz,
1309 dx / dt, dy / dt, dz / dt);
1313void AvalancheMC::ComputeInducedCharge(
const double q) {
1315 if (m_nDrift < 2)
return;
1317 m_drift[m_nDrift - 1].x, m_drift[m_nDrift - 1].y,
1318 m_drift[m_nDrift - 1].z);
DoubleAc cos(const DoubleAc &f)
DoubleAc pow(const DoubleAc &f, double p)
DoubleAc sqrt(const DoubleAc &f)
DoubleAc sin(const DoubleAc &f)
DoubleAc fabs(const DoubleAc &f)
void EnablePlotting(ViewDrift *view)
void SetTimeSteps(const double d=0.02)
bool AvalancheElectronHole(const double x0, const double y0, const double z0, const double t0)
bool DriftIon(const double x0, const double y0, const double z0, const double t0)
void SetTimeWindow(const double t0, const double t1)
void GetIonEndpoint(const unsigned int i, double &x0, double &y0, double &z0, double &t0, double &x1, double &y1, double &z1, double &t1, int &status) const
bool DriftElectron(const double x0, const double y0, const double z0, const double t0)
void GetElectronEndpoint(const unsigned int i, double &x0, double &y0, double &z0, double &t0, double &x1, double &y1, double &z1, double &t1, int &status) const
void SetCollisionSteps(const int n=100)
void GetHoleEndpoint(const unsigned int i, double &x0, double &y0, double &z0, double &t0, double &x1, double &y1, double &z1, double &t1, int &status) const
void GetDriftLinePoint(const unsigned int i, double &x, double &y, double &z, double &t)
void SetSensor(Sensor *s)
bool AvalancheElectron(const double x0, const double y0, const double z0, const double t0, const bool hole=false)
void SetDistanceSteps(const double d=0.001)
bool AvalancheHole(const double x0, const double y0, const double z0, const double t0, const bool electron=false)
bool DriftHole(const double x0, const double y0, const double z0, const double t0)
virtual bool HoleTownsend(const double ex, const double ey, const double ez, const double bx, const double by, const double bz, double &alpha)
virtual bool HoleVelocity(const double ex, const double ey, const double ez, const double bx, const double by, const double bz, double &vx, double &vy, double &vz)
virtual bool ElectronVelocity(const double ex, const double ey, const double ez, const double bx, const double by, const double bz, double &vx, double &vy, double &vz)
virtual bool IonVelocity(const double ex, const double ey, const double ez, const double bx, const double by, const double bz, double &vx, double &vy, double &vz)
virtual bool ElectronDiffusion(const double ex, const double ey, const double ez, const double bx, const double by, const double bz, double &dl, double &dt)
virtual bool ElectronTownsend(const double ex, const double ey, const double ez, const double bx, const double by, const double bz, double &alpha)
virtual bool ElectronAttachment(const double ex, const double ey, const double ez, const double bx, const double by, const double bz, double &eta)
virtual bool HoleDiffusion(const double ex, const double ey, const double ez, const double bx, const double by, const double bz, double &dl, double &dt)
virtual bool HoleAttachment(const double ex, const double ey, const double ez, const double bx, const double by, const double bz, double &eta)
virtual bool IonDiffusion(const double ex, const double ey, const double ez, const double bx, const double by, const double bz, double &dl, double &dt)
void MagneticField(const double x, const double y, const double z, double &bx, double &by, double &bz, int &status)
void AddSignal(const double &q, const double &t, const double &dt, const double &x, const double &y, const double &z, const double &vx, const double &vy, const double &vz)
void ElectricField(const double x, const double y, const double z, double &ex, double &ey, double &ez, double &v, Medium *&medium, int &status)
bool IsInArea(const double x, const double y, const double z)
bool IsWireCrossed(const double x0, const double y0, const double z0, const double x1, const double y1, const double z1, double &xc, double &yc, double &zc)
void AddInducedCharge(const double q, const double x0, const double y0, const double z0, const double x1, const double y1, const double z1)
void NewElectronDriftLine(const unsigned int np, int &id, const double x0, const double y0, const double z0)
void SetDriftLinePoint(const unsigned int iL, const unsigned int iP, const double x, const double y, const double z)
void NewHoleDriftLine(const unsigned int np, int &id, const double x0, const double y0, const double z0)
void NewIonDriftLine(const unsigned int np, int &id, const double x0, const double y0, const double z0)