Garfield++ v1r0
A toolkit for the detailed simulation of particle detectors based on ionisation measurement in gases and semiconductors
Loading...
Searching...
No Matches
DriftLineRKF.cc
Go to the documentation of this file.
1#include <iostream>
2#include <cmath>
3
4#include "DriftLineRKF.hh"
7
8namespace Garfield {
9
11 : m_sensor(0),
12 m_medium(0),
13 m_maxStepSize(1.e8),
14 m_accuracy(1.e-8),
15 m_maxSteps(1000),
16 m_usePlotting(false),
17 m_view(0),
18 m_scaleElectronSignal(1.),
19 m_scaleHoleSignal(1.),
20 m_scaleIonSignal(1.),
21 m_debug(false),
22 m_verbose(false) {
23
24 m_className = "DriftLineRKF";
25 m_path.clear();
26}
27
29
30 if (!s) {
31 std::cerr << m_className << "::SetSensor:\n";
32 std::cerr << " Sensor pointer is null.\n";
33 return;
34 }
35 m_sensor = s;
36}
37
39
40 if (a > 0.) {
41 m_accuracy = a;
42 } else {
43 std::cerr << m_className << "::SetIntegrationAccuracy:\n";
44 std::cerr << " Accuracy must be greater than zero.\n";
45 }
46}
47
48void DriftLineRKF::SetMaximumStepSize(const double ms) {
49
50 if (ms > 0.) {
51 m_maxStepSize = ms;
52 } else {
53 std::cerr << m_className << "::SetMaximumStepSize:\n";
54 std::cerr << " Step size must be greater than zero.\n";
55 }
56}
57
59
60 if (!view) {
61 std::cerr << m_className << "::EnablePlotting:\n";
62 std::cerr << " Viewer pointer is null.\n";
63 return;
64 }
65 m_usePlotting = true;
66 m_view = view;
67}
68
70
71 m_view = 0;
72 m_usePlotting = false;
73}
74
75bool DriftLineRKF::DriftElectron(const double& x0, const double& y0,
76 const double& z0, const double& t0) {
77
78 m_particleType = ParticleTypeElectron;
79 if (!DriftLine(x0, y0, z0, t0)) return false;
80 GetGain();
81 ComputeSignal();
82 return true;
83}
84
85bool DriftLineRKF::DriftHole(const double& x0, const double& y0,
86 const double& z0, const double& t0) {
87
88 m_particleType = ParticleTypeHole;
89 if (!DriftLine(x0, y0, z0, t0)) return false;
90 ComputeSignal();
91 return true;
92}
93
94bool DriftLineRKF::DriftIon(const double& x0, const double& y0,
95 const double& z0, const double& t0) {
96
97 m_particleType = ParticleTypeIon;
98 if (!DriftLine(x0, y0, z0, t0)) return false;
99 ComputeSignal();
100 return true;
101}
102
103bool DriftLineRKF::DriftLine(const double& x0, const double& y0,
104 const double& z0, const double& t0) {
105
106 // Check if the sensor is defined.
107 if (!m_sensor) {
108 std::cerr << m_className << "::DriftLine:\n";
109 std::cerr << " Sensor is not defined.\n";
110 return false;
111 }
112 // Get electric and magnetic field at initial position.
113 double ex = 0., ey = 0., ez = 0.;
114 double bx = 0., by = 0., bz = 0.;
115 int status = 0;
116 m_sensor->MagneticField(x0, y0, z0, bx, by, bz, status);
117 m_sensor->ElectricField(x0, y0, z0, ex, ey, ez, m_medium, status);
118 // Make sure the initial position is at a valid location.
119 if (status != 0) {
120 std::cerr << m_className << "::DriftLine:\n";
121 std::cerr << " No valid field at initial position.\n";
122 return false;
123 }
124
125 // Start plotting a new line if requested.
126 int iLine = 0;
127 if (m_usePlotting) {
128 if (m_particleType == ParticleTypeIon) {
129 m_view->NewIonDriftLine(1, iLine, x0, y0, z0);
130 } else if (m_particleType == ParticleTypeElectron) {
131 m_view->NewElectronDriftLine(1, iLine, x0, y0, z0);
132 } else if (m_particleType == ParticleTypeHole) {
133 m_view->NewHoleDriftLine(1, iLine, x0, y0, z0);
134 }
135 }
136 // Setup numerical constants for RKF integration.
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.;
143
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.;
150
151 // Current position
152 double x = x0;
153 double y = y0;
154 double z = z0;
155 // Initial velocity
156 double v0x = 0., v0y = 0., v0z = 0.;
157 // Velocities at mid-points
158 double v1[3] = {0., 0., 0.};
159 double v2[3] = {0., 0., 0.};
160 double v3[3] = {0., 0., 0.};
161 // Position where particle has crossed the trap radius of a wire
162 double rc[3] = {0., 0., 0.};
163 // Centre and radius of the wire at which the particle is to be terminated
164 double xWire = 0., yWire = 0.;
165 double rWire = 0.;
166 // Final velocity estimates
167 double phi1[3] = {0., 0., 0.};
168 double phi2[3] = {0., 0., 0.};
169
170 // Initialize particle velocity.
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";
174 return false;
175 }
176 const double vTot = sqrt(v0x * v0x + v0y * v0y + v0z * v0z);
177 if (vTot < Small) {
178 std::cerr << m_className << "::DriftLine:\n";
179 std::cerr << " Zero velocity at initial position.\n";
180 return false;
181 }
182 // Initialise time step and previous time step.
183 double dt = m_accuracy / vTot;
184 double pdt = 0.;
185
186 // Count the number of steps
187 unsigned int counter = 0;
188 // Flag whether to continue with the next drift step or not
189 bool keepGoing = true;
190 m_path.clear();
191 while (counter <= m_maxSteps && keepGoing) {
192 step tempStep;
193 m_path.push_back(tempStep);
194 m_path[counter].xi = x;
195 m_path[counter].yi = y;
196 m_path[counter].zi = z;
197 if (counter == 0) {
198 m_path[counter].ti = t0;
199 } else {
200 m_path[counter].ti = m_path[counter - 1].tf;
201 }
202 // Get first estimate of new drift velocity.
203 double x1 = x + dt * b10 * v0x;
204 double y1 = y + dt * b10 * v0y;
205 double z1 = z + dt * b10 * v0z;
206 m_sensor->MagneticField(x1, y1, z1, bx, by, bz, status);
207 m_sensor->ElectricField(x1, y1, z1, ex, ey, ez, m_medium, status);
208 if (status != 0) {
209 if (!EndDriftLine()) return false;
210 break;
211 }
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],
214 rc[2])) {
215 std::cerr << m_className << "::DriftLine:\n";
216 std::cerr << " Drift line crossed wire. Abandoning.\n";
217 m_path[counter].status = StatusCalculationAbandoned;
218 break;
219 }
220 if (m_sensor->IsInTrapRadius(x1, y1, z1, xWire, yWire, rWire) &&
221 m_particleType != ParticleTypeIon) {
222 if (!DriftToWire(x1, y1, z1, xWire, yWire, rWire)) return false;
223 break;
224 }
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";
228 return false;
229 }
230 // Get second estimate of new drift velocity.
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]);
234 m_sensor->MagneticField(x1, y1, z1, bx, by, bz, status);
235 m_sensor->ElectricField(x1, y1, z1, ex, ey, ez, m_medium, status);
236 if (status != 0) {
237 if (!EndDriftLine()) return false;
238 break;
239 }
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],
242 rc[2])) {
243 std::cerr << m_className << "::DriftLine:\n";
244 std::cerr << " Drift line crossed wire. Abandoning.\n";
245 m_path[counter].status = StatusCalculationAbandoned;
246 break;
247 }
248 if (m_sensor->IsInTrapRadius(x1, y1, z1, xWire, yWire, rWire) &&
249 m_particleType != ParticleTypeIon) {
250 if (!DriftToWire(x1, y1, z1, xWire, yWire, rWire)) return false;
251 break;
252 }
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";
256 return false;
257 }
258 // Get third estimate of new drift velocity.
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]);
262 m_sensor->MagneticField(x1, y1, z1, bx, by, bz, status);
263 m_sensor->ElectricField(x1, y1, z1, ex, ey, ez, m_medium, status);
264 if (status != 0) {
265 if (!EndDriftLine()) return false;
266 break;
267 }
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],
270 rc[2])) {
271 std::cerr << m_className << "::DriftLine:\n";
272 std::cerr << " Drift line crossed wire. Abandoning.\n";
273 m_path[counter].status = StatusCalculationAbandoned;
274 break;
275 }
276 if (m_sensor->IsInTrapRadius(x1, y1, z1, xWire, yWire, rWire) &&
277 m_particleType != ParticleTypeIon) {
278 if (!DriftToWire(x1, y1, z1, xWire, yWire, rWire)) return false;
279 break;
280 }
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";
284 return false;
285 }
286
287 // Calculate estimates of velocity over step.
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];
291
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];
295
296 // Check step length is valid.
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";
302 keepGoing = false;
303 } else if (dt * phi1Tot > m_maxStepSize) {
304 if (m_debug) {
305 std::cout << m_className << "::DriftLine: Step too long, reduce.\n";
306 }
307 dt = 0.5 * m_maxStepSize / phi1Tot;
308 } else {
309 if (m_debug) {
310 std::cout << m_className << "::DriftLine: Step good.\n";
311 }
312 }
313 pdt = dt;
314 // Update position.
315 x += dt * phi1[0];
316 y += dt * phi1[1];
317 z += dt * phi1[2];
318
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);
324 if (status != 0) {
325 if (!EndDriftLine()) return false;
326 break;
327 }
328
329 // Adjust step size depending on accuracy.
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) {
334 if (m_debug) {
335 std::cout << m_className << "::DriftLine: Adapting step size.\n";
336 }
337 dt = sqrt(dt * m_accuracy / (dphi0 + dphi1 + dphi2));
338 } else {
339 if (m_debug) {
340 std::cout << m_className << "::DriftLine: Increase step size.\n";
341 }
342 dt *= 2.;
343 }
344 // Make sure that dt is different from zero;
345 // this should always be ok.
346 if (dt <= 0.) {
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";
350 return false;
351 }
352 // Prevent step size from growing too fast.
353 if (dt > 10. * pdt) dt = 10. * pdt;
354 // Stop in case dt tends to become too small.
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";
359 return false;
360 }
361 // Update velocity.
362 v0x = v3[0];
363 v0y = v3[1];
364 v0z = v3[2];
365
366 if (keepGoing && counter <= m_maxSteps) {
367 m_path[counter].status = StatusAlive;
368 } else if (counter > m_maxSteps) {
369 m_path[counter].status = StatusTooManySteps;
370 } else {
371 m_path[counter].status = StatusCalculationAbandoned;
372 }
373 // Increase counter (default counter max = 1000)
374 ++counter;
375 }
376 const unsigned int nSteps = m_path.size();
377 if (m_verbose) {
378 // If requested, print step history.
379 std::cout << " Step # time Xi Yi Zi Xf Yf Zf dt "
380 " Status\n";
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";
388 }
389 }
390 if (m_usePlotting) {
391 for (unsigned int i = 0; i < nSteps; ++i) {
392 m_view->AddDriftLinePoint(iLine, m_path[i].xi, m_path[i].yi,
393 m_path[i].zi);
394 }
395 m_view->AddDriftLinePoint(iLine, m_path.back().xf, m_path.back().yf,
396 m_path.back().zf);
397 }
398 return true;
399}
400
402
403 const unsigned int nSteps = m_path.size();
404 double sum = 0.;
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);
408 }
409 return sqrt(sum);
410}
411
413
414 if (m_path.empty()) return 0.;
415 const unsigned int nSteps = m_path.size();
416 // First get a rough estimate of the result.
417 double crude = 0.;
418 double alpha0 = 0.;
419 double alpha1 = 0.;
420 for (unsigned int i = 0; i < nSteps; ++i) {
421 // Get the Townsend coefficient at this step.
422 const double x = m_path[i].xi;
423 const double y = m_path[i].yi;
424 const double z = m_path[i].zi;
425 double ex, ey, ez;
426 double bx, by, bz;
427 int status;
428 m_sensor->MagneticField(x, y, z, bx, by, bz, status);
429 m_sensor->ElectricField(x, y, z, ex, ey, ez, m_medium, status);
430 if (status != 0) {
431 std::cerr << m_className << "::GetGain:\n";
432 std::cerr << " Initial drift line point.\n";
433 return 0.;
434 }
435 if (0 == i) {
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";
439 return 0.;
440 }
441 } else {
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";
445 return 0.;
446 }
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);
452 alpha0 = alpha1;
453 }
454 }
455 // Calculate the integration tolerance based on the rough estimate.
456 const double tol = 1.e-4 * crude;
457 double sum = 0.;
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;
462 }
463 return exp(sum);
464}
465
467
468 if (m_path.empty()) return 0.;
469 return m_path.back().tf;
470}
471
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 {
476
477 if (m_particleType == ParticleTypeElectron) {
478 if (m_medium->ElectronVelocity(ex, ey, ez, bx, by, bz, vx, vy, vz)) {
479 return true;
480 }
481 } else if (m_particleType == ParticleTypeIon) {
482 if (m_medium->IonVelocity(ex, ey, ez, bx, by, bz, vx, vy, vz)) {
483 return true;
484 }
485 } else if (m_particleType == ParticleTypeHole) {
486 if (m_medium->HoleVelocity(ex, ey, ez, bx, by, bz, vx, vy, vz)) {
487 return true;
488 }
489 }
490 return false;
491}
492
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,
496 double& dt) const {
497
498 if (m_particleType == ParticleTypeElectron) {
499 if (m_medium->ElectronDiffusion(ex, ey, ez, bx, by, bz, dl, dt)) {
500 return true;
501 }
502 } else if (m_particleType == ParticleTypeIon) {
503 if (m_medium->IonDiffusion(ex, ey, ez, bx, by, bz, dl, dt)) {
504 return true;
505 }
506 } else if (m_particleType == ParticleTypeHole) {
507 if (m_medium->HoleDiffusion(ex, ey, ez, bx, by, bz, dl, dt)) {
508 return true;
509 }
510 }
511 return false;
512}
513
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 {
518
519 if (m_particleType == ParticleTypeElectron) {
520 if (m_medium->ElectronTownsend(ex, ey, ez, bx, by, bz, alpha)) {
521 return true;
522 }
523 } else if (m_particleType == ParticleTypeHole) {
524 if (m_medium->HoleTownsend(ex, ey, ez, bx, by, bz, alpha)) {
525 return true;
526 }
527 }
528 return false;
529}
530
531bool DriftLineRKF::EndDriftLine() {
532
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.;
542 int status = 0;
543 m_sensor->MagneticField(x0, y0, z0, bx, by, bz, status);
544 m_sensor->ElectricField(x0, y0, z0, ex, ey, ez, m_medium, status);
545 if (status != 0) {
546 std::cerr << m_className << "::EndDriftLine:\n";
547 std::cerr << " No valid field at initial point. Program bug!\n";
548 return false;
549 }
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";
554 return false;
555 }
556 const double speed = sqrt(vx * vx + vy * vy + vz * vz);
557 if (speed < Small) {
558 std::cerr << m_className << "::EndDriftLine:\n";
559 std::cerr << " Zero velocity at initial position.\n";
560 return false;
561 }
562 // Calculate the initial step size.
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;
568 vx *= scale;
569 vy *= scale;
570 vz *= scale;
571 } else {
572 // This is the first step. Start with a small step size.
573 vx *= m_accuracy / speed;
574 vy *= m_accuracy / speed;
575 vz *= m_accuracy / speed;
576 }
577 double x1 = x0;
578 double y1 = y0;
579 double z1 = z0;
580 // Step along the initial direction until we leave the volume.
581 bool inside = true;
582 while (inside) {
583 x1 += vx;
584 y1 += vy;
585 z1 += vz;
586 m_sensor->ElectricField(x1, y1, z1, ex, ey, ez, m_medium, status);
587 if (status != 0) inside = false;
588 }
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);
596 if (status == 0) {
597 x0 = x;
598 y0 = y;
599 z0 = z;
600 } else {
601 x1 = x;
602 y1 = y;
603 z1 = z;
604 }
605 }
606 // Set final position.
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;
616 return true;
617}
618
619bool DriftLineRKF::DriftToWire(double x0, double y0, double z0,
620 const double& xw, const double& yw,
621 const double& rw) {
622
623 if (m_debug) {
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";
628 }
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;
635
636 // Check initial position.
637 double ex = 0., ey = 0., ez = 0.;
638 double bx = 0., by = 0., bz = 0.;
639 int status = 0;
640 m_sensor->MagneticField(x0, y0, z0, bx, by, bz, status);
641 m_sensor->ElectricField(x0, y0, z0, ex, ey, ez, m_medium, status);
642 if (status != 0) {
643 std::cerr << m_className << "::DriftToWire:\n";
644 std::cerr << " Initial position not valid. Abandoning.\n";
645 return false;
646 }
647 // Calculate the drift velocity at the initial position.
648 double vx0 = 0.;
649 double vz0 = 0.;
650 double vy0 = 0.;
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";
654 return false;
655 }
656 // Get a coarse estimate of the drift time
657 // assuming a straight-line trajectory and constant velocity.
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) {
664 // JAMES MOTT HACK (5th Oct 2015) - m_path.back().xf,yf,zf not being set
665 // Put in flag here, remove return statement and check when looking for onwire flag
666 bool smallTimeStep = false;
667 if (dt0 < 1.e-6) {
668 if (m_debug) {
669 std::cout << m_className << "::DriftToWire:\n";
670 std::cout << " Estimated time step: " << dt0 << " ns. Stop.\n";
671 }
672 // Estimated time step is very small. Stop.
673 m_path.back().tf = m_path.back().ti + dt0;
674 m_path.back().status = StatusLeftDriftMedium;
675 // JAMES MOTT HACK (5th Oct 2015)
676 // return true;
677 smallTimeStep = true;
678 }
679 // Calculate the estimated end-point.
680 double x1 = x0 + dt0 * vx0;
681 double y1 = y0 + dt0 * vy0;
682 double z1 = z0 + dt0 * vz0;
683 if (m_debug) {
684 std::cout << m_className << "::DriftToWire:\n";
685 std::cout << " Step " << i << " from (" << x0 << ", " << y0
686 << ") to (" << x1 << ", " << y1 << ").\n";
687 }
688 // Make sure we are not moving away from the wire.
689 const double xin0 = (x1 - x0) * (xw - x0) + (y1 - y0) * (yw - y0);
690 if (xin0 < 0.) {
691 std::cerr << m_className << "::DriftToWire:\n";
692 std::cerr << " Particle moves away from the wire. Abandoning.\n";
693 return false;
694 }
695 // Check if the wire was crossed.
696 bool onwire = false;
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";
700 x1 = xc;
701 y1 = yc;
702 z1 = zc;
703 onwire = true;
704 const double dx10 = x1 - x0;
705 const double dy10 = y1 - y0;
706 dt0 = sqrt(dx10 * dx10 + dy10 * dy10) / (vx0 * vx0 + vy0 * vy0);
707 }
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;
712 // Get the field at this point.
713 m_sensor->MagneticField(x1, y1, z1, bx, by, bz, status);
714 m_sensor->ElectricField(x1, y1, z1, ex, ey, ez, m_medium, status);
715 if (status != 0) {
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;
720 return false;
721 }
722 // Calculate the drift velocity at this point.
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;
728 return false;
729 }
730
731 // Get a point halfway between.
732 const double xm = 0.5 * (x0 + x1);
733 const double ym = 0.5 * (y0 + y1);
734 const double zm = 0.5 * (z0 + z1);
735 // Get the field at this point.
736 m_sensor->MagneticField(xm, ym, zm, bx, by, bz, status);
737 m_sensor->ElectricField(xm, ym, zm, ex, ey, ez, m_medium, status);
738 if (status != 0) {
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;
743 return false;
744 }
745 // Calculate the drift velocity at this point.
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;
751 return false;
752 }
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);
756 // Make sure the velocities are non-zero.
757 if (speed0 < Small || speed1 < Small || speedm < Small) {
758 std::cerr << m_className << "::DriftToWire:\n";
759 std::cerr << " Zero velocity. Abandoning.\n";
760 return false;
761 }
762 // Compare first and second order estimates.
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)) &&
768 i < nMaxSteps - 1) {
769 // Accuracy was not good enough so halve the step time.
770 if (m_debug) {
771 std::cout << m_className << "::DriftToWire: Reducing step size.\n";
772 }
773 dt0 *= 0.5;
774 continue;
775 }
776 // Add point to the drift line.
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;
782 if (onwire) break;
783 // JAMES MOTT HACK (5th Oct 2015)
784 if(smallTimeStep) break;
785 step newStep;
786 newStep.xi = x1;
787 newStep.yi = y1;
788 newStep.zi = z1;
789 newStep.ti = m_path.back().tf;
790 m_path.push_back(newStep);
791 // Proceed to the next step
792 x0 = x1;
793 y0 = y1;
794 z0 = z1;
795 vx0 = vx1;
796 vy0 = vy1;
797 vz0 = vz1;
798 dx0 = xw - x0;
799 dy0 = yw - y0;
800 dt0 = (sqrt(dx0 * dx0 + dy0 * dy0) - rw - BoundaryDistance) /
801 sqrt(vx0 * vx0 + vy0 * vy0);
802 }
803 return true;
804}
805
806void DriftLineRKF::GetEndPoint(double& x, double& y, double& z, double& t,
807 int& stat) const {
808
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;
814}
815
816void DriftLineRKF::GetDriftLinePoint(const unsigned int i, double& x, double& y,
817 double& z, double& t) const {
818
819 if (i >= m_path.size()) {
820 std::cerr << m_className << "::GetDriftLinePoint:\n";
821 std::cerr << " Index is outside the range.\n";
822 return;
823 }
824
825 // Return midpoint of drift line stage
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);
830}
831
832double DriftLineRKF::IntegrateDiffusion(const double& x, const double& y,
833 const double& z, const double& xe,
834 const double& ye, const double& ze) {
835
836 if (m_debug) {
837 std::cout << m_className << "::IntegrateDiffusion:\n";
838 std::cout << " Integrating from ";
839 std::cout << x << ", " << y << ", " << z << " to " << xe << ", " << ye
840 << ", " << ze << "\n";
841 }
842 // Make sure initial position is valid.
843 double ex, ey, ez;
844 double bx, by, bz;
845 int status;
846 m_sensor->MagneticField(x, y, z, bx, by, bz, status);
847 m_sensor->ElectricField(x, y, z, ex, ey, ez, m_medium, status);
848 if (status != 0) {
849 std::cerr << m_className << "::IntegrateDiffusion:\n";
850 std::cerr << " Initial position not valid.\n";
851 return 0.;
852 }
853 // Determine drift velocity at initial position.
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";
858 return 0.;
859 }
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";
864 return 0.;
865 }
866 // Determine diffusion coefficients at initial position.
867 double dL0 = 0.;
868 double dT0 = 0.;
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";
872 return 0.;
873 }
874
875 // Start and end point coordinates of initial step.
876 double x0 = x;
877 double y0 = y;
878 double z0 = z;
879 double x1 = xe;
880 double y1 = ye;
881 double z1 = ze;
882
883 double integral = 0.;
884 bool keepGoing = true;
885 while (keepGoing) {
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);
890 if (d < 1.e-6) {
891 // Step length has become very small.
892 if (m_debug) {
893 std::cout << m_className << "::IntegrateDiffusion: Small step.\n";
894 }
895 const double s = dL0 / speed0;
896 integral += s * s * d;
897 // Check if we are close to the end point.
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;
902 // Proceed with the next step.
903 x0 = x1;
904 y0 = y1;
905 z0 = z1;
906 x1 = xe;
907 y1 = ye;
908 z1 = ze;
909 continue;
910 }
911 // Determine drift velocity and diffusion at the end point of the step.
912 m_sensor->MagneticField(x1, y1, z1, bx, by, bz, status);
913 m_sensor->ElectricField(x1, y1, z1, ex, ey, ez, m_medium, status);
914 if (status != 0) {
915 std::cerr << m_className << "::IntegrateDiffusion:\n";
916 std::cerr << " Invalid end point.\n";
917 break;
918 }
919 double vx1 = 0.;
920 double vy1 = 0.;
921 double vz1 = 0.;
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";
925 break;
926 }
927 double speed1 = sqrt(vx1 * vx1 + vy1 * vy1 + vz1 * vz1);
928 double dL1 = 0.;
929 double dT1 = 0.;
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";
933 break;
934 }
935 // Determine drift velocity and diffusion at the mid point of the step.
936 const double xm = 0.5 * (x0 + x1);
937 const double ym = 0.5 * (y0 + y1);
938 const double zm = 0.5 * (z0 + z1);
939 m_sensor->MagneticField(xm, ym, zm, bx, by, bz, status);
940 m_sensor->ElectricField(xm, ym, zm, ex, ey, ez, m_medium, status);
941 if (status != 0) {
942 std::cerr << m_className << "::IntegrateDiffusion:\n";
943 std::cerr << " Invalid mid point.\n";
944 break;
945 }
946 double vxm = 0.;
947 double vym = 0.;
948 double vzm = 0.;
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";
952 break;
953 }
954 double speedm = sqrt(vxm * vxm + vym * vym + vzm * vzm);
955 double dLm = 0.;
956 double dTm = 0.;
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";
960 break;
961 }
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);
966 // Calculate integral using Simpsons rule.
967 const double simpson = d * (s0 + 4. * sm + s1) / 6.;
968 // Calculate integral using trapezoidal rule.
969 const double trapez = d * (s0 + s1) / 2.;
970 // Compare the two estimates.
971 if (fabs(trapez - simpson) * sqrt(2. * d / (s0 + s1)) / 6. < tolerance) {
972 // Accuracy is good enough.
973 integral += simpson;
974 // Proceed to the next step.
975 x0 = x1;
976 y0 = y1;
977 z0 = z1;
978 dL0 = dL1;
979 dT0 = dT1;
980 speed0 = speed1;
981 x1 = xe;
982 y1 = ye;
983 z1 = ze;
984 } else {
985 // Accuracy is not good enough, so halve the step.
986 x1 = xm;
987 y1 = ym;
988 z1 = zm;
989 dL1 = dLm;
990 dT1 = dTm;
991 }
992 }
993 return integral;
994}
995
996double DriftLineRKF::IntegrateTownsend(const double& xi, const double& yi,
997 const double& zi,
998 const double& xe, const double& ye,
999 const double& ze,
1000 const double& tol) {
1001
1002 // Make sure initial position is valid.
1003 double ex = 0., ey = 0., ez = 0.;
1004 double bx = 0., by = 0., bz = 0.;
1005 int status = 0;
1006 m_sensor->MagneticField(xi, yi, zi, bx, by, bz, status);
1007 m_sensor->ElectricField(xi, yi, zi, ex, ey, ez, m_medium, status);
1008 if (status != 0) {
1009 std::cerr << m_className << "::IntegrateTownsend:\n";
1010 std::cerr << " Initial position (" << xi << ", " << yi << ", "
1011 << zi << ") not valid.\n";
1012 return 0.;
1013 }
1014 // Determine Townsend coefficient at initial point.
1015 double alpha0 = 0.;
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";
1019 return 0.;
1020 }
1021 // Make sure end position is valid.
1022 m_sensor->MagneticField(xe, ye, ze, bx, by, bz, status);
1023 m_sensor->ElectricField(xe, ye, ze, ex, ey, ez, m_medium, status);
1024 if (status != 0) {
1025 std::cerr << m_className << "::IntegrateTownsend:\n";
1026 std::cerr << " End position (" << xi << ", " << yi << ", "
1027 << zi << ") not valid.\n";
1028 return 0.;
1029 }
1030 // Determine Townsend coefficient at end point.
1031 double alpha1 = 0.;
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";
1035 return 0.;
1036 }
1037 // Start and end point coordinates of initial step.
1038 double x0 = xi;
1039 double y0 = yi;
1040 double z0 = zi;
1041 double x1 = xe;
1042 double y1 = ye;
1043 double z1 = ze;
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);
1048 // Calculate the convergence criterium.
1049 const double eps = tol / d;
1050 unsigned int stepCounter = 0;
1051 double integral = 0.;
1052 bool keepGoing = true;
1053 while (keepGoing) {
1054 dx = x1 - x0;
1055 dy = y1 - y0;
1056 dz = z1 - z0;
1057 d = sqrt(dx * dx + dy * dy + dz * dz);
1058 const double tol = 1.e-6;
1059 if (d < tol) {
1060 // Step length has become very small.
1061 if (m_debug) {
1062 std::cout << m_className << "::IntegrateTownsend: Small step.\n";
1063 }
1064 integral += alpha0 * d;
1065 // Check if we are close to the end point.
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;
1071 // Proceed with the next step.
1072 x0 = x1;
1073 y0 = y1;
1074 z0 = z1;
1075 x1 = xe;
1076 y1 = ye;
1077 z1 = ze;
1078 continue;
1079 }
1080 ++stepCounter;
1081 // Calculate the Townsend coefficient at the end point of the step.
1082 m_sensor->MagneticField(x1, y1, z1, bx, by, bz, status);
1083 m_sensor->ElectricField(x1, y1, z1, ex, ey, ez, m_medium, status);
1084 if (status != 0) {
1085 std::cerr << m_className << "::IntegrateTownsend:\n";
1086 std::cerr << " Invalid end point.\n";
1087 break;
1088 }
1089 double alpha1 = 0.;
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";
1093 break;
1094 }
1095 // Calculate the Townsend coefficient at the mid point of the step.
1096 const double xm = 0.5 * (x0 + x1);
1097 const double ym = 0.5 * (y0 + y1);
1098 const double zm = 0.5 * (z0 + z1);
1099 m_sensor->MagneticField(xm, ym, zm, bx, by, bz, status);
1100 m_sensor->ElectricField(xm, ym, zm, ex, ey, ez, m_medium, status);
1101 if (status != 0) {
1102 std::cerr << m_className << "::IntegrateTownsend:\n";
1103 std::cerr << " Invalid mid point.\n";
1104 break;
1105 }
1106 double alpham = 0.;
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";
1110 break;
1111 }
1112 // Check the accuracy of the result.
1113 if (fabs(alpha0 - 2. * alpham + alpha1) / 3. < eps) {
1114 // Accuracy is good enough.
1115 integral += d * (alpha0 + 4. * alpham + alpha1) / 6.;
1116 // Proceed to the next step.
1117 x0 = x1;
1118 y0 = y1;
1119 z0 = z1;
1120 alpha0 = alpha1;
1121 if (fabs(x0 - xe) < BoundaryDistance &&
1122 fabs(y0 - ye) < BoundaryDistance &&
1123 fabs(z0 - ze) < BoundaryDistance) {
1124 keepGoing = false;
1125 break;
1126 }
1127 x1 += dx;
1128 y1 += dy;
1129 z1 += dz;
1130 } else {
1131 // Accuracy is not good enough, so halve the step.
1132 x1 = xm;
1133 y1 = ym;
1134 z1 = zm;
1135 alpha1 = alpham;
1136 }
1137 }
1138 return integral;
1139}
1140
1141void DriftLineRKF::ComputeSignal() const {
1142
1143 const unsigned int nSteps = m_path.size();
1144 if (nSteps < 2) return;
1145 for (unsigned int i = 0; i < nSteps; ++i) {
1146 // Calculate step length.
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;
1151 // Calculate average velocity.
1152 const double vx = dx / dt;
1153 const double vy = dy / dt;
1154 const double vz = dz / dt;
1155 // Calculate midpoint.
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) {
1160 // Signal is weighted by avalanche size at this step.
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);
1167 }
1168 }
1169}
1170}
DoubleAc pow(const DoubleAc &f, double p)
Definition: DoubleAc.cpp:336
DoubleAc sqrt(const DoubleAc &f)
Definition: DoubleAc.cpp:313
DoubleAc exp(const DoubleAc &f)
Definition: DoubleAc.cpp:376
DoubleAc fabs(const DoubleAc &f)
Definition: DoubleAc.h:616
bool DriftElectron(const double &x0, const double &y0, const double &z0, const double &t0)
Definition: DriftLineRKF.cc:75
void SetIntegrationAccuracy(const double a)
Definition: DriftLineRKF.cc:38
void SetSensor(Sensor *s)
Definition: DriftLineRKF.cc:28
bool DriftHole(const double &x0, const double &y0, const double &z0, const double &t0)
Definition: DriftLineRKF.cc:85
bool DriftIon(const double &x0, const double &y0, const double &z0, const double &t0)
Definition: DriftLineRKF.cc:94
void GetDriftLinePoint(const unsigned int i, double &x, double &y, double &z, double &t) const
void EnablePlotting(ViewDrift *view)
Definition: DriftLineRKF.cc:58
double GetDriftTime() const
void GetEndPoint(double &x, double &y, double &z, double &t, int &st) const
void SetMaximumStepSize(const double ms)
Definition: DriftLineRKF.cc:48
virtual bool HoleTownsend(const double ex, const double ey, const double ez, const double bx, const double by, const double bz, double &alpha)
Definition: Medium.cc:1079
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)
Definition: Medium.cc:773
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)
Definition: Medium.cc:217
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)
Definition: Medium.cc:1211
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)
Definition: Medium.cc:388
virtual bool ElectronTownsend(const double ex, const double ey, const double ez, const double bx, const double by, const double bz, double &alpha)
Definition: Medium.cc:542
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)
Definition: Medium.cc:928
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)
Definition: Medium.cc:1268
void MagneticField(const double x, const double y, const double z, double &bx, double &by, double &bz, int &status)
Definition: Sensor.cc:95
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)
Definition: Sensor.cc:409
void ElectricField(const double x, const double y, const double z, double &ex, double &ey, double &ez, double &v, Medium *&medium, int &status)
Definition: Sensor.cc:44
bool IsInTrapRadius(double x0, double y0, double z0, double &xw, double &yw, double &rw)
Definition: Sensor.cc:291
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)
Definition: Sensor.cc:278
void NewElectronDriftLine(const unsigned int np, int &id, const double x0, const double y0, const double z0)
Definition: ViewDrift.cc:140
void AddDriftLinePoint(const unsigned int iL, const double x, const double y, const double z)
Definition: ViewDrift.cc:269
void NewHoleDriftLine(const unsigned int np, int &id, const double x0, const double y0, const double z0)
Definition: ViewDrift.cc:170
void NewIonDriftLine(const unsigned int np, int &id, const double x0, const double y0, const double z0)
Definition: ViewDrift.cc:195