18 m_scaleElectronSignal(1.),
19 m_scaleHoleSignal(1.),
24 m_className =
"DriftLineRKF";
31 std::cerr << m_className <<
"::SetSensor:\n";
32 std::cerr <<
" Sensor pointer is null.\n";
43 std::cerr << m_className <<
"::SetIntegrationAccuracy:\n";
44 std::cerr <<
" Accuracy must be greater than zero.\n";
53 std::cerr << m_className <<
"::SetMaximumStepSize:\n";
54 std::cerr <<
" Step size must be greater than zero.\n";
61 std::cerr << m_className <<
"::EnablePlotting:\n";
62 std::cerr <<
" Viewer pointer is null.\n";
72 m_usePlotting =
false;
76 const double& z0,
const double& t0) {
78 m_particleType = ParticleTypeElectron;
79 if (!DriftLine(x0, y0, z0, t0))
return false;
86 const double& z0,
const double& t0) {
88 m_particleType = ParticleTypeHole;
89 if (!DriftLine(x0, y0, z0, t0))
return false;
95 const double& z0,
const double& t0) {
97 m_particleType = ParticleTypeIon;
98 if (!DriftLine(x0, y0, z0, t0))
return false;
103bool DriftLineRKF::DriftLine(
const double& x0,
const double& y0,
104 const double& z0,
const double& t0) {
108 std::cerr << m_className <<
"::DriftLine:\n";
109 std::cerr <<
" Sensor is not defined.\n";
113 double ex = 0., ey = 0., ez = 0.;
114 double bx = 0., by = 0., bz = 0.;
117 m_sensor->
ElectricField(x0, y0, z0, ex, ey, ez, m_medium, status);
120 std::cerr << m_className <<
"::DriftLine:\n";
121 std::cerr <<
" No valid field at initial position.\n";
128 if (m_particleType == ParticleTypeIon) {
130 }
else if (m_particleType == ParticleTypeElectron) {
132 }
else if (m_particleType == ParticleTypeHole) {
137 const double c10 = 214. / 891.;
138 const double c11 = 1. / 33.;
139 const double c12 = 650. / 891.;
140 const double c20 = 533. / 2106.;
141 const double c22 = 800. / 1053.;
142 const double c23 = -1. / 78.;
144 const double b10 = 1. / 4.;
145 const double b20 = -189. / 800.;
146 const double b21 = 729. / 800.;
147 const double b30 = 214. / 891.;
148 const double b31 = 1. / 33.;
149 const double b32 = 650. / 891.;
156 double v0x = 0., v0y = 0., v0z = 0.;
158 double v1[3] = {0., 0., 0.};
159 double v2[3] = {0., 0., 0.};
160 double v3[3] = {0., 0., 0.};
162 double rc[3] = {0., 0., 0.};
164 double xWire = 0., yWire = 0.;
167 double phi1[3] = {0., 0., 0.};
168 double phi2[3] = {0., 0., 0.};
171 if (!GetVelocity(ex, ey, ez, bx, by, bz, v0x, v0y, v0z)) {
172 std::cerr << m_className <<
"::DriftLine:\n";
173 std::cerr <<
" Failed to retrieve drift velocity.\n";
176 const double vTot =
sqrt(v0x * v0x + v0y * v0y + v0z * v0z);
178 std::cerr << m_className <<
"::DriftLine:\n";
179 std::cerr <<
" Zero velocity at initial position.\n";
183 double dt = m_accuracy / vTot;
187 unsigned int counter = 0;
189 bool keepGoing =
true;
191 while (counter <= m_maxSteps && keepGoing) {
193 m_path.push_back(tempStep);
194 m_path[counter].xi = x;
195 m_path[counter].yi = y;
196 m_path[counter].zi = z;
198 m_path[counter].ti = t0;
200 m_path[counter].ti = m_path[counter - 1].tf;
203 double x1 = x + dt * b10 * v0x;
204 double y1 = y + dt * b10 * v0y;
205 double z1 = z + dt * b10 * v0z;
207 m_sensor->
ElectricField(x1, y1, z1, ex, ey, ez, m_medium, status);
209 if (!EndDriftLine())
return false;
212 if (m_sensor->
IsWireCrossed(m_path.back().xi, m_path.back().yi,
213 m_path.back().zi, x1, y1, z1, rc[0], rc[1],
215 std::cerr << m_className <<
"::DriftLine:\n";
216 std::cerr <<
" Drift line crossed wire. Abandoning.\n";
217 m_path[counter].status = StatusCalculationAbandoned;
221 m_particleType != ParticleTypeIon) {
222 if (!DriftToWire(x1, y1, z1, xWire, yWire, rWire))
return false;
225 if (!GetVelocity(ex, ey, ez, bx, by, bz, v1[0], v1[1], v1[2])) {
226 std::cerr << m_className <<
"::DriftLine:\n";
227 std::cerr <<
" Failed to retrieve drift velocity.\n";
231 x1 = x + dt * (b20 * v0x + b21 * v1[0]);
232 y1 = y + dt * (b20 * v0y + b21 * v1[1]);
233 z1 = z + dt * (b20 * v0z + b21 * v1[2]);
235 m_sensor->
ElectricField(x1, y1, z1, ex, ey, ez, m_medium, status);
237 if (!EndDriftLine())
return false;
240 if (m_sensor->
IsWireCrossed(m_path.back().xi, m_path.back().yi,
241 m_path.back().zi, x1, y1, z1, rc[0], rc[1],
243 std::cerr << m_className <<
"::DriftLine:\n";
244 std::cerr <<
" Drift line crossed wire. Abandoning.\n";
245 m_path[counter].status = StatusCalculationAbandoned;
249 m_particleType != ParticleTypeIon) {
250 if (!DriftToWire(x1, y1, z1, xWire, yWire, rWire))
return false;
253 if (!GetVelocity(ex, ey, ez, bx, by, bz, v2[0], v2[1], v2[2])) {
254 std::cerr << m_className <<
"::DriftLine:\n";
255 std::cerr <<
" Failed to retrieve drift velocity.\n";
259 x1 = x + dt * (b30 * v0x + b31 * v1[0] + b32 * v2[0]);
260 y1 = y + dt * (b30 * v0y + b31 * v1[1] + b32 * v2[1]);
261 z1 = z + dt * (b30 * v0z + b31 * v1[2] + b32 * v2[2]);
263 m_sensor->
ElectricField(x1, y1, z1, ex, ey, ez, m_medium, status);
265 if (!EndDriftLine())
return false;
268 if (m_sensor->
IsWireCrossed(m_path.back().xi, m_path.back().yi,
269 m_path.back().zi, x1, y1, z1, rc[0], rc[1],
271 std::cerr << m_className <<
"::DriftLine:\n";
272 std::cerr <<
" Drift line crossed wire. Abandoning.\n";
273 m_path[counter].status = StatusCalculationAbandoned;
277 m_particleType != ParticleTypeIon) {
278 if (!DriftToWire(x1, y1, z1, xWire, yWire, rWire))
return false;
281 if (!GetVelocity(ex, ey, ez, bx, by, bz, v3[0], v3[1], v3[2])) {
282 std::cerr << m_className <<
"::DriftLine:\n";
283 std::cerr <<
" Failed to retrieve drift velocity.\n";
288 phi1[0] = c10 * v0x + c11 * v1[0] + c12 * v2[0];
289 phi1[1] = c10 * v0y + c11 * v1[1] + c12 * v2[1];
290 phi1[2] = c10 * v0z + c11 * v1[2] + c12 * v2[2];
292 phi2[0] = c20 * v0x + c22 * v2[0] + c23 * v3[0];
293 phi2[1] = c20 * v0y + c22 * v2[1] + c23 * v3[1];
294 phi2[2] = c20 * v0z + c22 * v2[2] + c23 * v3[2];
297 const double phi1Tot =
298 sqrt(phi1[0] * phi1[0] + phi1[1] * phi1[1] + phi1[2] * phi1[2]);
299 if (phi1Tot <= 0.0) {
300 std::cerr << m_className <<
"::DriftLine:\n"
301 <<
" Zero velocity. Abandoning drift.\n";
303 }
else if (dt * phi1Tot > m_maxStepSize) {
305 std::cout << m_className <<
"::DriftLine: Step too long, reduce.\n";
307 dt = 0.5 * m_maxStepSize / phi1Tot;
310 std::cout << m_className <<
"::DriftLine: Step good.\n";
319 m_path[counter].xf = x;
320 m_path[counter].yf = y;
321 m_path[counter].zf = z;
322 m_path[counter].tf = m_path[counter].ti + dt;
323 m_sensor->
ElectricField(x, y, z, ex, ey, ez, m_medium, status);
325 if (!EndDriftLine())
return false;
330 const double dphi0 =
fabs(phi1[0] - phi2[0]);
331 const double dphi1 =
fabs(phi1[1] - phi2[1]);
332 const double dphi2 =
fabs(phi1[2] - phi2[2]);
333 if (dphi0 > Small || dphi1 > Small || dphi2 > Small) {
335 std::cout << m_className <<
"::DriftLine: Adapting step size.\n";
337 dt =
sqrt(dt * m_accuracy / (dphi0 + dphi1 + dphi2));
340 std::cout << m_className <<
"::DriftLine: Increase step size.\n";
347 std::cerr << m_className <<
"::DriftLine:\n";
348 std::cerr <<
" Step size is zero (program bug).\n";
349 std::cerr <<
" The calculation is abandoned.\n";
353 if (dt > 10. * pdt) dt = 10. * pdt;
355 if (dt * (
fabs(phi1[0]) +
fabs(phi1[1]) +
fabs(phi1[2])) < m_accuracy) {
356 std::cerr << m_className <<
"::DriftLine:\n";
357 std::cerr <<
" Step size has become smaller than int. accuracy.\n";
358 std::cerr <<
" The calculation is abandoned.\n";
366 if (keepGoing && counter <= m_maxSteps) {
367 m_path[counter].status = StatusAlive;
368 }
else if (counter > m_maxSteps) {
369 m_path[counter].status = StatusTooManySteps;
371 m_path[counter].status = StatusCalculationAbandoned;
376 const unsigned int nSteps = m_path.size();
379 std::cout <<
" Step # time Xi Yi Zi Xf Yf Zf dt "
381 for (
unsigned int i = 0; i < nSteps; ++i) {
382 std::cout.precision(8);
383 std::cout << i <<
" " << m_path[i].ti <<
" " << m_path[i].xi
384 <<
" " << m_path[i].yi <<
" " << m_path[i].zi <<
" "
385 << m_path[i].xf <<
" " << m_path[i].yf <<
" "
386 << m_path[i].zf <<
" " <<
fabs(m_path[i].tf - m_path[i].ti)
387 <<
" " << m_path[i].status <<
"\n";
391 for (
unsigned int i = 0; i < nSteps; ++i) {
403 const unsigned int nSteps = m_path.size();
405 for (
unsigned int i = 0; i < nSteps; ++i) {
406 sum += IntegrateDiffusion(m_path[i].xi, m_path[i].yi, m_path[i].zi,
407 m_path[i].xf, m_path[i].yf, m_path[i].zf);
414 if (m_path.empty())
return 0.;
415 const unsigned int nSteps = m_path.size();
420 for (
unsigned int i = 0; i < nSteps; ++i) {
422 const double x = m_path[i].xi;
423 const double y = m_path[i].yi;
424 const double z = m_path[i].zi;
429 m_sensor->
ElectricField(x, y, z, ex, ey, ez, m_medium, status);
431 std::cerr << m_className <<
"::GetGain:\n";
432 std::cerr <<
" Initial drift line point.\n";
436 if (!GetTownsend(ex, ey, ez, bx, by, bz, alpha0)) {
437 std::cerr << m_className <<
"::GetGain:\n";
438 std::cerr <<
" Unable to retrieve Townsend coefficient.\n";
442 if (!GetTownsend(ex, ey, ez, bx, by, bz, alpha1)) {
443 std::cerr << m_className <<
"::GetGain:\n";
444 std::cerr <<
" Unable to retrieve Townsend coefficient.\n";
447 const double dx = x - m_path[i - 1].xi;
448 const double dy = y - m_path[i - 1].yi;
449 const double dz = z - m_path[i - 1].zi;
450 const double d =
sqrt(dx * dx + dy * dy + dz * dz);
451 crude += 0.5 * d * (alpha1 + alpha0);
456 const double tol = 1.e-4 * crude;
458 for (
unsigned int i = 0; i < nSteps; ++i) {
459 sum += IntegrateTownsend(m_path[i].xi, m_path[i].yi, m_path[i].zi,
460 m_path[i].xf, m_path[i].yf, m_path[i].zf, tol);
461 m_path[i].alphaint = sum;
468 if (m_path.empty())
return 0.;
469 return m_path.back().tf;
472bool DriftLineRKF::GetVelocity(
const double& ex,
const double& ey,
473 const double& ez,
const double& bx,
474 const double& by,
const double& bz,
double& vx,
475 double& vy,
double& vz)
const {
477 if (m_particleType == ParticleTypeElectron) {
481 }
else if (m_particleType == ParticleTypeIon) {
482 if (m_medium->
IonVelocity(ex, ey, ez, bx, by, bz, vx, vy, vz)) {
485 }
else if (m_particleType == ParticleTypeHole) {
486 if (m_medium->
HoleVelocity(ex, ey, ez, bx, by, bz, vx, vy, vz)) {
493bool DriftLineRKF::GetDiffusion(
const double& ex,
const double& ey,
494 const double& ez,
const double& bx,
495 const double& by,
const double& bz,
double& dl,
498 if (m_particleType == ParticleTypeElectron) {
502 }
else if (m_particleType == ParticleTypeIon) {
503 if (m_medium->
IonDiffusion(ex, ey, ez, bx, by, bz, dl, dt)) {
506 }
else if (m_particleType == ParticleTypeHole) {
507 if (m_medium->
HoleDiffusion(ex, ey, ez, bx, by, bz, dl, dt)) {
514bool DriftLineRKF::GetTownsend(
const double& ex,
const double& ey,
515 const double& ez,
const double& bx,
516 const double& by,
const double& bz,
517 double& alpha)
const {
519 if (m_particleType == ParticleTypeElectron) {
523 }
else if (m_particleType == ParticleTypeHole) {
524 if (m_medium->
HoleTownsend(ex, ey, ez, bx, by, bz, alpha)) {
531bool DriftLineRKF::EndDriftLine() {
533 m_path.back().status = StatusCalculationAbandoned;
534 m_path.back().xf = m_path.back().xi;
535 m_path.back().yf = m_path.back().yi;
536 m_path.back().zf = m_path.back().zi;
537 double x0 = m_path.back().xi;
538 double y0 = m_path.back().yi;
539 double z0 = m_path.back().zi;
540 double bx = 0., by = 0., bz = 0.;
541 double ex = 0., ey = 0., ez = 0.;
544 m_sensor->
ElectricField(x0, y0, z0, ex, ey, ez, m_medium, status);
546 std::cerr << m_className <<
"::EndDriftLine:\n";
547 std::cerr <<
" No valid field at initial point. Program bug!\n";
550 double vx = 0., vy = 0., vz = 0.;
551 if (!GetVelocity(ex, ey, ez, bx, by, bz, vx, vy, vz)) {
552 std::cerr << m_className <<
"::EndDriftLine:\n";
553 std::cerr <<
" Failed to retrieve initial drift velocity.\n";
556 const double speed =
sqrt(vx * vx + vy * vy + vz * vz);
558 std::cerr << m_className <<
"::EndDriftLine:\n";
559 std::cerr <<
" Zero velocity at initial position.\n";
563 if (m_path.size() > 1) {
564 const double dx = x0 - m_path[m_path.size() - 2].xi;
565 const double dy = y0 - m_path[m_path.size() - 2].yi;
566 const double dz = z0 - m_path[m_path.size() - 2].zi;
567 const double scale =
sqrt(dx * dx + dy * dy + dz * dz) / speed;
573 vx *= m_accuracy / speed;
574 vy *= m_accuracy / speed;
575 vz *= m_accuracy / speed;
586 m_sensor->
ElectricField(x1, y1, z1, ex, ey, ez, m_medium, status);
587 if (status != 0) inside =
false;
589 double x = 0., y = 0., z = 0.;
590 const unsigned int nBisections = 100;
591 for (
unsigned int i = 0; i < nBisections; ++i) {
592 x = x0 + 0.5 * (x1 - x0);
593 y = y0 + 0.5 * (y1 - y0);
594 z = z0 + 0.5 * (z1 - z0);
595 m_sensor->
ElectricField(x, y, z, ex, ey, ez, m_medium, status);
607 m_path.back().xf = x;
608 m_path.back().yf = y;
609 m_path.back().zf = z;
610 const double dx = x - m_path.back().xi;
611 const double dy = y - m_path.back().yi;
612 const double dz = z - m_path.back().zi;
613 const double dt =
sqrt(dx * dx + dy * dy + dz * dz) / speed;
614 m_path.back().tf = m_path.back().ti + dt;
615 m_path.back().status = StatusLeftDriftMedium;
619bool DriftLineRKF::DriftToWire(
double x0,
double y0,
double z0,
620 const double& xw,
const double& yw,
624 std::cout << m_className <<
"::DriftToWire:\n";
625 std::cout <<
" Drifting particle at (" << x0 <<
", " << y0 <<
")\n";
626 std::cout <<
" to wire at (" << xw <<
", " << yw
627 <<
") with physical radius " << rw <<
" cm.\n";
629 const double t0 = m_path.front().ti;
630 m_path.back().xf = x0;
631 m_path.back().yf = y0;
632 m_path.back().zf = z0;
633 m_path.back().tf = m_path.back().ti;
634 m_path.back().status = StatusCalculationAbandoned;
637 double ex = 0., ey = 0., ez = 0.;
638 double bx = 0., by = 0., bz = 0.;
641 m_sensor->
ElectricField(x0, y0, z0, ex, ey, ez, m_medium, status);
643 std::cerr << m_className <<
"::DriftToWire:\n";
644 std::cerr <<
" Initial position not valid. Abandoning.\n";
651 if (!GetVelocity(ex, ey, ez, bx, by, bz, vx0, vy0, vz0)) {
652 std::cerr << m_className <<
"::DriftToWire:\n";
653 std::cerr <<
" Cannot retrieve drift velocity at initial position.\n";
658 double dx0 = xw - x0;
659 double dy0 = yw - y0;
660 double dt0 = (
sqrt(dx0 * dx0 + dy0 * dy0) - rw - BoundaryDistance) /
661 sqrt(vx0 * vx0 + vy0 * vy0);
662 const unsigned int nMaxSteps = 10;
663 for (
unsigned int i = 0; i < nMaxSteps; ++i) {
666 bool smallTimeStep =
false;
669 std::cout << m_className <<
"::DriftToWire:\n";
670 std::cout <<
" Estimated time step: " << dt0 <<
" ns. Stop.\n";
673 m_path.back().tf = m_path.back().ti + dt0;
674 m_path.back().status = StatusLeftDriftMedium;
677 smallTimeStep =
true;
680 double x1 = x0 + dt0 * vx0;
681 double y1 = y0 + dt0 * vy0;
682 double z1 = z0 + dt0 * vz0;
684 std::cout << m_className <<
"::DriftToWire:\n";
685 std::cout <<
" Step " << i <<
" from (" << x0 <<
", " << y0
686 <<
") to (" << x1 <<
", " << y1 <<
").\n";
689 const double xin0 = (x1 - x0) * (xw - x0) + (y1 - y0) * (yw - y0);
691 std::cerr << m_className <<
"::DriftToWire:\n";
692 std::cerr <<
" Particle moves away from the wire. Abandoning.\n";
697 double xc = 0., yc = 0., zc = 0.;
698 if (m_sensor->
IsWireCrossed(x0, y0, z0, x1, y1, z1, xc, yc, zc)) {
699 if (m_debug) std::cout << m_className <<
"::DriftToWire: Wire crossed.\n";
704 const double dx10 = x1 - x0;
705 const double dy10 = y1 - y0;
706 dt0 =
sqrt(dx10 * dx10 + dy10 * dy10) / (vx0 * vx0 + vy0 * vy0);
708 m_path.back().xf = x1;
709 m_path.back().yf = y1;
710 m_path.back().zf = z1;
711 m_path.back().tf = m_path.back().ti + dt0;
714 m_sensor->
ElectricField(x1, y1, z1, ex, ey, ez, m_medium, status);
716 std::cerr << m_className <<
"::DriftToWire:\n";
717 std::cerr <<
" End point is not in a valid drift medium.\n";
718 std::cerr <<
" Abandoning.\n";
719 m_path.back().status = StatusCalculationAbandoned;
723 double vx1 = 0., vy1 = 0., vz1 = 0.;
724 if (!GetVelocity(ex, ey, ez, bx, by, bz, vx1, vy1, vz1)) {
725 std::cerr << m_className <<
"::DriftToWire:\n";
726 std::cerr <<
" Cannot retrieve drift velocity at end point.\n";
727 m_path.back().status = StatusCalculationAbandoned;
732 const double xm = 0.5 * (x0 + x1);
733 const double ym = 0.5 * (y0 + y1);
734 const double zm = 0.5 * (z0 + z1);
737 m_sensor->
ElectricField(xm, ym, zm, ex, ey, ez, m_medium, status);
739 std::cerr << m_className <<
"::DriftToWire:\n";
740 std::cerr <<
" Mid point is not in a valid drift medium.\n";
741 std::cerr <<
" Abandoning.\n";
742 m_path.back().status = StatusCalculationAbandoned;
746 double vxm = 0., vym = 0., vzm = 0.;
747 if (!GetVelocity(ex, ey, ez, bx, by, bz, vxm, vym, vzm)) {
748 std::cerr << m_className <<
"::DriftToWire:\n";
749 std::cerr <<
" Cannot retrieve drift velocity at mid point.\n";
750 m_path.back().status = StatusCalculationAbandoned;
753 const double speed0 =
sqrt(vx0 * vx0 + vy0 * vy0);
754 const double speed1 =
sqrt(vx1 * vx1 + vy1 * vy1);
755 const double speedm =
sqrt(vxm * vxm + vym * vym);
757 if (speed0 < Small || speed1 < Small || speedm < Small) {
758 std::cerr << m_className <<
"::DriftToWire:\n";
759 std::cerr <<
" Zero velocity. Abandoning.\n";
763 const double dx = x0 - x1;
764 const double dy = y0 - y1;
765 const double dxy =
sqrt(dx * dx + dy * dy);
766 if (dxy *
fabs(1. / speed0 - 2. / speedm + 1. / speed1) / 3. >
767 1.e-4 * (1. +
fabs(m_path.back().ti - t0)) &&
771 std::cout << m_className <<
"::DriftToWire: Reducing step size.\n";
777 m_path.back().tf = m_path.back().ti +
778 dxy * (1. / speed0 + 4. / speedm + 1. / speed1) / 6.;
779 m_path.back().xf = x1;
780 m_path.back().yf = y1;
781 m_path.back().zf = z1;
784 if(smallTimeStep)
break;
789 newStep.ti = m_path.back().tf;
790 m_path.push_back(newStep);
800 dt0 = (
sqrt(dx0 * dx0 + dy0 * dy0) - rw - BoundaryDistance) /
801 sqrt(vx0 * vx0 + vy0 * vy0);
809 x = m_path.back().xi;
810 y = m_path.back().yi;
811 z = m_path.back().zi;
812 t = m_path.back().ti;
813 stat = m_path.back().status;
817 double& z,
double& t)
const {
819 if (i >= m_path.size()) {
820 std::cerr << m_className <<
"::GetDriftLinePoint:\n";
821 std::cerr <<
" Index is outside the range.\n";
826 x = 0.5*(m_path.at(i).xi+m_path.at(i).xf);
827 y = 0.5*(m_path.at(i).yi+m_path.at(i).yf);
828 z = 0.5*(m_path.at(i).zi+m_path.at(i).zf);
829 t = 0.5*(m_path.at(i).ti+m_path.at(i).tf);
832double DriftLineRKF::IntegrateDiffusion(
const double& x,
const double& y,
833 const double& z,
const double& xe,
834 const double& ye,
const double& ze) {
837 std::cout << m_className <<
"::IntegrateDiffusion:\n";
838 std::cout <<
" Integrating from ";
839 std::cout << x <<
", " << y <<
", " << z <<
" to " << xe <<
", " << ye
840 <<
", " << ze <<
"\n";
847 m_sensor->
ElectricField(x, y, z, ex, ey, ez, m_medium, status);
849 std::cerr << m_className <<
"::IntegrateDiffusion:\n";
850 std::cerr <<
" Initial position not valid.\n";
854 double vx0 = 0., vy0 = 0., vz0 = 0.;
855 if (!GetVelocity(ex, ey, ez, bx, by, bz, vx0, vy0, vz0)) {
856 std::cerr << m_className <<
"::IntegrateDiffusion:\n";
857 std::cerr <<
" Unable to retrieve drift velocity.\n";
860 double speed0 =
sqrt(vx0 * vx0 + vy0 * vy0 + vz0 * vz0);
861 if (speed0 < Small) {
862 std::cerr << m_className <<
"::IntegrateDiffusion:\n";
863 std::cerr <<
" Zero velocity at initial position.\n";
869 if (!GetDiffusion(ex, ey, ez, bx, by, bz, dL0, dT0)) {
870 std::cerr << m_className <<
"::IntegrateDiffusion:\n";
871 std::cerr <<
" Unable to retrieve diffusion coefficients.\n";
883 double integral = 0.;
884 bool keepGoing =
true;
886 const double dx = x1 - x0;
887 const double dy = y1 - y0;
888 const double dz = z1 - z0;
889 const double d =
sqrt(dx * dx + dy * dy + dz * dz);
893 std::cout << m_className <<
"::IntegrateDiffusion: Small step.\n";
895 const double s = dL0 / speed0;
896 integral += s * s * d;
898 const double dxe = xe - x1;
899 const double dye = ye - y1;
900 const double dze = ze - z1;
901 if (
sqrt(dxe * dxe + dye * dye + dze * dze) < 1.e-6)
break;
913 m_sensor->
ElectricField(x1, y1, z1, ex, ey, ez, m_medium, status);
915 std::cerr << m_className <<
"::IntegrateDiffusion:\n";
916 std::cerr <<
" Invalid end point.\n";
922 if (!GetVelocity(ex, ey, ez, bx, by, bz, vx1, vy1, vz1)) {
923 std::cerr << m_className <<
"::IntegrateDiffusion:\n";
924 std::cerr <<
" Unable to retrieve drift velocity.\n";
927 double speed1 =
sqrt(vx1 * vx1 + vy1 * vy1 + vz1 * vz1);
930 if (!GetDiffusion(ex, ey, ez, bx, by, bz, dL1, dT1)) {
931 std::cerr << m_className <<
"::IntegrateDiffusion:\n";
932 std::cerr <<
" Unable to retrieve diffusion.\n";
936 const double xm = 0.5 * (x0 + x1);
937 const double ym = 0.5 * (y0 + y1);
938 const double zm = 0.5 * (z0 + z1);
940 m_sensor->
ElectricField(xm, ym, zm, ex, ey, ez, m_medium, status);
942 std::cerr << m_className <<
"::IntegrateDiffusion:\n";
943 std::cerr <<
" Invalid mid point.\n";
949 if (!GetVelocity(ex, ey, ez, bx, by, bz, vxm, vym, vzm)) {
950 std::cerr << m_className <<
"::IntegrateDiffusion:\n";
951 std::cerr <<
" Unable to retrieve drift velocity.\n";
954 double speedm =
sqrt(vxm * vxm + vym * vym + vzm * vzm);
957 if (!GetDiffusion(ex, ey, ez, bx, by, bz, dLm, dTm)) {
958 std::cerr << m_className <<
"::IntegrateDiffusion:\n";
959 std::cerr <<
" Unable to retrieve diffusion.\n";
962 const double tolerance = 1.e-3;
963 const double s0 =
pow(dL0 / speed0, 2);
964 const double s1 =
pow(dL1 / speed1, 2);
965 const double sm =
pow(dLm / speedm, 2);
967 const double simpson = d * (s0 + 4. * sm + s1) / 6.;
969 const double trapez = d * (s0 + s1) / 2.;
971 if (
fabs(trapez - simpson) *
sqrt(2. * d / (s0 + s1)) / 6. < tolerance) {
996double DriftLineRKF::IntegrateTownsend(
const double& xi,
const double& yi,
998 const double& xe,
const double& ye,
1000 const double& tol) {
1003 double ex = 0., ey = 0., ez = 0.;
1004 double bx = 0., by = 0., bz = 0.;
1007 m_sensor->
ElectricField(xi, yi, zi, ex, ey, ez, m_medium, status);
1009 std::cerr << m_className <<
"::IntegrateTownsend:\n";
1010 std::cerr <<
" Initial position (" << xi <<
", " << yi <<
", "
1011 << zi <<
") not valid.\n";
1016 if (!GetTownsend(ex, ey, ez, bx, by, bz, alpha0)) {
1017 std::cerr << m_className <<
"::IntegrateTownsend:\n";
1018 std::cerr <<
" Cannot retrieve Townsend coefficient at initial point.\n";
1023 m_sensor->
ElectricField(xe, ye, ze, ex, ey, ez, m_medium, status);
1025 std::cerr << m_className <<
"::IntegrateTownsend:\n";
1026 std::cerr <<
" End position (" << xi <<
", " << yi <<
", "
1027 << zi <<
") not valid.\n";
1032 if (!GetTownsend(ex, ey, ez, bx, by, bz, alpha1)) {
1033 std::cerr << m_className <<
"::IntegrateTownsend:\n";
1034 std::cerr <<
" Cannot retrieve Townsend coefficient at end point.\n";
1044 double dx = x1 - x0;
1045 double dy = y1 - y0;
1046 double dz = z1 - z0;
1047 double d =
sqrt(dx * dx + dy * dy + dz * dz);
1049 const double eps = tol / d;
1050 unsigned int stepCounter = 0;
1051 double integral = 0.;
1052 bool keepGoing =
true;
1057 d =
sqrt(dx * dx + dy * dy + dz * dz);
1058 const double tol = 1.e-6;
1062 std::cout << m_className <<
"::IntegrateTownsend: Small step.\n";
1064 integral += alpha0 * d;
1066 const double dxe = xe - x1;
1067 const double dye = ye - y1;
1068 const double dze = ze - z1;
1069 const double tol2 = tol * tol;
1070 if (dxe * dxe + dye * dye + dze * dze < tol2)
break;
1083 m_sensor->
ElectricField(x1, y1, z1, ex, ey, ez, m_medium, status);
1085 std::cerr << m_className <<
"::IntegrateTownsend:\n";
1086 std::cerr <<
" Invalid end point.\n";
1090 if (!GetTownsend(ex, ey, ez, bx, by, bz, alpha1)) {
1091 std::cerr << m_className <<
"::IntegrateTownsend:\n";
1092 std::cerr <<
" Cannot retrieve Townsend coefficient at end point.\n";
1096 const double xm = 0.5 * (x0 + x1);
1097 const double ym = 0.5 * (y0 + y1);
1098 const double zm = 0.5 * (z0 + z1);
1100 m_sensor->
ElectricField(xm, ym, zm, ex, ey, ez, m_medium, status);
1102 std::cerr << m_className <<
"::IntegrateTownsend:\n";
1103 std::cerr <<
" Invalid mid point.\n";
1107 if (!GetTownsend(ex, ey, ez, bx, by, bz, alpham)) {
1108 std::cerr << m_className <<
"::IntegrateTownsend:\n";
1109 std::cerr <<
" Cannot retrieve Townsend coefficient at mid point.\n";
1113 if (
fabs(alpha0 - 2. * alpham + alpha1) / 3. < eps) {
1115 integral += d * (alpha0 + 4. * alpham + alpha1) / 6.;
1121 if (
fabs(x0 - xe) < BoundaryDistance &&
1122 fabs(y0 - ye) < BoundaryDistance &&
1123 fabs(z0 - ze) < BoundaryDistance) {
1141void DriftLineRKF::ComputeSignal()
const {
1143 const unsigned int nSteps = m_path.size();
1144 if (nSteps < 2)
return;
1145 for (
unsigned int i = 0; i < nSteps; ++i) {
1147 const double dt = m_path[i].tf - m_path[i].ti;
1148 const double dx = m_path[i].xf - m_path[i].xi;
1149 const double dy = m_path[i].yf - m_path[i].yi;
1150 const double dz = m_path[i].zf - m_path[i].zi;
1152 const double vx = dx / dt;
1153 const double vy = dy / dt;
1154 const double vz = dz / dt;
1156 const double xm = m_path[i].xi + 0.5 * dx;
1157 const double ym = m_path[i].yi + 0.5 * dy;
1158 const double zm = m_path[i].zi + 0.5 * dz;
1159 if (m_particleType == ParticleTypeElectron) {
1161 const double g =
exp(m_path[i].alphaint);
1162 m_sensor->
AddSignal(-1. * g * m_scaleElectronSignal, m_path[i].ti, dt, xm, ym, zm, vx, vy, vz);
1163 }
else if (m_particleType == ParticleTypeIon) {
1164 m_sensor->
AddSignal(1. * m_scaleIonSignal, m_path[i].ti, dt, xm, ym, zm, vx, vy, vz);
1165 }
else if (m_particleType == ParticleTypeHole) {
1166 m_sensor->
AddSignal(1. * m_scaleHoleSignal, m_path[i].ti, dt, xm, ym, zm, vx, vy, vz);
DoubleAc pow(const DoubleAc &f, double p)
DoubleAc sqrt(const DoubleAc &f)
DoubleAc exp(const DoubleAc &f)
DoubleAc fabs(const DoubleAc &f)
bool DriftElectron(const double &x0, const double &y0, const double &z0, const double &t0)
void SetIntegrationAccuracy(const double a)
void SetSensor(Sensor *s)
bool DriftHole(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 GetDriftLinePoint(const unsigned int i, double &x, double &y, double &z, double &t) const
void EnablePlotting(ViewDrift *view)
double GetDriftTime() const
void GetEndPoint(double &x, double &y, double &z, double &t, int &st) const
double GetArrivalTimeSpread()
void SetMaximumStepSize(const double ms)
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 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 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 IsInTrapRadius(double x0, double y0, double z0, double &xw, double &yw, double &rw)
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 NewElectronDriftLine(const unsigned int np, int &id, const double x0, const double y0, const double z0)
void AddDriftLinePoint(const unsigned int iL, 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)