Garfield++ v1r0
A toolkit for the detailed simulation of particle detectors based on ionisation measurement in gases and semiconductors
Loading...
Searching...
No Matches
AvalancheMC.cc
Go to the documentation of this file.
1#include <iostream>
2#include <fstream>
3#include <cmath>
4#include <string>
5
6#include "AvalancheMC.hh"
9#include "Random.hh"
10
11namespace Garfield {
12
13double AvalancheMC::c1 = ElectronMass / (SpeedOfLight * SpeedOfLight);
14
16 : m_sensor(NULL),
17 m_nDrift(0),
18 m_stepModel(2),
19 m_tMc(0.02),
20 m_dMc(0.001),
21 m_nMc(100),
22 m_hasTimeWindow(false),
23 m_tMin(0.),
24 m_tMax(0.),
25 m_nElectrons(0),
26 m_nHoles(0),
27 m_nIons(0),
28 m_nEndpointsElectrons(0),
29 m_nEndpointsHoles(0),
30 m_nEndpointsIons(0),
31 m_usePlotting(false),
32 m_viewer(NULL),
33 m_useSignal(false),
34 m_useInducedCharge(false),
35 m_useEquilibration(true),
36 m_useDiffusion(true),
37 m_useAttachment(false),
38 m_useBfield(false),
39 m_useIons(true),
40 m_withElectrons(true),
41 m_withHoles(true),
42 m_scaleElectronSignal(1.),
43 m_scaleHoleSignal(1.),
44 m_scaleIonSignal(1.),
45 m_debug(false) {
46
47 m_className = "AvalancheMC";
48
49 m_drift.reserve(10000);
50}
51
53
54 if (!s) {
55 std::cerr << m_className << "::SetSensor:\n";
56 std::cerr << " Sensor pointer is null.\n";
57 return;
58 }
59
60 m_sensor = s;
61}
62
64
65 if (!view) {
66 std::cerr << m_className << "::EnablePlotting:\n";
67 std::cerr << " Viewer pointer is null.\n";
68 return;
69 }
70
71 m_usePlotting = true;
72 m_viewer = view;
73}
74
76
77 m_viewer = NULL;
78 m_usePlotting = false;
79}
80
81void AvalancheMC::SetTimeSteps(const double d) {
82
83 m_stepModel = 0;
84 if (d < Small) {
85 std::cerr << m_className << "::SetTimeSteps:\n";
86 std::cerr << " Specified step size is too small.\n";
87 std::cerr << " Using default (20 ps) instead.\n";
88 m_tMc = 0.02;
89 } else {
90 if (m_debug) {
91 std::cout << m_className << "::SetTimeSteps:\n";
92 std::cout << " Step size set to " << d << " ns.\n";
93 }
94 m_tMc = d;
95 }
96}
97
98void AvalancheMC::SetDistanceSteps(const double d) {
99
100 m_stepModel = 1;
101 if (d < Small) {
102 std::cerr << m_className << "::SetDistanceSteps:\n";
103 std::cerr << " Specified step size is too small.\n";
104 std::cerr << " Using default (10 um) instead.\n";
105 m_dMc = 0.001;
106 } else {
107 if (m_debug) {
108 std::cout << m_className << "::SetDistanceSteps:\n";
109 std::cout << " Step size set to " << d << " cm.\n";
110 }
111 m_dMc = d;
112 }
113}
114
116
117 m_stepModel = 2;
118 if (n < 1) {
119 std::cerr << m_className << "::SetCollisionSteps:\n";
120 std::cerr << " Number of collisions to be skipped set to "
121 << " default value (100).\n";
122 m_nMc = 100;
123 } else {
124 if (m_debug) {
125 std::cout << m_className << "::SetCollisionSteps:\n";
126 std::cout << " Number of collisions to be skipped set to " << n
127 << ".\n";
128 }
129 m_nMc = n;
130 }
131}
132
133void AvalancheMC::SetTimeWindow(const double t0, const double t1) {
134
135 if (fabs(t1 - t0) < Small) {
136 std::cerr << m_className << "::SetTimeWindow:\n";
137 std::cerr << " Time interval must be greater than zero.\n";
138 return;
139 }
140
141 m_tMin = std::min(t0, t1);
142 m_tMax = std::max(t0, t1);
143 m_hasTimeWindow = true;
144}
145
146void AvalancheMC::UnsetTimeWindow() { m_hasTimeWindow = false; }
147
148void AvalancheMC::GetDriftLinePoint(const unsigned int i, double& x, double& y,
149 double& z, double& t) {
150
151 if (i >= m_nDrift) {
152 std::cerr << m_className << "::GetDriftLinePoint:\n";
153 std::cerr << " Index is outside the range.\n";
154 return;
155 }
156
157 x = m_drift[i].x;
158 y = m_drift[i].y;
159 z = m_drift[i].z;
160 t = m_drift[i].t;
161}
162
163void AvalancheMC::GetHoleEndpoint(const unsigned int i, double& x0, double& y0,
164 double& z0, double& t0, double& x1,
165 double& y1, double& z1, double& t1,
166 int& status) const {
167
168 if (i >= m_nEndpointsHoles) {
169 std::cerr << m_className << "::GetHoleEndpoint:\n";
170 std::cerr << " Endpoint " << i << " does not exist.\n";
171 return;
172 }
173
174 x0 = m_endpointsHoles[i].x0;
175 x1 = m_endpointsHoles[i].x1;
176 y0 = m_endpointsHoles[i].y0;
177 y1 = m_endpointsHoles[i].y1;
178 z0 = m_endpointsHoles[i].z0;
179 z1 = m_endpointsHoles[i].z1;
180 t0 = m_endpointsHoles[i].t0;
181 t1 = m_endpointsHoles[i].t1;
182 status = m_endpointsHoles[i].status;
183}
184
185void AvalancheMC::GetIonEndpoint(const unsigned int i, double& x0, double& y0,
186 double& z0, double& t0, double& x1, double& y1,
187 double& z1, double& t1, int& status) const {
188
189 if (i >= m_nEndpointsIons) {
190 std::cerr << m_className << "::GetIonEndpoint:\n";
191 std::cerr << " Endpoint " << i << " does not exist.\n";
192 return;
193 }
194
195 x0 = m_endpointsIons[i].x0;
196 x1 = m_endpointsIons[i].x1;
197 y0 = m_endpointsIons[i].y0;
198 y1 = m_endpointsIons[i].y1;
199 z0 = m_endpointsIons[i].z0;
200 z1 = m_endpointsIons[i].z1;
201 t0 = m_endpointsIons[i].t0;
202 t1 = m_endpointsIons[i].t1;
203 status = m_endpointsIons[i].status;
204}
205
206void AvalancheMC::GetElectronEndpoint(const unsigned int i,
207 double& x0, double& y0,
208 double& z0, double& t0, double& x1,
209 double& y1, double& z1, double& t1,
210 int& status) const {
211
212 if (i >= m_nEndpointsElectrons) {
213 std::cerr << m_className << "::GetElectronEndpoint:\n";
214 std::cerr << " Endpoint " << i << " does not exist.\n";
215 return;
216 }
217
218 x0 = m_endpointsElectrons[i].x0;
219 x1 = m_endpointsElectrons[i].x1;
220 y0 = m_endpointsElectrons[i].y0;
221 y1 = m_endpointsElectrons[i].y1;
222 z0 = m_endpointsElectrons[i].z0;
223 z1 = m_endpointsElectrons[i].z1;
224 t0 = m_endpointsElectrons[i].t0;
225 t1 = m_endpointsElectrons[i].t1;
226 status = m_endpointsElectrons[i].status;
227}
228
229bool AvalancheMC::DriftElectron(const double x0, const double y0,
230 const double z0, const double t0) {
231
232 if (!m_sensor) {
233 std::cerr << m_className << "::DriftElectron:\n";
234 std::cerr << " Sensor is not defined.\n";
235 return false;
236 }
237
238 m_endpointsElectrons.clear();
239 m_endpointsHoles.clear();
240 m_endpointsIons.clear();
241 m_nEndpointsElectrons = 0;
242 m_nEndpointsHoles = 0;
243 m_nEndpointsIons = 0;
244
245 m_nElectrons = 1;
246 m_nHoles = 0;
247 m_nIons = 0;
248
249 if (!DriftLine(x0, y0, z0, t0, -1)) return false;
250
251 return true;
252}
253
254bool AvalancheMC::DriftHole(const double x0, const double y0,
255 const double z0, const double t0) {
256
257 if (!m_sensor) {
258 std::cerr << m_className << "::DriftHole:\n";
259 std::cerr << " Sensor is not defined.\n";
260 return false;
261 }
262
263 m_endpointsElectrons.clear();
264 m_endpointsHoles.clear();
265 m_endpointsIons.clear();
266 m_nEndpointsElectrons = 0;
267 m_nEndpointsHoles = 0;
268 m_nEndpointsIons = 0;
269
270 m_nElectrons = 0;
271 m_nHoles = 1;
272 m_nIons = 0;
273
274 if (!DriftLine(x0, y0, z0, t0, 1)) return false;
275
276 return true;
277}
278
279bool AvalancheMC::DriftIon(const double x0, const double y0,
280 const double z0, const double t0) {
281
282 if (!m_sensor) {
283 std::cerr << m_className << "::DriftIon:\n";
284 std::cerr << " Sensor is not defined.\n";
285 return false;
286 }
287
288 m_endpointsElectrons.clear();
289 m_endpointsHoles.clear();
290 m_endpointsIons.clear();
291 m_nEndpointsElectrons = 0;
292 m_nEndpointsHoles = 0;
293 m_nEndpointsIons = 0;
294
295 m_nElectrons = 0;
296 m_nHoles = 0;
297 m_nIons = 1;
298
299 if (!DriftLine(x0, y0, z0, t0, 2)) return false;
300
301 return true;
302}
303
304bool AvalancheMC::DriftLine(const double x0, const double y0,
305 const double z0, const double t0,
306 const int type, const bool aval) {
307
308 // Current position
309 double x = x0, y = y0, z = z0;
310 // Time step
311 double delta;
312 // Medium
313 Medium* medium = 0;
314 // Electric field
315 int status = 0;
316 double ex = 0., ey = 0., ez = 0.;
317 // Magnetic field
318 double bx = 0., by = 0., bz = 0.;
319 // Drift velocity
320 double vx = 0., vy = 0., vz = 0., v = 0., vt = 0.;
321 // Longitudinal and transverse diffusion coefficients
322 double dl = 0., dt = 0.;
323 // Diffusion vector
324 double dx = 0., dy = 0., dz = 0., d = 0.;
325 // Rotation angles
326 double phi, cphi, sphi;
327 double theta, ctheta, stheta;
328 // Collision time
329 double tau = 0.;
330
331 // Reset the drift line.
332 m_drift.clear();
333 // Add the starting point to the drift line.
334 driftPoint point;
335 point.x = x0;
336 point.y = y0;
337 point.z = z0;
338 point.t = t0;
339 point.ne = 0;
340 point.nh = 0;
341 point.ni = 0;
342 m_drift.push_back(point);
343 m_nDrift = 1;
344
345 bool ok = true;
346 bool trapped = false;
347 bool validAlphaEta = false;
348 int abortReason = 0;
349
350 if (m_hasTimeWindow && (t0 < m_tMin || t0 > m_tMax)) {
351 std::cerr << m_className << "::DriftLine:\n";
352 std::cerr << " Starting time " << t0 << " is outside the specified\n";
353 std::cerr << " time window (" << m_tMin << ", " << m_tMax << ").\n";
354 ok = false;
355 abortReason = StatusOutsideTimeWindow;
356 }
357
358 // Get the electric field at the starting point.
359 m_sensor->ElectricField(x, y, z, ex, ey, ez, medium, status);
360 // Make sure the starting point is inside a drift medium.
361 if (status != 0) {
362 std::cerr << m_className << "::DriftLine:\n";
363 std::cerr << " No drift medium at initial position (" << x << ", " << y
364 << ", " << z << ").\n";
365 ok = false;
366 abortReason = StatusLeftDriftMedium;
367 }
368
369 double e = sqrt(ex * ex + ey * ey + ez * ez);
370 if (e < Small) {
371 std::cerr << m_className << "::DriftLine:\n";
372 std::cerr << " Electric field at initial position is too small:\n";
373 std::cerr << " ex = " << ex << " V/cm\n";
374 std::cerr << " ey = " << ey << " V/cm\n";
375 std::cerr << " ez = " << ez << " V/cm\n";
376 ok = false;
377 abortReason = StatusCalculationAbandoned;
378 }
379
380 if (m_useBfield) {
381 m_sensor->MagneticField(x, y, z, bx, by, bz, status);
382 bx *= Tesla2Internal;
383 by *= Tesla2Internal;
384 bz *= Tesla2Internal;
385 }
386
387 while (ok) {
388
389 // Compute the drift velocity and the diffusion coefficients.
390 if (type < 0) {
391 if (!medium->ElectronVelocity(ex, ey, ez, bx, by, bz, vx, vy, vz) ||
392 !medium->ElectronDiffusion(ex, ey, ez, bx, by, bz, dl, dt)) {
393 std::cerr << m_className << "::DriftLine:\n";
394 std::cerr << " Error calculating electron"
395 << " velocity or diffusion\n";
396 std::cerr << " at (" << x << ", " << y << ", " << z << ")\n";
397 ok = false;
398 abortReason = StatusCalculationAbandoned;
399 break;
400 }
401 } else if (type == 1) {
402 if (!medium->HoleVelocity(ex, ey, ez, bx, by, bz, vx, vy, vz) ||
403 !medium->HoleDiffusion(ex, ey, ez, bx, by, bz, dl, dt)) {
404 std::cerr << m_className << "::DriftLine:\n";
405 std::cerr << " Error calculating hole"
406 << " velocity or diffusion\n";
407 std::cerr << " at (" << x << ", " << y << ", " << z << ")\n";
408 ok = false;
409 abortReason = StatusCalculationAbandoned;
410 break;
411 }
412 } else if (type == 2) {
413 if (!medium->IonVelocity(ex, ey, ez, bx, by, bz, vx, vy, vz) ||
414 !medium->IonDiffusion(ex, ey, ez, bx, by, bz, dl, dt)) {
415 std::cerr << m_className << "::DriftLine:\n";
416 std::cerr << " Error calculating ion"
417 << " velocity or diffusion\n";
418 std::cerr << " at (" << x << ", " << y << ", " << z << ")\n";
419 ok = false;
420 abortReason = StatusCalculationAbandoned;
421 break;
422 }
423 } else {
424 std::cerr << m_className << "::DriftLine:\n";
425 std::cerr << " Unknown drift line type (" << type << ").\n";
426 std::cerr << " Program bug!\n";
427 ok = false;
428 abortReason = StatusCalculationAbandoned;
429 return false;
430 }
431 if (m_debug) {
432 std::cout << m_className << "::DriftLine:\n";
433 std::cout << " Drift velocity at " << x << ", " << y << ", " << z
434 << ": " << vx << ", " << vy << ", " << vz << "\n";
435 }
436 v = sqrt(vx * vx + vy * vy + vz * vz);
437 if (v < Small) {
438 std::cerr << m_className << "::DriftLine:\n";
439 std::cerr << " Drift velocity at (" << x << ", " << y << ", " << z
440 << ") is too small:\n";
441 std::cerr << " vx = " << vx << " cm/ns\n";
442 std::cerr << " vy = " << vy << " cm/ns\n";
443 std::cerr << " vz = " << vz << " cm/ns\n";
444 ok = false;
445 abortReason = StatusCalculationAbandoned;
446 break;
447 }
448
449 // Determine the time step.
450 switch (m_stepModel) {
451 case 0:
452 // Fixed time steps
453 delta = m_tMc;
454 break;
455 case 1:
456 // Fixed distance steps
457 delta = m_dMc / v;
458 break;
459 case 2:
460 // Steps based on collision time
461 tau = c1 * v / e;
462 delta = -m_nMc * tau * log(RndmUniformPos());
463 break;
464 default:
465 std::cerr << m_className << "::DriftLine:\n";
466 std::cerr << " Unknown stepping model.\n";
467 return false;
468 }
469
470 // Draw a random diffusion direction in the particle frame.
471 if (m_useDiffusion) {
472 d = sqrt(v * delta);
473 dx = d * RndmGaussian(0., dl);
474 dy = d * RndmGaussian(0., dt);
475 dz = d * RndmGaussian(0., dt);
476 }
477 if (m_debug) {
478 std::cout << m_className << "::DriftLine:\n";
479 std::cout << " Adding diffusion step "
480 << dx << ", " << dy << ", " << dz << "\n";
481 }
482 // Compute the rotation angles to align the diffusion
483 // and drift velocity vectors
484 vt = sqrt(vx * vx + vy * vy);
485 if (vt < Small) {
486 phi = 0.;
487 theta = HalfPi;
488 if (vz < 0.) theta = -theta;
489 } else {
490 phi = atan2(vy, vx);
491 theta = atan2(vz, vt);
492 }
493 cphi = cos(phi);
494 sphi = sin(phi);
495 ctheta = cos(theta);
496 stheta = sin(theta);
497
498 // Compute the proposed end-point of this step.
499 x += delta * vx + cphi * ctheta * dx - sphi * dy - cphi * stheta * dz;
500 y += delta * vy + sphi * ctheta * dx + cphi * dy - sphi * stheta * dz;
501 z += delta * vz + stheta * dx + ctheta * dz;
502
503 if (m_debug) {
504 std::cout << m_className << "::DriftLine:\n";
505 std::cout << " New point: "
506 << x << ", " << y << ", " << z << "\n";
507 }
508 // Compute the electric field at the new point.
509 m_sensor->ElectricField(x, y, z, ex, ey, ez, medium, status);
510
511 // Check if the new position is inside a drift medium.
512 if (status != 0) {
513 // Try to terminate the drift line
514 // close to the boundary.
515 dx = x - point.x;
516 dy = y - point.y;
517 dz = z - point.z;
518 d = sqrt(dx * dx + dy * dy + dz * dz);
519 if (d > 0.) {
520 dx /= d;
521 dy /= d;
522 dz /= d;
523 }
524 while (d > BoundaryDistance) {
525 delta *= 0.5;
526 d *= 0.5;
527 x = point.x + dx * d;
528 y = point.y + dy * d;
529 z = point.z + dz * d;
530 // Check if the mid-point is inside the drift medium.
531 m_sensor->ElectricField(x, y, z, ex, ey, ez, medium, status);
532 if (status == 0) {
533 point.x = x;
534 point.y = y;
535 point.z = z;
536 point.t += delta;
537 }
538 }
539 // Place the particle OUTSIDE the drift medium.
540 point.x += dx * d;
541 point.y += dy * d;
542 point.z += dz * d;
543 m_drift.push_back(point);
544 ++m_nDrift;
545 abortReason = StatusLeftDriftMedium;
546 if (m_debug) {
547 std::cout << m_className << "::DriftLine:\n";
548 std::cout << " Particle left the drift medium.\n";
549 std::cout << " At " << point.x << ", " << point.y << ", " << point.z
550 << "\n";
551 }
552 break;
553 }
554
555 // Check if the new position is inside the drift area.
556 if (!m_sensor->IsInArea(x, y, z)) {
557 // Try to terminate the drift line
558 // close to the boundary.
559 dx = x - point.x;
560 dy = y - point.y;
561 dz = z - point.z;
562 d = sqrt(dx * dx + dy * dy + dz * dz);
563 if (d > 0.) {
564 dx /= d;
565 dy /= d;
566 dz /= d;
567 }
568 while (d > BoundaryDistance) {
569 delta *= 0.5;
570 d *= 0.5;
571 x = point.x + dx * d;
572 y = point.y + dy * d;
573 z = point.z + dz * d;
574 // Check if the mid-point is inside the drift area.
575 if (m_sensor->IsInArea(x, y, z)) {
576 point.x = x;
577 point.y = y;
578 point.z = z;
579 point.t += delta;
580 }
581 }
582 // Place the particle OUTSIDE the drift area.
583 point.x += dx * d;
584 point.y += dy * d;
585 point.z += dz * d;
586 m_drift.push_back(point);
587 ++m_nDrift;
588 abortReason = StatusLeftDriftArea;
589 if (m_debug) {
590 std::cout << m_className << "::DriftLine:\n";
591 std::cout << " Particle left the drift area.\n";
592 std::cout << " At " << point.x << ", " << point.y << ", " << point.z
593 << "\n";
594 }
595 break;
596 }
597
598 // Check if the particle has crossed a wire.
599 double xCross = point.x, yCross = point.y, zCross = point.z;
600 if (m_sensor->IsWireCrossed(point.x, point.y, point.z, x, y, z, xCross,
601 yCross, zCross)) {
602 delta *=
603 sqrt(pow(xCross - point.x, 2) + pow(yCross - point.y, 2) +
604 pow(zCross - point.z, 2)) /
605 sqrt(pow(x - point.x, 2) + pow(y - point.y, 2) + pow(z - point.z, 2));
606 point.x = xCross;
607 point.y = yCross;
608 point.z = zCross;
609 point.t += delta;
610 m_drift.push_back(point);
611 ++m_nDrift;
612 abortReason = StatusLeftDriftMedium;
613 if (m_debug) {
614 std::cout << m_className << "::DriftLine:\n";
615 std::cout << " Particle hit a wire.\n";
616 std::cout << " At " << xCross << ", " << yCross << ", " << zCross
617 << "\n";
618 }
619 break;
620 }
621
622 e = sqrt(ex * ex + ey * ey + ez * ez);
623 if (e < Small) {
624 std::cerr << m_className << "::DriftLine:\n";
625 std::cerr << " Electric field at (" << x << ", " << y << ", " << z
626 << ") is too small:\n";
627 std::cerr << " ex = " << ex << " V/cm\n";
628 std::cerr << " ey = " << ey << " V/cm\n";
629 std::cerr << " ez = " << ez << " V/cm\n";
630 ok = false;
631 abortReason = StatusCalculationAbandoned;
632 break;
633 }
634 // Add the new point to drift line.
635 point.x = x;
636 point.y = y;
637 point.z = z;
638 point.t += delta;
639 m_drift.push_back(point);
640 ++m_nDrift;
641
642 // Check if the time is still within the specified interval.
643 if (m_hasTimeWindow && point.t > m_tMax) {
644 abortReason = StatusOutsideTimeWindow;
645 break;
646 }
647
648 if (m_useBfield) {
649 m_sensor->MagneticField(x, y, z, bx, by, bz, status);
650 bx *= Tesla2Internal;
651 by *= Tesla2Internal;
652 bz *= Tesla2Internal;
653 }
654 }
655
656 // Compute Townsend and attachment coefficients for each drift step.
657 unsigned int nElectronsOld = m_nElectrons;
658 unsigned int nHolesOld = m_nHoles;
659 unsigned int nIonsOld = m_nIons;
660 if ((type == -1 || type == 1) && (aval || m_useAttachment)) {
661 // Compute Townsend and attachment coefficient
662 validAlphaEta = ComputeAlphaEta(type);
663 if (ok) ok = validAlphaEta;
664 // Subdivision of a step
665 const double probth = 0.01;
666
667 // Set initial number of electrons/ions.
668 int ne = 1, ni = 0;
669 // Loop over the drift line.
670 for (unsigned int i = 0; i < m_nDrift - 1; ++i) {
671 m_drift[i].ne = 0;
672 m_drift[i].nh = 0;
673 m_drift[i].ni = 0;
674 // Only attempt avalanche calculation if alpha and eta are valid.
675 if (validAlphaEta) {
676 // Compute the number of subdivisions.
677 int nDiv = int((m_drift[i].alpha + m_drift[i].eta) / probth);
678 if (nDiv < 1) nDiv = 1;
679 // Probabilities for gain and loss.
680 const double alpha = std::max(m_drift[i].alpha / nDiv, 0.);
681 const double eta = std::max(m_drift[i].eta / nDiv, 0.);
682 // Set initial number of electrons/ions.
683 int neInit = ne, niInit = ni;
684 // Loop over the subdivisions.
685 for (int j = 0; j < nDiv; ++j) {
686 if (ne > 1000) {
687 // Gaussian approximation.
688 const int gain = int(
689 ne * alpha + RndmGaussian() * sqrt(ne * alpha * (1. - alpha)));
690 const int loss =
691 int(ne * eta + RndmGaussian() * sqrt(ne * eta * (1. - eta)));
692 ne += gain - loss;
693 ni += gain;
694 } else {
695 // Binomial approximation
696 for (int k = ne; k--;) {
697 if (RndmUniform() < alpha) {
698 ++ne;
699 ++ni;
700 }
701 if (RndmUniform() < eta) {
702 --ne;
703 }
704 }
705 }
706 // Check if the particle has survived.
707 if (ne <= 0) {
708 trapped = true;
709 if (type == -1) {
710 --m_nElectrons;
711 } else if (type == 1) {
712 --m_nHoles;
713 } else {
714 --m_nIons;
715 }
716 m_nDrift = i + 2;
717 m_drift[m_nDrift - 1].x = 0.5 * (m_drift[i].x + m_drift[i + 1].x);
718 m_drift[m_nDrift - 1].y = 0.5 * (m_drift[i].y + m_drift[i + 1].y);
719 m_drift[m_nDrift - 1].z = 0.5 * (m_drift[i].z + m_drift[i + 1].z);
720 break;
721 }
722 }
723 // If at least one new electron has been created,
724 // add the new electrons to the table.
725 if (ne - neInit >= 1) {
726 if (type == -1) {
727 m_drift[i].ne = ne - neInit;
728 m_nElectrons += ne - neInit;
729 } else if (type == 1) {
730 m_drift[i].nh = ne - neInit;
731 m_nHoles += ne - neInit;
732 } else {
733 m_drift[i].ni = ne - neInit;
734 m_nIons += ne - neInit;
735 }
736 }
737 if (ni - niInit >= 1) {
738 if (type == -1) {
739 if (m_useIons) {
740 m_drift[i].ni = ni - niInit;
741 m_nIons += ni - niInit;
742 } else {
743 m_drift[i].nh = ni - niInit;
744 m_nHoles += ni - niInit;
745 }
746 } else {
747 m_drift[i].ne = ni - niInit;
748 m_nElectrons += ni - niInit;
749 }
750 }
751 // If trapped, exit the loop over the drift line.
752 if (trapped) {
753 abortReason = StatusAttached;
754 if (m_debug) {
755 std::cout << m_className << "::DriftLine:\n";
756 std::cout << " Particle attached.\n";
757 std::cout << " At " << m_drift[m_nDrift - 1].x << ", "
758 << m_drift[m_nDrift - 1].y << ", " << m_drift[m_nDrift - 1].z
759 << "\n";
760 }
761 break;
762 }
763 }
764 }
765 }
766
767 // Create an "endpoint"
768 endpoint endPoint;
769 endPoint.x0 = x0;
770 endPoint.y0 = y0;
771 endPoint.z0 = z0;
772 endPoint.t0 = t0;
773 endPoint.status = abortReason;
774
775 endPoint.x1 = m_drift[m_nDrift - 1].x;
776 endPoint.y1 = m_drift[m_nDrift - 1].y;
777 endPoint.z1 = m_drift[m_nDrift - 1].z;
778 endPoint.t1 = m_drift[m_nDrift - 1].t;
779
780 if (m_debug) {
781 const int nNewElectrons = m_nElectrons - nElectronsOld;
782 const int nNewHoles = m_nHoles - nHolesOld;
783 const int nNewIons = m_nIons - nIonsOld;
784 std::cout << m_className << "::DriftLine:\n";
785 std::cout << " Produced\n"
786 << " " << nNewElectrons << " electrons,\n"
787 << " " << nNewHoles << " holes, and\n"
788 << " " << nNewIons << " ions\n"
789 << " along the drift line from \n"
790 << " (" << endPoint.x0 << ", " << endPoint.y0 << ", "
791 << endPoint.z0 << ") to \n"
792 << " (" << endPoint.x1 << ", " << endPoint.y1 << ", "
793 << endPoint.z1 << ").\n";
794 }
795
796 if (type == -1) {
797 m_endpointsElectrons.push_back(endPoint);
798 ++m_nEndpointsElectrons;
799 } else if (type == 1) {
800 m_endpointsHoles.push_back(endPoint);
801 ++m_nEndpointsHoles;
802 } else if (type == 2) {
803 m_endpointsIons.push_back(endPoint);
804 ++m_nEndpointsIons;
805 }
806
807 // Compute the induced signals if requested.
808 if (m_useSignal) {
809 if (type == 2) {
810 ComputeSignal(1. * m_scaleIonSignal);
811 } else if (type == 1) {
812 ComputeSignal(1. * m_scaleHoleSignal);
813 } else if (type < 0) {
814 ComputeSignal(-1. * m_scaleElectronSignal);
815 }
816 }
817 if (m_useInducedCharge) {
818 if (type == 2) {
819 ComputeInducedCharge(1. * m_scaleIonSignal);
820 } else if (type == 1) {
821 ComputeInducedCharge(1. * m_scaleHoleSignal);
822 } else if (type < 0) {
823 ComputeInducedCharge(-1. * m_scaleElectronSignal);
824 }
825 }
826
827 // Plot the drift line if requested.
828 if (m_usePlotting && m_nDrift > 0) {
829 int jL;
830 if (type < 0) {
831 m_viewer->NewElectronDriftLine(m_nDrift, jL, m_drift[0].x, m_drift[0].y,
832 m_drift[0].z);
833 } else if (type == 1) {
834 m_viewer->NewHoleDriftLine(m_nDrift, jL, m_drift[0].x, m_drift[0].y, m_drift[0].z);
835 } else {
836 m_viewer->NewIonDriftLine(m_nDrift, jL, m_drift[0].x, m_drift[0].y, m_drift[0].z);
837 }
838 for (unsigned int iP = 0; iP < m_nDrift; ++iP) {
839 m_viewer->SetDriftLinePoint(jL, iP, m_drift[iP].x, m_drift[iP].y, m_drift[iP].z);
840 }
841 }
842
843 if (!ok) return false;
844
845 return true;
846}
847
848bool AvalancheMC::AvalancheElectron(const double x0, const double y0,
849 const double z0, const double t0,
850 const bool holes) {
851
852 // Initialise the avalanche table
853 m_aval.clear();
854 avalPoint point;
855 point.x = x0;
856 point.y = y0;
857 point.z = z0;
858 point.t = t0;
859 point.ne = 1;
860 point.nh = 0;
861 point.ni = 0;
862 m_aval.push_back(point);
863
864 m_endpointsElectrons.clear();
865 m_endpointsHoles.clear();
866 m_endpointsIons.clear();
867 m_nEndpointsElectrons = 0;
868 m_nEndpointsHoles = 0;
869 m_nEndpointsIons = 0;
870
871 m_nElectrons = 1;
872 m_nHoles = 0;
873 m_nIons = 0;
874
875 m_withHoles = holes;
876 return Avalanche();
877}
878
879bool AvalancheMC::AvalancheHole(const double x0, const double y0,
880 const double z0, const double t0,
881 const bool electrons) {
882
883 // Initialise the avalanche table
884 m_aval.clear();
885 avalPoint point;
886 point.x = x0;
887 point.y = y0;
888 point.z = z0;
889 point.t = t0;
890 point.ne = 0;
891 point.nh = 1;
892 point.ni = 0;
893 m_aval.push_back(point);
894
895 m_endpointsElectrons.clear();
896 m_endpointsHoles.clear();
897 m_endpointsIons.clear();
898 m_nEndpointsElectrons = 0;
899 m_nEndpointsHoles = 0;
900 m_nEndpointsIons = 0;
901
902 m_nElectrons = 0;
903 m_nHoles = 1;
904 m_nIons = 0;
905
906 m_withElectrons = electrons;
907 return Avalanche();
908}
909
910bool AvalancheMC::AvalancheElectronHole(const double x0, const double y0,
911 const double z0, const double t0) {
912
913 // Initialise the avalanche table
914 m_aval.clear();
915 avalPoint point;
916 point.x = x0;
917 point.y = y0;
918 point.z = z0;
919 point.t = t0;
920 point.ne = 1;
921 point.nh = 1;
922 point.ni = 0;
923 m_aval.push_back(point);
924
925 m_endpointsElectrons.clear();
926 m_endpointsHoles.clear();
927 m_endpointsIons.clear();
928 m_nEndpointsElectrons = 0;
929 m_nEndpointsHoles = 0;
930 m_nEndpointsIons = 0;
931
932 m_nElectrons = 1;
933 m_nHoles = 1;
934 m_nIons = 0;
935
936 m_withElectrons = m_withHoles = true;
937 return Avalanche();
938}
939
940bool AvalancheMC::Avalanche() {
941
942 // Make sure that the sensor is defined
943 if (!m_sensor) {
944 std::cerr << m_className << "::Avalanche:\n";
945 std::cerr << " Sensor is not defined.\n";
946 return false;
947 }
948
949 avalPoint point;
950
951 if (!m_withHoles && !m_withElectrons) {
952 std::cerr << m_className << "::Avalanche:\n";
953 std::cerr << " Neither electron nor hole/ion component"
954 << " are activated.\n";
955 }
956
957 int nAval = m_aval.size();
958 while (nAval > 0) {
959 for (int iAval = nAval; iAval--;) {
960 if (m_withElectrons) {
961 // Loop over the electrons at this location.
962 for (int iE = m_aval[iAval].ne; iE--;) {
963 // Compute an electron drift line.
964 if (!DriftLine(m_aval[iAval].x, m_aval[iAval].y, m_aval[iAval].z,
965 m_aval[iAval].t, -1, true)) {
966 continue;
967 }
968 // Loop over the drift line.
969 for (unsigned int iDrift = 0; iDrift < m_nDrift - 2; ++iDrift) {
970 if (m_drift[iDrift].ne > 0 || m_drift[iDrift].nh > 0 ||
971 m_drift[iDrift].ni > 0) {
972 // Add the point to the table.
973 point.x = m_drift[iDrift + 1].x;
974 point.y = m_drift[iDrift + 1].y;
975 point.z = m_drift[iDrift + 1].z;
976 point.t = m_drift[iDrift + 1].t;
977 point.ne = m_drift[iDrift].ne;
978 point.nh = m_drift[iDrift].nh;
979 point.ni = m_drift[iDrift].ni;
980 m_aval.push_back(point);
981 }
982 }
983 }
984 }
985
986 if (m_withHoles) {
987 // Loop over the ions at this location.
988 for (int iI = 0; iI < m_aval[iAval].ni; ++iI) {
989 // Compute an ion drift line.
990 DriftLine(m_aval[iAval].x, m_aval[iAval].y, m_aval[iAval].z, m_aval[iAval].t,
991 2, false);
992 continue;
993 }
994
995 // Loop over the holes at this location.
996 for (int iH = 0; iH < m_aval[iAval].nh; ++iH) {
997 // Compute a hole drift line.
998 if (!DriftLine(m_aval[iAval].x, m_aval[iAval].y, m_aval[iAval].z,
999 m_aval[iAval].t, +1, true))
1000 continue;
1001 // Loop over the drift line.
1002 for (unsigned int iDrift = 0; iDrift < m_nDrift - 1; ++iDrift) {
1003 if (m_drift[iDrift].ne > 0 || m_drift[iDrift].nh > 0 ||
1004 m_drift[iDrift].ni > 0) {
1005 // Add the point to the table.
1006 point.x = m_drift[iDrift + 1].x;
1007 point.y = m_drift[iDrift + 1].y;
1008 point.z = m_drift[iDrift + 1].z;
1009 point.t = m_drift[iDrift + 1].t;
1010 point.ne = m_drift[iDrift].ne;
1011 point.nh = m_drift[iDrift].nh;
1012 point.ni = m_drift[iDrift].ni;
1013 m_aval.push_back(point);
1014 }
1015 }
1016 }
1017 }
1018 // Remove the avalanche point.
1019 m_aval.erase(m_aval.begin() + iAval);
1020 }
1021 nAval = m_aval.size();
1022 }
1023 return true;
1024}
1025
1026bool AvalancheMC::ComputeAlphaEta(const int type) {
1027
1028 // Locations and weights for 6-point Gaussian integration
1029 const double tg[6] = {-0.932469514203152028, -0.661209386466264514,
1030 -0.238619186083196909, 0.238619186083196909,
1031 0.661209386466264514, 0.932469514203152028};
1032 const double wg[6] = {0.171324492379170345, 0.360761573048138608,
1033 0.467913934572691047, 0.467913934572691047,
1034 0.360761573048138608, 0.171324492379170345};
1035
1036 // Medium
1037 Medium* medium;
1038 int status = 0;
1039 // Position
1040 double x, y, z;
1041 // Electric field
1042 double ex = 0., ey = 0., ez = 0.;
1043 // Magnetic field
1044 double bx = 0., by = 0., bz = 0.;
1045 // Drift velocity
1046 double vx = 0., vy = 0., vz = 0.;
1047 // Townsend and attachment coefficient
1048 double alpha = 0., eta = 0.;
1049
1050 // Integrated drift velocity
1051 double vdx = 0., vdy = 0., vdz = 0.;
1052
1053 // Loop a first time over the drift line.
1054 for (int i = m_nDrift - 1; i--;) {
1055 // Compute the step length.
1056 const double delx = m_drift[i + 1].x - m_drift[i].x;
1057 const double dely = m_drift[i + 1].y - m_drift[i].y;
1058 const double delz = m_drift[i + 1].z - m_drift[i].z;
1059 const double del = sqrt(delx * delx + dely * dely + delz * delz);
1060 // Compute the integrated drift velocity,
1061 // Townsend coefficient and attachment coefficient.
1062 vdx = 0., vdy = 0., vdz = 0.;
1063 m_drift[i].alpha = 0.;
1064 m_drift[i].eta = 0.;
1065 for (int j = 6; j--;) {
1066 x = m_drift[i].x + 0.5 * (1. + tg[j]) * delx;
1067 y = m_drift[i].y + 0.5 * (1. + tg[j]) * dely;
1068 z = m_drift[i].z + 0.5 * (1. + tg[j]) * delz;
1069 m_sensor->ElectricField(x, y, z, ex, ey, ez, medium, status);
1070 // Make sure that we are in a drift medium.
1071 if (status != 0) {
1072 // Check if this point is the last but one.
1073 const int lastButOne = m_nDrift - 2;
1074 if (i < lastButOne) {
1075 std::cerr << m_className << "::ComputeAlphaEta:\n";
1076 std::cerr << " Got status value " << status << " at segment "
1077 << j + 1 << "/6, drift point " << i + 1 << "/" << m_nDrift
1078 << ".\n";
1079 return false;
1080 }
1081 continue;
1082 }
1083 if (m_useBfield) {
1084 m_sensor->MagneticField(x, y, z, bx, by, bz, status);
1085 bx *= Tesla2Internal;
1086 by *= Tesla2Internal;
1087 bz *= Tesla2Internal;
1088 }
1089 if (type < 0) {
1090 medium->ElectronVelocity(ex, ey, ez, bx, by, bz, vx, vy, vz);
1091 medium->ElectronTownsend(ex, ey, ez, bx, by, bz, alpha);
1092 medium->ElectronAttachment(ex, ey, ez, bx, by, bz, eta);
1093 } else {
1094 medium->HoleVelocity(ex, ey, ez, bx, by, bz, vx, vy, vz);
1095 medium->HoleTownsend(ex, ey, ez, bx, by, bz, alpha);
1096 medium->HoleAttachment(ex, ey, ez, bx, by, bz, eta);
1097 }
1098 vdx += wg[j] * vx;
1099 vdy += wg[j] * vy;
1100 vdz += wg[j] * vz;
1101 m_drift[i].alpha += wg[j] * alpha;
1102 m_drift[i].eta += wg[j] * eta;
1103 }
1104 // Compute the scaling factor for the projected length.
1105 double scale = 1.;
1106 if (m_useEquilibration) {
1107 const double vd = sqrt(vdx * vdx + vdy * vdy + vdz * vdz);
1108 if (vd * del <= 0.) {
1109 scale = 0.;
1110 } else {
1111 const double dinv = delx * vdx + dely * vdy + delz * vdz;
1112 if (dinv < 0.) {
1113 scale = 0.;
1114 } else {
1115 scale = (delx * vdx + dely * vdy + delz * vdz) / (vd * del);
1116 }
1117 }
1118 }
1119 m_drift[i].alpha *= 0.5 * del * scale;
1120 m_drift[i].eta *= 0.5 * del * scale;
1121 }
1122
1123 // Skip equilibration if projection has not been requested.
1124 if (!m_useEquilibration) return true;
1125
1126 double sub1 = 0., sub2 = 0.;
1127 bool try1 = false, try2 = false, done = false;
1128 // Try to alpha-equilibrate the returning parts.
1129 for (unsigned int i = 0; i < m_nDrift - 1; ++i) {
1130 if (m_drift[i].alpha < 0.) {
1131 // Targets for subtracting
1132 sub1 = sub2 = -m_drift[i].alpha / 2.;
1133 try1 = try2 = false;
1134 // Try to subtract half in earlier points.
1135 for (unsigned int j = 0; j < i - 1; ++j) {
1136 if (m_drift[i - j].alpha > sub1) {
1137 m_drift[i - j].alpha -= sub1;
1138 m_drift[i].alpha += sub1;
1139 sub1 = 0.;
1140 try1 = true;
1141 break;
1142 } else if (m_drift[i - j].alpha > 0.) {
1143 m_drift[i].alpha += m_drift[i - j].alpha;
1144 sub1 -= m_drift[i - j].alpha;
1145 m_drift[i - j].alpha = 0.;
1146 }
1147 }
1148 // Try to subtract the other half in later points.
1149 for (unsigned int j = 0; j < m_nDrift - i - 1; ++j) {
1150 if (m_drift[i + j].alpha > sub2) {
1151 m_drift[i + j].alpha -= sub2;
1152 m_drift[i].alpha += sub2;
1153 sub2 = 0.;
1154 try2 = true;
1155 break;
1156 } else if (m_drift[i + j].alpha > 0.) {
1157 m_drift[i].alpha += m_drift[i + j].alpha;
1158 sub2 -= m_drift[i + j].alpha;
1159 m_drift[i + j].alpha = 0.;
1160 }
1161 }
1162
1163 // Done if both sides have margin left.
1164 done = false;
1165 if (try1 && try2) {
1166 done = true;
1167 } else if (try1) {
1168 sub1 = -m_drift[i].alpha;
1169 for (unsigned int j = 0; j < i - 1; ++j) {
1170 if (m_drift[i - j].alpha > sub1) {
1171 m_drift[i - j].alpha -= sub1;
1172 m_drift[i].alpha += sub1;
1173 sub1 = 0.;
1174 done = true;
1175 break;
1176 } else if (m_drift[i - j].alpha > 0.) {
1177 m_drift[i].alpha += m_drift[i - j].alpha;
1178 sub1 -= m_drift[i - j].alpha;
1179 m_drift[i - j].alpha = 0.;
1180 }
1181 }
1182 } else if (try2) {
1183 // Try upper side again.
1184 sub2 = -m_drift[i].alpha;
1185 for (unsigned int j = 0; j < m_nDrift - i - 1; ++j) {
1186 if (m_drift[i + j].alpha > sub2) {
1187 m_drift[i + j].alpha -= sub2;
1188 m_drift[i].alpha += sub2;
1189 sub2 = 0.;
1190 done = true;
1191 break;
1192 } else if (m_drift[i + j].alpha > 0.) {
1193 m_drift[i].alpha += m_drift[i + j].alpha;
1194 sub2 -= m_drift[i + j].alpha;
1195 m_drift[i + j].alpha = 0.;
1196 }
1197 }
1198 }
1199 // See whether we succeeded.
1200 if (!done) {
1201 if (m_debug) {
1202 std::cerr << m_className << "::ComputeAlphaEta:\n";
1203 std::cerr << " Unable to even out backwards alpha steps.\n";
1204 std::cerr << " Calculation is probably inaccurate.\n";
1205 }
1206 return false;
1207 }
1208 }
1209 }
1210
1211 // Try to eta-equilibrate the returning parts.
1212 for (unsigned int i = 0; i < m_nDrift - 1; ++i) {
1213 if (m_drift[i].eta < 0.) {
1214 // Targets for subtracting
1215 sub1 = -m_drift[i].eta / 2.;
1216 sub2 = -m_drift[i].eta / 2.;
1217 try1 = false;
1218 try2 = false;
1219 // Try to subtract half in earlier points.
1220 for (unsigned int j = 0; j < i - 1; ++j) {
1221 if (m_drift[i - j].eta > sub1) {
1222 m_drift[i - j].eta -= sub1;
1223 m_drift[i].eta += sub1;
1224 sub1 = 0.;
1225 try1 = true;
1226 break;
1227 } else if (m_drift[i - j].eta > 0.) {
1228 m_drift[i].eta += m_drift[i - j].eta;
1229 sub1 -= m_drift[i - j].eta;
1230 m_drift[i - j].eta = 0.;
1231 }
1232 }
1233 // Try to subtract the other half in later points.
1234 for (unsigned int j = 0; j < m_nDrift - i - 1; ++j) {
1235 if (m_drift[i + j].eta > sub2) {
1236 m_drift[i + j].eta -= sub2;
1237 m_drift[i].eta += sub2;
1238 sub2 = 0.;
1239 try2 = true;
1240 break;
1241 } else if (m_drift[i + j].eta > 0.) {
1242 m_drift[i].eta += m_drift[i + j].eta;
1243 sub2 -= m_drift[i + j].eta;
1244 m_drift[i + j].eta = 0.;
1245 }
1246 }
1247 done = false;
1248 if (try1 && try2) {
1249 done = true;
1250 } else if (try1) {
1251 // Try lower side again.
1252 sub1 = -m_drift[i].eta;
1253 for (unsigned int j = 0; j < i - 1; ++j) {
1254 if (m_drift[i - j].eta > sub1) {
1255 m_drift[i - j].eta -= sub1;
1256 m_drift[i].eta += sub1;
1257 sub1 = 0.;
1258 done = true;
1259 break;
1260 } else if (m_drift[i - j].eta > 0.) {
1261 m_drift[i].eta += m_drift[i - j].eta;
1262 sub1 -= m_drift[i - j].eta;
1263 m_drift[i - j].eta = 0.;
1264 }
1265 }
1266 } else if (try2) {
1267 // Try upper side again.
1268 sub2 = -m_drift[i].eta;
1269 for (unsigned int j = 0; j < m_nDrift - i - 1; ++j) {
1270 if (m_drift[i + j].eta > sub2) {
1271 m_drift[i + j].eta -= sub2;
1272 m_drift[i].eta += sub2;
1273 sub2 = 0.;
1274 done = true;
1275 break;
1276 } else if (m_drift[i + j].eta > 0.) {
1277 m_drift[i].eta += m_drift[i + j].eta;
1278 sub2 -= m_drift[i + j].eta;
1279 m_drift[i + j].eta = 0.;
1280 }
1281 }
1282 }
1283 if (!done) {
1284 if (m_debug) {
1285 std::cerr << m_className << "::ComputeAlphaEta:\n";
1286 std::cerr << " Unable to even out backwards eta steps.\n";
1287 std::cerr << " Calculation is probably inaccurate.\n";
1288 }
1289 return false;
1290 }
1291 }
1292 }
1293
1294 // Seems to have worked.
1295 return true;
1296}
1297
1298void AvalancheMC::ComputeSignal(const double q) {
1299
1300 if (m_nDrift < 2) return;
1301 double dt, dx, dy, dz;
1302 for (unsigned int i = 0; i < m_nDrift - 1; ++i) {
1303 dt = m_drift[i + 1].t - m_drift[i].t;
1304 dx = m_drift[i + 1].x - m_drift[i].x;
1305 dy = m_drift[i + 1].y - m_drift[i].y;
1306 dz = m_drift[i + 1].z - m_drift[i].z;
1307 m_sensor->AddSignal(q, m_drift[i].t, dt, m_drift[i].x + 0.5 * dx,
1308 m_drift[i].y + 0.5 * dy, m_drift[i].z + 0.5 * dz,
1309 dx / dt, dy / dt, dz / dt);
1310 }
1311}
1312
1313void AvalancheMC::ComputeInducedCharge(const double q) {
1314
1315 if (m_nDrift < 2) return;
1316 m_sensor->AddInducedCharge(q, m_drift[0].x, m_drift[0].y, m_drift[0].z,
1317 m_drift[m_nDrift - 1].x, m_drift[m_nDrift - 1].y,
1318 m_drift[m_nDrift - 1].z);
1319}
1320}
DoubleAc cos(const DoubleAc &f)
Definition: DoubleAc.cpp:431
DoubleAc pow(const DoubleAc &f, double p)
Definition: DoubleAc.cpp:336
DoubleAc sqrt(const DoubleAc &f)
Definition: DoubleAc.cpp:313
DoubleAc sin(const DoubleAc &f)
Definition: DoubleAc.cpp:383
DoubleAc fabs(const DoubleAc &f)
Definition: DoubleAc.h:616
void EnablePlotting(ViewDrift *view)
Definition: AvalancheMC.cc:63
void SetTimeSteps(const double d=0.02)
Definition: AvalancheMC.cc:81
bool AvalancheElectronHole(const double x0, const double y0, const double z0, const double t0)
Definition: AvalancheMC.cc:910
bool DriftIon(const double x0, const double y0, const double z0, const double t0)
Definition: AvalancheMC.cc:279
void SetTimeWindow(const double t0, const double t1)
Definition: AvalancheMC.cc:133
void GetIonEndpoint(const unsigned int i, double &x0, double &y0, double &z0, double &t0, double &x1, double &y1, double &z1, double &t1, int &status) const
Definition: AvalancheMC.cc:185
bool DriftElectron(const double x0, const double y0, const double z0, const double t0)
Definition: AvalancheMC.cc:229
void GetElectronEndpoint(const unsigned int i, double &x0, double &y0, double &z0, double &t0, double &x1, double &y1, double &z1, double &t1, int &status) const
Definition: AvalancheMC.cc:206
void SetCollisionSteps(const int n=100)
Definition: AvalancheMC.cc:115
void GetHoleEndpoint(const unsigned int i, double &x0, double &y0, double &z0, double &t0, double &x1, double &y1, double &z1, double &t1, int &status) const
Definition: AvalancheMC.cc:163
void GetDriftLinePoint(const unsigned int i, double &x, double &y, double &z, double &t)
Definition: AvalancheMC.cc:148
void SetSensor(Sensor *s)
Definition: AvalancheMC.cc:52
bool AvalancheElectron(const double x0, const double y0, const double z0, const double t0, const bool hole=false)
Definition: AvalancheMC.cc:848
void SetDistanceSteps(const double d=0.001)
Definition: AvalancheMC.cc:98
bool AvalancheHole(const double x0, const double y0, const double z0, const double t0, const bool electron=false)
Definition: AvalancheMC.cc:879
bool DriftHole(const double x0, const double y0, const double z0, const double t0)
Definition: AvalancheMC.cc:254
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 ElectronAttachment(const double ex, const double ey, const double ez, const double bx, const double by, const double bz, double &eta)
Definition: Medium.cc:609
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 HoleAttachment(const double ex, const double ey, const double ez, const double bx, const double by, const double bz, double &eta)
Definition: Medium.cc:1144
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 IsInArea(const double x, const double y, const double z)
Definition: Sensor.cc:254
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 AddInducedCharge(const double q, const double x0, const double y0, const double z0, const double x1, const double y1, const double z1)
Definition: Sensor.cc:493
void NewElectronDriftLine(const unsigned int np, int &id, const double x0, const double y0, const double z0)
Definition: ViewDrift.cc:140
void SetDriftLinePoint(const unsigned int iL, const unsigned int iP, const double x, const double y, const double z)
Definition: ViewDrift.cc:255
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
Definition: vec.h:477
double RndmUniform()
Definition: Random.hh:16
double RndmUniformPos()
Definition: Random.hh:19
double RndmGaussian()
Definition: Random.hh:27