17 m_maxStepsToWire(1000),
19 m_useStepSizeLimit(false),
24 m_scaleElectronSignal(1.),
25 m_scaleHoleSignal(1.),
30 const unsigned int nMaxPoints = m_maxSteps + m_maxStepsToWire + 10;
31 m_path.resize(nMaxPoints);
32 m_className =
"DriftLineRKF";
38 std::cerr << m_className <<
"::SetSensor:\n Null pointer.\n";
49 std::cerr << m_className <<
"::SetIntegrationAccuracy:\n"
50 <<
" Accuracy must be greater than zero.\n";
58 if (!m_useStepSizeLimit) {
59 std::cout << m_className <<
"::SetMaximumStepSize:\n"
60 <<
" Don't forget to call EnableStepSizeLimit.\n";
63 std::cerr << m_className <<
"::SetMaximumStepSize:\n"
64 <<
" Step size must be greater than zero.\n";
71 std::cerr << m_className <<
"::EnablePlotting:\n Null pointer.\n";
81 m_usePlotting =
false;
85 const double z0,
const double t0) {
87 m_particleType = ParticleTypeElectron;
88 if (!DriftLine(x0, y0, z0, t0))
return false;
90 ComputeSignal(-1., m_scaleElectronSignal);
95 const double z0,
const double t0) {
97 m_particleType = ParticleTypeHole;
98 if (!DriftLine(x0, y0, z0, t0))
return false;
99 ComputeSignal(1., m_scaleHoleSignal);
104 const double z0,
const double t0) {
106 m_particleType = ParticleTypeIon;
107 if (!DriftLine(x0, y0, z0, t0))
return false;
108 ComputeSignal(1., m_scaleIonSignal);
112bool DriftLineRKF::DriftLine(
const double x0,
const double y0,
113 const double z0,
const double t0) {
116 const unsigned int nMaxPoints = m_maxSteps + m_maxStepsToWire + 10;
117 if (nMaxPoints > m_path.size()) m_path.resize(nMaxPoints);
122 m_status = StatusAlive;
126 std::cerr << m_className <<
"::DriftLine:\n Sensor is not defined.\n";
127 m_status = StatusCalculationAbandoned;
132 double xmin = 0., xmax = 0.;
133 double ymin = 0., ymax = 0.;
134 double zmin = 0., zmax = 0.;
135 bool bbox = m_sensor->
GetArea(xmin, ymin, zmin, xmax, ymax, zmax);
138 double ex = 0., ey = 0., ez = 0.;
139 double bx = 0., by = 0., bz = 0.;
142 m_sensor->
ElectricField(x0, y0, z0, ex, ey, ez, m_medium, status);
145 std::cerr << m_className <<
"::DriftLine:\n"
146 <<
" No valid field at initial position.\n";
147 m_status = StatusLeftDriftMedium;
154 if (m_particleType == ParticleTypeIon) {
156 }
else if (m_particleType == ParticleTypeElectron) {
158 }
else if (m_particleType == ParticleTypeHole) {
164 const double c10 = 214. / 891.;
165 const double c11 = 1. / 33.;
166 const double c12 = 650. / 891.;
167 const double c20 = 533. / 2106.;
168 const double c22 = 800. / 1053.;
169 const double c23 = -1. / 78.;
171 const double b10 = 1. / 4.;
172 const double b20 = -189. / 800.;
173 const double b21 = 729. / 800.;
174 const double b30 = 214. / 891.;
175 const double b31 = 1. / 33.;
176 const double b32 = 650. / 891.;
179 const double charge = m_particleType == ParticleTypeElectron ? -1 : 1;
185 double v0[3] = {0., 0., 0.};
186 if (!GetVelocity(ex, ey, ez, bx, by, bz, v0[0], v0[1], v0[2])) {
187 std::cerr << m_className <<
"::DriftLine:\n"
188 <<
" Failed to retrieve drift velocity.\n";
191 const double vTot =
sqrt(v0[0] * v0[0] + v0[1] * v0[1] + v0[2] * v0[2]);
193 std::cerr << m_className <<
"::DriftLine:\n"
194 <<
" Zero velocity at initial position.\n";
199 double dt = m_accuracy / vTot;
209 while (m_nPoints <= m_maxSteps) {
211 const double x1 = x + dt * b10 * v0[0];
212 const double y1 = y + dt * b10 * v0[1];
213 const double z1 = z + dt * b10 * v0[2];
214 double v1[3] = {0., 0., 0.};
215 if (!GetVelocity(x1, y1, z1, v1[0], v1[1], v1[2], status)) {
216 m_status = StatusCalculationAbandoned;
222 std::cout << m_className <<
"::DriftLine: Inside wire, halve.\n";
227 if (!EndDriftLine()) m_status = StatusCalculationAbandoned;
231 const double x2 = x + dt * (b20 * v0[0] + b21 * v1[0]);
232 const double y2 = y + dt * (b20 * v0[1] + b21 * v1[1]);
233 const double z2 = z + dt * (b20 * v0[2] + b21 * v1[2]);
234 double v2[3] = {0., 0., 0.};
235 if (!GetVelocity(x2, y2, z2, v2[0], v2[1], v2[2], status)) {
236 m_status = StatusCalculationAbandoned;
242 std::cout << m_className <<
"::DriftLine: Inside wire, halve.\n";
247 if (!EndDriftLine()) m_status = StatusCalculationAbandoned;
251 double v3[3] = {0., 0., 0.};
252 const double x3 = x + dt * (b30 * v0[0] + b31 * v1[0] + b32 * v2[0]);
253 const double y3 = y + dt * (b30 * v0[1] + b31 * v1[1] + b32 * v2[1]);
254 const double z3 = z + dt * (b30 * v0[2] + b31 * v1[2] + b32 * v2[2]);
255 if (!GetVelocity(x3, y3, z3, v3[0], v3[1], v3[2], status)) {
256 m_status = StatusCalculationAbandoned;
262 std::cout << m_className <<
"::DriftLine: Inside wire, halve.\n";
267 if (!EndDriftLine()) m_status = StatusCalculationAbandoned;
272 double xw = 0., yw = 0., zw = 0.;
273 if (m_sensor->
IsWireCrossed(x, y, z, x1, y1, z1, xw, yw, zw) ||
277 std::cout << m_className <<
"::DriftLine:\n"
278 <<
" Drift line crossed wire. Reduce step size.\n";
281 std::cerr << m_className <<
"::DriftLine: Step size too small. Stop.\n";
282 m_status = StatusCalculationAbandoned;
291 m_particleType != ParticleTypeIon) {
292 if (!DriftToWire(xw, yw, rw)) m_status = StatusCalculationAbandoned;
296 m_particleType != ParticleTypeIon) {
297 if (!DriftToWire(xw, yw, rw)) m_status = StatusCalculationAbandoned;
301 m_particleType != ParticleTypeIon) {
302 if (!DriftToWire(xw, yw, rw)) m_status = StatusCalculationAbandoned;
306 double phi1[3] = {0., 0., 0.};
307 double phi2[3] = {0., 0., 0.};
308 for (
unsigned int i = 0; i < 3; ++i) {
309 phi1[i] = c10 * v0[i] + c11 * v1[i] + c12 * v2[i];
310 phi2[i] = c20 * v0[i] + c22 * v2[i] + c23 * v3[i];
313 const double phi1Tot =
314 sqrt(phi1[0] * phi1[0] + phi1[1] * phi1[1] + phi1[2] * phi1[2]);
315 if (phi1Tot < Small) {
316 std::cerr << m_className <<
"::DriftLine:\n"
317 <<
" Step has zero length. Abandoning drift.\n";
318 m_status = StatusCalculationAbandoned;
320 }
else if (m_useStepSizeLimit && dt * phi1Tot > m_maxStepSize) {
322 std::cout << m_className <<
"::DriftLine: Step too long, reduce.\n";
324 dt = 0.5 * m_maxStepSize / phi1Tot;
328 if (dt *
fabs(phi1[0]) > 0.1 *
fabs(xmax - xmin) ||
329 dt *
fabs(phi1[1]) > 0.1 *
fabs(ymax - ymin)) {
332 std::cout << m_className <<
"::DriftLine: Step too long, halve.\n";
336 }
else if (m_rejectKinks && m_nPoints > 1) {
337 if (phi1[0] * (m_path[m_nPoints - 1].x - m_path[m_nPoints - 2].x) +
338 phi1[1] * (m_path[m_nPoints - 1].y - m_path[m_nPoints - 2].y) +
339 phi1[2] * (m_path[m_nPoints - 1].z - m_path[m_nPoints - 2].z) < 0.) {
340 std::cerr << m_className <<
"::DriftLine: Bending angle > 90 degree.\n";
341 m_status = StatusSharpKink;
345 if (m_debug) std::cout << m_className <<
"::DriftLine: Step size ok.\n";
352 m_path[m_nPoints - 1].x = x;
353 m_path[m_nPoints - 1].y = y;
354 m_path[m_nPoints - 1].z = z;
355 m_path[m_nPoints - 1].t = m_path[m_nPoints - 2].t + dt;
357 m_sensor->
ElectricField(x, y, z, ex, ey, ez, m_medium, status);
363 std::cout << m_className <<
"::DriftLine:\n"
364 <<
" New point is outside. Terminate.\n";
366 if (!EndDriftLine()) m_status = StatusCalculationAbandoned;
371 const double dphi0 =
fabs(phi1[0] - phi2[0]);
372 const double dphi1 =
fabs(phi1[1] - phi2[1]);
373 const double dphi2 =
fabs(phi1[2] - phi2[2]);
374 if (dphi0 > Small || dphi1 > Small || dphi2 > Small) {
375 dt =
sqrt(dt * m_accuracy / (dphi0 + dphi1 + dphi2));
377 std::cout << m_className <<
"::DriftLine: Adapting step size to "
378 << dt <<
" ns (from " << pdt <<
").\n";
383 std::cout << m_className <<
"::DriftLine: Double step size.\n";
389 std::cerr << m_className <<
"::DriftLine:\n"
390 <<
" Step size is zero (program bug).\n"
391 <<
" The calculation is abandoned.\n";
392 m_status = StatusCalculationAbandoned;
396 if (initCycle > 0 && dt < pdt / 5.) {
398 std::cout << m_className <<
"::DriftLine: Reinitialise step size.\n";
409 if (dt > 10. * pdt) {
412 std::cout << m_className <<
"::DriftLine: Limit step size to " << dt <<
"\n";
416 if (dt * (
fabs(phi1[0]) +
fabs(phi1[1]) +
fabs(phi1[2])) < m_accuracy) {
417 std::cerr << m_className <<
"::DriftLine:\n"
418 <<
" Step size has become smaller than int. accuracy.\n"
419 <<
" The calculation is abandoned.\n";
420 m_status = StatusCalculationAbandoned;
428 if (m_nPoints > m_maxSteps) {
429 m_status = StatusTooManySteps;
435 std::cout << m_className <<
"::DriftLine:\n";
436 std::cout <<
" Drift line status: " << m_status <<
"\n";
437 std::cout <<
" Step time time step "
439 for (
unsigned int i = 0; i < m_nPoints; ++i) {
440 std::cout << std::setw(8) << i <<
" "
441 << std::fixed << std::setprecision(7)
442 << std::setw(15) << m_path[i].t <<
" ";
444 std::cout << std::setw(15) << m_path[i].t - m_path[i - 1].t <<
" ";
446 std::cout << std::string(17,
' ');
448 std::cout << std::setw(15) << m_path[i].x <<
" "
449 << std::setw(15) << m_path[i].y <<
" "
450 << std::setw(15) << m_path[i].z <<
"\n";
454 for (
unsigned int i = 0; i < m_nPoints; ++i) {
458 if (status == StatusCalculationAbandoned)
return false;
464 if (m_nPoints < 2)
return 0.;
466 for (
unsigned int i = 0; i < m_nPoints - 1; ++i) {
467 const unsigned int j = i + 1;
468 sum += IntegrateDiffusion(m_path[i].x, m_path[i].y, m_path[i].z,
469 m_path[j].x, m_path[j].y, m_path[j].z);
476 if (m_nPoints < 2)
return 0.;
477 if (m_status == StatusCalculationAbandoned)
return 0.;
480 double alphaPrev = 0.;
481 for (
unsigned int i = 0; i < m_nPoints; ++i) {
483 const double x = m_path[i].x;
484 const double y = m_path[i].y;
485 const double z = m_path[i].z;
490 m_sensor->
ElectricField(x, y, z, ex, ey, ez, m_medium, status);
492 std::cerr << m_className <<
"::GetGain:\n"
493 <<
" Invalid drift line point " << i <<
".\n";
497 if (!GetTownsend(ex, ey, ez, bx, by, bz, alpha)) {
498 std::cerr << m_className <<
"::GetGain:\n"
499 <<
" Unable to retrieve Townsend coefficient.\n";
506 const double dx = x - m_path[i - 1].x;
507 const double dy = y - m_path[i - 1].y;
508 const double dz = z - m_path[i - 1].z;
509 const double d = sqrt(dx * dx + dy * dy + dz * dz);
510 crude += 0.5 * d * (alpha + alphaPrev);
514 if (crude < Small)
return 1.;
517 const double tol = 1.e-4 * crude;
519 m_path[0].alphaint = 0.;
520 for (
unsigned int i = 0; i < m_nPoints - 1; ++i) {
521 const unsigned int j = i + 1;
522 sum += IntegrateTownsend(m_path[i].x, m_path[i].y, m_path[i].z,
523 m_path[j].x, m_path[j].y, m_path[j].z, tol);
524 m_path[j].alphaint = sum;
529bool DriftLineRKF::GetVelocity(
const double x,
const double y,
const double z,
530 double& vx,
double& vy,
double& vz,
533 double ex = 0., ey = 0., ez = 0.;
534 double bx = 0., by = 0., bz = 0.;
536 m_sensor->
ElectricField(x, y, z, ex, ey, ez, m_medium, status);
538 if (status != 0)
return true;
539 if (m_particleType == ParticleTypeElectron) {
541 }
else if (m_particleType == ParticleTypeIon) {
542 return m_medium->
IonVelocity(ex, ey, ez, bx, by, bz, vx, vy, vz);
543 }
else if (m_particleType == ParticleTypeHole) {
544 return m_medium->
HoleVelocity(ex, ey, ez, bx, by, bz, vx, vy, vz);
546 std::cerr << m_className <<
"::GetVelocity:\n"
547 <<
" Cannot retrieve drift velocity at ("
548 << x <<
", " << y <<
", " << z <<
").\n";
553bool DriftLineRKF::GetVelocity(
const double ex,
const double ey,
554 const double ez,
const double bx,
555 const double by,
const double bz,
double& vx,
556 double& vy,
double& vz)
const {
558 if (m_particleType == ParticleTypeElectron) {
560 }
else if (m_particleType == ParticleTypeIon) {
561 return m_medium->
IonVelocity(ex, ey, ez, bx, by, bz, vx, vy, vz);
562 }
else if (m_particleType == ParticleTypeHole) {
563 return m_medium->
HoleVelocity(ex, ey, ez, bx, by, bz, vx, vy, vz);
568bool DriftLineRKF::GetDiffusion(
const double ex,
const double ey,
569 const double ez,
const double bx,
570 const double by,
const double bz,
double& dl,
573 if (m_particleType == ParticleTypeElectron) {
575 }
else if (m_particleType == ParticleTypeIon) {
576 return m_medium->
IonDiffusion(ex, ey, ez, bx, by, bz, dl, dt);
577 }
else if (m_particleType == ParticleTypeHole) {
578 return m_medium->
HoleDiffusion(ex, ey, ez, bx, by, bz, dl, dt);
583bool DriftLineRKF::GetTownsend(
const double ex,
const double ey,
584 const double ez,
const double bx,
585 const double by,
const double bz,
586 double& alpha)
const {
588 if (m_particleType == ParticleTypeElectron) {
590 }
else if (m_particleType == ParticleTypeHole) {
591 return m_medium->
HoleTownsend(ex, ey, ez, bx, by, bz, alpha);
596bool DriftLineRKF::EndDriftLine() {
599 double x0 = m_path[m_nPoints - 1].x;
600 double y0 = m_path[m_nPoints - 1].y;
601 double z0 = m_path[m_nPoints - 1].z;
603 double vx = 0., vy = 0., vz = 0.;
605 if (!GetVelocity(x0, y0, z0, vx, vy, vz, status)) {
606 std::cerr << m_className <<
"::EndDriftLine:\n";
607 std::cerr <<
" Failed to retrieve initial drift velocity.\n";
609 }
else if (status != 0) {
610 std::cerr << m_className <<
"::EndDriftLine:\n";
611 std::cerr <<
" No valid field at initial point. Program bug!\n";
614 const double speed =
sqrt(vx * vx + vy * vy + vz * vz);
616 std::cerr << m_className <<
"::EndDriftLine:\n";
617 std::cerr <<
" Zero velocity at initial position.\n";
622 const double dx = x0 - m_path[m_nPoints - 2].x;
623 const double dy = y0 - m_path[m_nPoints - 2].y;
624 const double dz = z0 - m_path[m_nPoints - 2].z;
625 const double scale =
sqrt(dx * dx + dy * dy + dz * dz) / speed;
631 vx *= m_accuracy / speed;
632 vy *= m_accuracy / speed;
633 vz *= m_accuracy / speed;
644 double ex = 0., ey = 0., ez = 0.;
645 m_sensor->
ElectricField(x1, y1, z1, ex, ey, ez, m_medium, status);
646 if (status != 0) inside =
false;
648 const unsigned int nBisections = 100;
649 const double tol = BoundaryDistance * BoundaryDistance;
650 for (
unsigned int i = 0; i < nBisections; ++i) {
651 const double x = x0 + 0.5 * (x1 - x0);
652 const double y = y0 + 0.5 * (y1 - y0);
653 const double z = z0 + 0.5 * (z1 - z0);
654 double ex = 0., ey = 0., ez = 0.;
655 m_sensor->
ElectricField(x, y, z, ex, ey, ez, m_medium, status);
665 const double dx = x1 - x0;
666 const double dy = y1 - y0;
667 const double dz = z1 - z0;
668 const double d = dx * dx + dy * dy + dz * dz;
672 const double dx = x0 - m_path[m_nPoints - 1].x;
673 const double dy = y0 - m_path[m_nPoints - 1].y;
674 const double dz = z0 - m_path[m_nPoints - 1].z;
675 const double dt =
sqrt(dx * dx + dy * dy + dz * dz) / speed;
678 m_path[m_nPoints - 1].x = x0;
679 m_path[m_nPoints - 1].y = y0;
680 m_path[m_nPoints - 1].z = z0;
681 m_path[m_nPoints - 1].t = m_path[m_nPoints - 2].t + dt;
682 m_status = StatusLeftDriftMedium;
686bool DriftLineRKF::DriftToWire(
const double xw,
const double yw,
690 double x0 = m_path[m_nPoints - 1].x;
691 double y0 = m_path[m_nPoints - 1].y;
692 double z0 = m_path[m_nPoints - 1].z;
693 double t0 = m_path[m_nPoints - 1].t - m_path[0].t;
695 std::cout << m_className <<
"::DriftToWire:\n";
696 std::cout <<
" Drifting particle at (" << x0 <<
", " << y0 <<
")\n";
697 std::cout <<
" to wire at (" << xw <<
", " << yw
698 <<
") with physical radius " << rw <<
" cm.\n";
702 double vx0 = 0., vy0 = 0., vz0 = 0.;
704 if (!GetVelocity(x0, y0, z0, vx0, vy0, vz0, status)) {
705 std::cerr << m_className <<
"::DriftToWire:\n";
706 std::cerr <<
" Failed to retrieve initial drift velocity.\n";
708 }
else if (status != 0) {
709 std::cerr << m_className <<
"::DriftToWire:\n";
710 std::cerr <<
" No valid field at initial point. Program bug!\n";
716 double dx0 = xw - x0;
717 double dy0 = yw - y0;
718 double dt = (
sqrt(dx0 * dx0 + dy0 * dy0) - rw) /
719 sqrt(vx0 * vx0 + vy0 * vy0);
721 if (dt < 1.e-6 * t0) {
722 m_status = StatusLeftDriftMedium;
726 const double c1 = 1. / 3.;
727 const double r2 = rw * rw;
728 const unsigned int nMaxSteps = m_maxStepsToWire;
729 for (
unsigned int i = 0; i < nMaxSteps; ++i) {
731 bool smallTimeStep =
false;
743 double x1 = x0 + dt * vx0;
744 double y1 = y0 + dt * vy0;
745 double z1 = z0 + dt * vz0;
747 std::cout << m_className <<
"::DriftToWire:\n";
748 std::cout <<
" Step " << i <<
" from (" << x0 <<
", " << y0
749 <<
") to (" << x1 <<
", " << y1 <<
").\n";
752 const double dxw0 = xw - x0;
753 const double dyw0 = yw - y0;
754 const double xinp0 = (x1 - x0) * dxw0 + (y1 - y0) * dyw0;
756 std::cerr << m_className <<
"::DriftToWire:\n";
757 std::cerr <<
" Particle moves away from the wire. Abandoning.\n";
762 const double dxw1 = xw - x1;
763 const double dyw1 = yw - y1;
764 const double xinp1 = (x0 - x1) * dxw1 + (y0 - y1) * dyw1;
766 const double d2 = dxw1 * dxw1 + dyw1 * dyw1;
769 if (m_debug) std::cout << m_className <<
"::DriftToWire: Inside.\n";
772 if (m_debug) std::cout << m_className <<
"::DriftToWire: Wire crossed.\n";
776 const double dw0 =
sqrt(dxw0 * dxw0 + dyw0 * dyw0);
777 x1 = xw - (rw + BoundaryDistance) * dxw0 / dw0;
778 y1 = yw - (rw + BoundaryDistance) * dyw0 / dw0;
779 const double dx10 = x1 - x0;
780 const double dy10 = y1 - y0;
781 dt =
sqrt((dx10 * dx10 + dy10 * dy10) / (vx0 * vx0 + vy0 * vy0));
785 double vx1 = 0., vy1 = 0., vz1 = 0.;
786 if (!GetVelocity(x1, y1, z1, vx1, vy1, vz1, status)) {
787 std::cerr << m_className <<
"::DriftToWire:\n";
788 std::cerr <<
" Cannot retrieve drift velocity at end point. Quit.\n";
790 }
else if (status != 0) {
791 std::cerr << m_className <<
"::DriftToWire:\n";
792 std::cerr <<
" End point is not in a valid drift medium. Quit.\n";
796 const double xm = 0.5 * (x0 + x1);
797 const double ym = 0.5 * (y0 + y1);
798 const double zm = 0.5 * (z0 + z1);
800 double vxm = 0., vym = 0., vzm = 0.;
801 if (!GetVelocity(xm, ym, zm, vxm, vym, vzm, status)) {
802 std::cerr << m_className <<
"::DriftToWire:\n";
803 std::cerr <<
" Cannot retrieve drift velocity at mid point. Quit.\n";
805 }
else if (status != 0) {
806 std::cerr << m_className <<
"::DriftToWire:\n";
807 std::cerr <<
" Mid point is not in a valid drift medium. Quit.\n";
810 const double v0 =
sqrt(vx0 * vx0 + vy0 * vy0);
811 const double v1 =
sqrt(vx1 * vx1 + vy1 * vy1);
812 const double vm =
sqrt(vxm * vxm + vym * vym);
814 if (v0 < Small || v1 < Small || vm < Small) {
815 std::cerr << m_className <<
"::DriftToWire:\n";
816 std::cerr <<
" Zero velocity. Abandoning.\n";
820 const double dx01 = x0 - x1;
821 const double dy01 = y0 - y1;
822 const double d10 =
sqrt(dx01 * dx01 + dy01 * dy01);
823 if (d10 * c1 *
fabs(1. / v0 - 2. / vm + 1. / v1) > 1.e-4 * (1. +
fabs(t0)) &&
827 std::cout << m_className <<
"::DriftToWire: Reducing step size.\n";
832 const double t1 = t0 + d10 * (1. / v0 + 4. / vm + 1. / v1) / 6.;
835 m_path[m_nPoints - 1].x = x1;
836 m_path[m_nPoints - 1].y = y1;
837 m_path[m_nPoints - 1].z = z1;
838 m_path[m_nPoints - 1].t = m_path[0].t + t1;
841 if(smallTimeStep)
break;
851 m_status = StatusLeftDriftMedium;
858 if (m_nPoints == 0) {
863 x = m_path[m_nPoints - 1].x;
864 y = m_path[m_nPoints - 1].y;
865 z = m_path[m_nPoints - 1].z;
866 t = m_path[m_nPoints - 1].t;
871 double& z,
double& t)
const {
873 if (i >= m_nPoints) {
874 std::cerr << m_className <<
"::GetDriftLinePoint:\n";
875 std::cerr <<
" Index is outside the range.\n";
886double DriftLineRKF::IntegrateDiffusion(
const double x,
const double y,
887 const double z,
const double xe,
888 const double ye,
const double ze) {
891 std::cout << m_className <<
"::IntegrateDiffusion:\n Integrating from "
892 << x <<
", " << y <<
", " << z <<
" to " << xe <<
", " << ye
893 <<
", " << ze <<
"\n";
900 m_sensor->
ElectricField(x, y, z, ex, ey, ez, m_medium, status);
902 std::cerr << m_className <<
"::IntegrateDiffusion:\n"
903 <<
" Initial position not valid.\n";
907 double vx0 = 0., vy0 = 0., vz0 = 0.;
908 if (!GetVelocity(ex, ey, ez, bx, by, bz, vx0, vy0, vz0)) {
909 std::cerr << m_className <<
"::IntegrateDiffusion:\n"
910 <<
" Cannot retrieve drift velocity.\n";
913 double speed0 =
sqrt(vx0 * vx0 + vy0 * vy0 + vz0 * vz0);
914 if (speed0 < Small) {
915 std::cerr << m_className <<
"::IntegrateDiffusion:\n"
916 <<
" Zero velocity at initial position.\n";
922 if (!GetDiffusion(ex, ey, ez, bx, by, bz, dL0, dT0)) {
923 std::cerr << m_className <<
"::IntegrateDiffusion:\n"
924 <<
" Cannot retrieve diffusion coefficients.\n";
936 double integral = 0.;
937 bool keepGoing =
true;
939 const double dx = x1 - x0;
940 const double dy = y1 - y0;
941 const double dz = z1 - z0;
942 const double d =
sqrt(dx * dx + dy * dy + dz * dz);
946 std::cout << m_className <<
"::IntegrateDiffusion: Small step.\n";
948 const double s = dL0 / speed0;
949 integral += s * s * d;
951 const double dxe = xe - x1;
952 const double dye = ye - y1;
953 const double dze = ze - z1;
954 if (
sqrt(dxe * dxe + dye * dye + dze * dze) < 1.e-6)
break;
966 m_sensor->
ElectricField(x1, y1, z1, ex, ey, ez, m_medium, status);
968 std::cerr << m_className <<
"::IntegrateDiffusion: Invalid end point.\n";
974 if (!GetVelocity(ex, ey, ez, bx, by, bz, vx1, vy1, vz1)) {
975 std::cerr << m_className <<
"::IntegrateDiffusion:\n"
976 <<
" Cannot retrieve drift velocity.\n";
979 double speed1 =
sqrt(vx1 * vx1 + vy1 * vy1 + vz1 * vz1);
982 if (!GetDiffusion(ex, ey, ez, bx, by, bz, dL1, dT1)) {
983 std::cerr << m_className <<
"::IntegrateDiffusion:\n"
984 <<
" Cannot retrieve diffusion.\n";
988 const double xm = 0.5 * (x0 + x1);
989 const double ym = 0.5 * (y0 + y1);
990 const double zm = 0.5 * (z0 + z1);
992 m_sensor->
ElectricField(xm, ym, zm, ex, ey, ez, m_medium, status);
994 std::cerr << m_className <<
"::IntegrateDiffusion: Invalid mid point.\n";
1000 if (!GetVelocity(ex, ey, ez, bx, by, bz, vxm, vym, vzm)) {
1001 std::cerr << m_className <<
"::IntegrateDiffusion:\n"
1002 <<
" Cannot retrieve drift velocity.\n";
1005 double speedm =
sqrt(vxm * vxm + vym * vym + vzm * vzm);
1008 if (!GetDiffusion(ex, ey, ez, bx, by, bz, dLm, dTm)) {
1009 std::cerr << m_className <<
"::IntegrateDiffusion:\n"
1010 <<
" Cannot retrieve diffusion.\n";
1013 const double tolerance = 1.e-3;
1014 const double s0 =
pow(dL0 / speed0, 2);
1015 const double s1 =
pow(dL1 / speed1, 2);
1016 const double sm =
pow(dLm / speedm, 2);
1018 const double simpson = d * (s0 + 4. * sm + s1) / 6.;
1020 const double trapez = 0.5 * d * (s0 + s1);
1022 if (
fabs(trapez - simpson) *
sqrt(2. * d / (s0 + s1)) / 6. < tolerance) {
1024 integral += simpson;
1047double DriftLineRKF::IntegrateTownsend(
const double xi,
const double yi,
1049 const double xe,
const double ye,
1054 double ex = 0., ey = 0., ez = 0.;
1055 double bx = 0., by = 0., bz = 0.;
1058 m_sensor->
ElectricField(xi, yi, zi, ex, ey, ez, m_medium, status);
1060 std::cerr << m_className <<
"::IntegrateTownsend:\n Initial position ("
1061 << xi <<
", " << yi <<
", " << zi <<
") not valid.\n";
1066 if (!GetTownsend(ex, ey, ez, bx, by, bz, alpha0)) {
1067 std::cerr << m_className <<
"::IntegrateTownsend:\n"
1068 <<
" Cannot retrieve Townsend coefficient at initial point.\n";
1073 m_sensor->
ElectricField(xe, ye, ze, ex, ey, ez, m_medium, status);
1075 std::cerr << m_className <<
"::IntegrateTownsend:\n End position ("
1076 << xi <<
", " << yi <<
", " << zi <<
") not valid.\n";
1081 if (!GetTownsend(ex, ey, ez, bx, by, bz, alpha1)) {
1082 std::cerr << m_className <<
"::IntegrateTownsend:\n"
1083 <<
" Cannot retrieve Townsend coefficient at end point.\n";
1093 double dx = x1 - x0;
1094 double dy = y1 - y0;
1095 double dz = z1 - z0;
1096 double d =
sqrt(dx * dx + dy * dy + dz * dz);
1098 const double eps = tol / d;
1099 unsigned int stepCounter = 0;
1100 double integral = 0.;
1101 bool keepGoing =
true;
1106 d =
sqrt(dx * dx + dy * dy + dz * dz);
1107 const double told = 1.e-6;
1111 std::cout << m_className <<
"::IntegrateTownsend: Small step.\n";
1113 integral += alpha0 * d;
1115 const double dxe = xe - x1;
1116 const double dye = ye - y1;
1117 const double dze = ze - z1;
1118 const double tol2 = told * told;
1119 if (dxe * dxe + dye * dye + dze * dze < tol2)
break;
1132 m_sensor->
ElectricField(x1, y1, z1, ex, ey, ez, m_medium, status);
1134 std::cerr << m_className <<
"::IntegrateTownsend: Invalid end point.\n";
1137 if (!GetTownsend(ex, ey, ez, bx, by, bz, alpha1)) {
1138 std::cerr << m_className <<
"::IntegrateTownsend:\n"
1139 <<
" Cannot retrieve Townsend coefficient at end point.\n";
1143 const double xm = 0.5 * (x0 + x1);
1144 const double ym = 0.5 * (y0 + y1);
1145 const double zm = 0.5 * (z0 + z1);
1147 m_sensor->
ElectricField(xm, ym, zm, ex, ey, ez, m_medium, status);
1149 std::cerr << m_className <<
"::IntegrateTownsend: Invalid mid point.\n";
1153 if (!GetTownsend(ex, ey, ez, bx, by, bz, alpham)) {
1154 std::cerr << m_className <<
"::IntegrateTownsend:\n"
1155 <<
" Cannot retrieve Townsend coefficient at mid point.\n";
1159 if (
fabs(alpha0 - 2. * alpham + alpha1) / 3. < eps) {
1161 integral += d * (alpha0 + 4. * alpham + alpha1) / 6.;
1167 if (
fabs(x0 - xe) < BoundaryDistance &&
1168 fabs(y0 - ye) < BoundaryDistance &&
1169 fabs(z0 - ze) < BoundaryDistance) {
1187void DriftLineRKF::ComputeSignal(
const double q,
const double scale)
const {
1189 if (m_nPoints < 2)
return;
1191 for (
unsigned int i = 0; i < m_nPoints - 1; ++i) {
1193 const double dt = m_path[i + 1].t - m_path[i].t;
1194 const double dx = m_path[i + 1].x - m_path[i].x;
1195 const double dy = m_path[i + 1].y - m_path[i].y;
1196 const double dz = m_path[i + 1].z - m_path[i].z;
1198 const double vx = dx / dt;
1199 const double vy = dy / dt;
1200 const double vz = dz / dt;
1202 const double xm = m_path[i].x + 0.5 * dx;
1203 const double ym = m_path[i].y + 0.5 * dy;
1204 const double zm = m_path[i].z + 0.5 * dz;
1207 g =
exp(m_path[i].alphaint);
1209 m_sensor->
AddSignal(q * g * scale, m_path[i].t, dt, xm, ym, zm, vx, vy, vz);
void SetIntegrationAccuracy(const double a)
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 SetSensor(Sensor *s)
bool DriftElectron(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)
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)
Get the magnetic field at (x, y, z).
bool IsInTrapRadius(const double q0, const double x0, const double y0, const double z0, double &xw, double &yw, double &rw)
void ElectricField(const double x, const double y, const double z, double &ex, double &ey, double &ez, double &v, Medium *&medium, int &status)
Get the drift field and potential at (x, y, z).
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)
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)
bool GetArea(double &xmin, double &ymin, double &zmin, double &xmax, double &ymax, double &zmax)
Return the current user area.
Visualize drift lines and tracks.
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)
DoubleAc pow(const DoubleAc &f, double p)
DoubleAc exp(const DoubleAc &f)
DoubleAc fabs(const DoubleAc &f)
DoubleAc sqrt(const DoubleAc &f)