Garfield++ 4.0
A toolkit for the detailed simulation of particle detectors based on ionisation measurement in gases and semiconductors
Loading...
Searching...
No Matches
AvalancheGrid.cc
Go to the documentation of this file.
2
3#include <TF1.h>
4
5#include <algorithm>
6#include <cmath>
7#include <iostream>
8
9#include "Garfield/Medium.hh"
10#include "Garfield/Random.hh"
11
12namespace Garfield {
13void AvalancheGrid::SetZGrid(Grid& av, const double ztop, const double zbottom,
14 const int zsteps) {
15 // Creating the z-coordinate grid.
16 av.zsteps = zsteps;
17 av.zStepSize = (ztop - zbottom) / zsteps;
18 // Loop bassed grid creation.
19 for (int i = 0; i < zsteps; i++) {
20 av.zgrid.push_back(zbottom + i * av.zStepSize);
21 }
22}
23
24void AvalancheGrid::SetYGrid(Grid& av, const double ytop, const double ybottom,
25 const int ysteps) {
26 // Idem to SetZGrid for the x-coordinate grid.
27 av.ysteps = ysteps;
28 av.yStepSize = (ytop - ybottom) / ysteps;
29
30 if (av.yStepSize == 0) av.yStepSize = 1;
31
32 for (int i = 0; i < ysteps; i++) {
33 av.ygrid.push_back(ybottom + i * av.yStepSize);
34 }
35}
36
37void AvalancheGrid::SetXGrid(Grid& av, const double xtop, const double xbottom,
38 const int xsteps) {
39 // Idem to SetZGrid for the x-coordinate grid.
40 av.xsteps = xsteps;
41 av.xStepSize = (xtop - xbottom) / xsteps;
42
43 if (av.xStepSize == 0) av.xStepSize = 1;
44
45 for (int i = 0; i < xsteps; i++) {
46 av.xgrid.push_back(xbottom + i * av.xStepSize);
47 }
48
49 std::vector<int> nhx(xsteps, 0);
50 std::vector<std::vector<int>> nhy(av.ysteps, nhx);
51 std::vector<std::vector<std::vector<int>>> nhz(av.zsteps, nhy);
52 av.n = nhz;
53
54 // Get the diffusion factors for neighboring points on the grid.
55 DiffusionFactors(av);
56}
57
58void AvalancheGrid::SetGrid(const double xmin, const double xmax,
59 const int xsteps, const double ymin,
60 const double ymax, const int ysteps,
61 const double zmin, const double zmax,
62 const int zsteps) {
63 m_avgrid.gridset = true;
64
65 if (zmin >= zmax || zsteps <= 0 || xmin > xmax || xsteps <= 0 ||
66 ymin > ymax || ysteps <= 0) {
67 std::cerr << m_className
68 << "::SetGrid:Error: Grid is not properly defined.\n";
69 return;
70 }
71
72 // Setting grid
73
74 SetZGrid(m_avgrid, zmax, zmin, zsteps);
75 SetYGrid(m_avgrid, ymax, ymin, ysteps);
76 SetXGrid(m_avgrid, xmax, xmin, xsteps);
77
78 if (m_sensor) GetParametersFromSensor();
79}
80
81int AvalancheGrid::GetAvalancheSize(double dx, const int nsize,
82 const double alpha, const double eta) {
83 // Algorithm to get the size of the avalanche after it has propagated over a
84 // distance dx.
85
86 int newnsize = 0; // Holder for final size.
87
88 const double k = eta / alpha;
89 const double ndx = exp((alpha - eta) *
90 dx); // Scaling Townsend and Attachment coef. to 1/mm.
91 // If the size is higher than 1e3 the central limit theorem will be used to
92 // describe the growth of the Townsend avalanche.
93 if (nsize < 1e3) {
94 // Running over all electrons in the avalanche.
95 for (int i = 0; i < nsize; i++) {
96 // Draw a random number from the uniform distribution (0,1).
97 double s = RndmUniformPos();
98 // Condition to which the random number will be compared. If the number is
99 // smaller than the condition, nothing happens. Otherwise, the single
100 // electron will be attached or retrieve additional electrons from the
101 // gas.
102 double condition = k * (ndx - 1) / (ndx - k);
103
104 if (s >= condition)
105 newnsize += (int)(1 + log((ndx - k) * (1 - s) / (ndx * (1 - k))) /
106 log(1 - (1 - k) / (ndx - k)));
107 }
108
109 } else {
110 // Central limit theorem.
111 const double sigma = sqrt((1 + k) * ndx * (ndx - 1) / (1 - k));
112 newnsize = RndmGaussian(nsize * ndx, sqrt(nsize) * sigma);
113 }
114
115 return newnsize;
116}
117
118bool AvalancheGrid::SnapToGrid(Grid& av, const double x, const double y,
119 const double z, const double /*v*/, const int n) {
120 // Snap electron from AvalancheMicroscopic to the predefined grid.
121 if (!av.gridset) {
122 std::cerr << m_className << "::SnapToGrid:Error: grid is not defined.\n";
123 return false;
124 }
125 // Finding the z position on the grid.
126
127 int indexX, indexY, indexZ = 0;
128
129 if (m_velNormal[0] != 0) {
130 indexX = m_velNormal[0] < 0 ? floor((x - av.xgrid.front()) / av.xStepSize)
131 : ceil((x - av.xgrid.front()) / av.xStepSize);
132 indexY = round((y - av.ygrid.front()) / av.yStepSize);
133 indexZ = round((z - av.zgrid.front()) / av.zStepSize);
134 } else if (m_velNormal[1] != 0) {
135 indexX = round((x - av.xgrid.front()) / av.xStepSize);
136 indexY = m_velNormal[1] < 0 ? floor((y - av.ygrid.front()) / av.yStepSize)
137 : ceil((y - av.ygrid.front()) / av.yStepSize);
138 indexZ = round((z - av.zgrid.front()) / av.zStepSize);
139 } else {
140 indexX = round((x - av.xgrid.front()) / av.xStepSize);
141 indexY = round((y - av.ygrid.front()) / av.yStepSize);
142 indexZ = m_velNormal[2] < 0 ? floor((z - av.zgrid.front()) / av.zStepSize)
143 : ceil((z - av.zgrid.front()) / av.zStepSize);
144 }
145
146 if (indexX < 0 || indexX >= av.xsteps || indexY < 0 || indexY >= av.ysteps ||
147 indexZ < 0 || indexZ >= av.zsteps)
148 return false;
149
150 av.gridPosition[2].push_back(indexX);
151 av.gridPosition[1].push_back(indexY);
152 av.gridPosition[0].push_back(indexZ);
153
154 // When snapping the electron to the grid the distance traveled can yield
155 // additional electrons or attachment.
156
157 double step = z - av.zgrid[indexZ];
158
159 if (m_velNormal[0] != 0) {
160 step = x - av.xgrid[indexX];
161 } else if (m_velNormal[1] != 0) {
162 step = y - av.ygrid[indexY];
163 }
164
165 const int nholder = GetAvalancheSize(step, n, m_Townsend, m_Attachment);
166
167 // av.N += nholder;
168 av.N += n;
169
170 av.n[indexZ][indexY][indexX] += nholder;
171 if (m_debug)
172 std::cerr << m_className << "::SnapToGrid: n from 1 to " << nholder
173 << ".\n";
174
175 if (m_debug)
176 std::cerr << m_className << "::SnapToGrid: Snapped to (x,y,z) = (" << x
177 << " -> " << av.xgrid[indexX] << ", " << y << " -> "
178 << av.ygrid[indexY] << ", " << z << " -> " << av.zgrid[indexZ]
179 << ").\n";
180 return true;
181}
182
183void AvalancheGrid::NextAvalancheGridPoint(Grid& av) {
184 // This main function propagates the electrons and applies the avalanche
185 // statistics.
186 int Nholder = 0; // Holds the avalanche size before propagating it to the
187 // next point in the grid.
188
189 av.run = false;
190
191 for (int& iz : av.gridPosition[0]) { // For every avalanche position on the
192 // z-coorindate grid.
193
194 // Check if it has reached the bottom resistive plate.
195
196 if ((m_velNormal[2] < 0 && iz == 0) ||
197 (m_velNormal[2] > 0 && iz == av.zsteps - 1)) {
198 continue;
199 } else {
200 av.run = true;
201 }
202
203 for (int& iy : av.gridPosition[1]) {
204 if ((m_velNormal[1] < 0 && iy == 0) ||
205 (m_velNormal[1] > 0 && iy == av.ysteps - 1)) {
206 av.run = false;
207 continue;
208 } else {
209 av.run = true;
210 }
211
212 for (int& ix : av.gridPosition[2]) {
213 if ((m_velNormal[0] < 0 && ix == 0) ||
214 (m_velNormal[0] > 0 && ix == av.xsteps - 1)) {
215 av.run = false;
216 continue;
217 } else {
218 av.run = true;
219 }
220
221 // Get avalanche size at z-index= iz and x-index=ix.
222 Nholder = av.n[iz][iy][ix];
223
224 if (Nholder == 0) continue; // If empty go to next point.
225 if (m_diffusion) {
226 // Idem to the else part of this function, but with the additional
227 // step that after the new avalanche size is calculated the charges
228 // will be spread over the neighboring x-points following the normal
229 // distribution given by the transverse diffusion coefficient.
230 double holdnsize = 0.;
231 if (av.N < m_MaxSize) {
232 double step = av.zStepSize;
233
234 if (m_velNormal[0] != 0) {
235 step = av.xStepSize;
236 } else if (m_velNormal[1] != 0) {
237 step = av.yStepSize;
238 }
239
240 holdnsize = GetAvalancheSize(step, av.n[iz][iy][ix], m_Townsend,
241 m_Attachment);
242
243 if (m_MaxSize - av.N < holdnsize - av.n[iz][iy][ix])
244 holdnsize = m_MaxSize - av.N + av.n[iz][iy][ix];
245
246 } else {
247 holdnsize = av.n[iz][iy][ix];
248 m_Saturated = true;
249
250 if (m_SaturationTime == -1)
251 m_SaturationTime = av.time + std::abs(av.zStepSize / av.velocity);
252 }
253
254 int chargeRemaining =
255 holdnsize; // Keeps charge of the amount of charge that is left
256 // over after it has spread to neighboring points. This
257 // will be the amount that will stay at the same
258 // x-coordinate grid point. This way no charge is lost
259 // during the diffusion step.
260
261 for (int j = av.transverseDiffusion.size() - 1; j >= 0; j--) {
262 int jx = 0;
263 int jy = 0;
264 int jz = 0;
265
266 if (m_velNormal[2] != 0) {
267 jy = j;
268 jz = j;
269 } else if (m_velNormal[1] != 0) {
270 jx = j;
271 jz = j;
272 } else {
273 jx = j;
274 jy = j;
275 }
276
277 if (ix - jx < 0 || ix + jx > av.xsteps - 1)
278 continue; // If in grid.
279 if (iy - jy < 0 || iy + jy > av.ysteps - 1) continue;
280 if (iz - jz < 0 || iz + jz > av.xsteps - 1) continue;
281
282 if (j > 0) { // For all neighboring points
283
284 int nxd = (int)(av.transverseDiffusion[j] * holdnsize);
285
286 av.n[iz - 1][iy][ix - j] += nxd;
287
288 av.n[iz - 1][iy][ix + j] += nxd;
289
290 m_sensor->AddSignal(-(nxd + Nholder) / 2, av.time,
291 av.time + av.zStepSize / av.velocity,
292 av.xgrid[ix], av.ygrid[iy], av.zgrid[iz],
293 av.xgrid[ix - j], av.ygrid[iy],
294 av.zgrid[iz - 1], false, true);
295
296 m_sensor->AddSignal(-(nxd + Nholder) / 2, av.time,
297 av.time + av.zStepSize / av.velocity,
298 av.xgrid[ix], av.ygrid[iy], av.zgrid[iz],
299 av.xgrid[ix + j], av.ygrid[iy],
300 av.zgrid[iz - 1], false, true);
301 chargeRemaining -= 2 * nxd;
302
303 } else { // For the initial x-position.
304 av.n[iz - 1][iy][ix] += chargeRemaining;
305
306 m_sensor->AddSignal(-(chargeRemaining + Nholder) / 2, av.time,
307 av.time + av.zStepSize / av.velocity,
308 av.xgrid[ix], av.ygrid[iy], av.zgrid[iz],
309 av.xgrid[ix], av.ygrid[iy], av.zgrid[iz - 1],
310 false, true);
311 }
312 }
313 av.N += holdnsize - Nholder;
314
315 } else {
316 // If the total avalanche size is smaller than the set saturation
317 // limit the GetAvalancheSize function is utilized to obtain the size
318 // after its propagation to the next z-coordinate grid point. Else,
319 // the size will be kept constant under the propagation.
320 if (av.N < m_MaxSize) {
321 int holdnsize = GetAvalancheSize(av.zStepSize, av.n[iz][iy][ix],
322 m_Townsend, m_Attachment);
323
324 if (m_MaxSize - av.N < holdnsize - av.n[iz][iy][ix])
325 holdnsize = m_MaxSize - av.N + av.n[iz][iy][ix];
326
327 av.n[iz + m_velNormal[2]][iy + m_velNormal[1]]
328 [ix + m_velNormal[0]] = holdnsize;
329
330 } else {
331 av.n[iz + m_velNormal[2]][iy + m_velNormal[1]]
332 [ix + m_velNormal[0]] = av.n[iz][iy][ix];
333 m_Saturated = true;
334
335 if (m_SaturationTime == -1)
336 m_SaturationTime = av.time + std::abs(av.zStepSize / av.velocity);
337 }
338 // Produce induced signal on readout electrodes.
339
340 m_sensor->AddSignal(
341 -(av.n[iz][iy][ix] +
342 av.n[iz + m_velNormal[2]][iy + m_velNormal[1]]
343 [ix + m_velNormal[0]]) /
344 2,
345 av.time, av.time + av.zStepSize / av.velocity, av.xgrid[ix],
346 av.ygrid[iy], av.zgrid[iz], av.xgrid[ix + m_velNormal[0]],
347 av.ygrid[iy + m_velNormal[1]], av.zgrid[iz - 1], false, true);
348
349 av.N += av.n[iz + m_velNormal[2]][iy + m_velNormal[1]]
350 [ix + m_velNormal[0]] -
351 Nholder; // Update total number of electrons.
352 }
353
354 av.n[iz][iy][ix] = 0; // Clear previous z-coordinate grid point.
355 }
356 }
357 }
358
359 // Update position index.
360 if (m_velNormal[2] != 0) {
361 for (int& iz : av.gridPosition[0])
362 if ((m_velNormal[2] < 0 && iz != 0) ||
363 (m_velNormal[2] > 0 && iz != av.zsteps - 1))
364 iz += m_velNormal[2];
365 } else if (m_velNormal[1] != 0) {
366 for (int& iy : av.gridPosition[1])
367 if ((m_velNormal[1] < 0 && iy != 0) ||
368 (m_velNormal[1] > 0 && iy != av.ysteps - 1))
369 iy += m_velNormal[1];
370 } else {
371 for (int& ix : av.gridPosition[2])
372 if ((m_velNormal[0] < 0 && ix != 0) ||
373 (m_velNormal[0] > 0 && ix != av.xsteps - 1))
374 ix += m_velNormal[0];
375 }
376 // After all active grid points have propagated, update the time.
377
378 av.time += std::abs(av.zStepSize / av.velocity);
379}
380
382 // Start the AvalancheGrid algorithm.
383 if ((!m_avmc && !m_driftAvalanche) || !m_sensor) return;
384
385 if (!m_importAvalanche && m_avmc) GetElectronsFromAvalancheMicroscopic();
386
387 std::cerr << m_className
388 << "::StartGridAvalanche::Starting grid based simulation with "
389 << m_avgrid.N << " initial electrons.\n";
390 if (m_avgrid.N <= 0) {
391 std::cerr << m_className << "::StartGridAvalanche::Cancelled.\n";
392 return;
393 }
394
395 m_nestart = m_avgrid.N;
396
397 // The vector containing the indexes of the z-coordinate grid points of the
398 // initial electrons needs to be ordered from small to large values. All
399 // duplicate values need to be removed.
400
401 GetParametersFromSensor();
402
403 SortPositionVector();
404
405 if (m_debug) {
406 std::cerr << m_className
407 << "::StartGridAvalanche::m_avgrid.gridPosition at iz = ";
408 for (size_t i = 0; i < m_avgrid.gridPosition[0].size(); i++) {
409 std::cerr << m_avgrid.gridPosition[0][i] << ",";
410 }
411 std::cerr << ".\n";
412 }
413
414 // Set velocity if given.
415 m_avgrid.velocity = m_Velocity;
416 // Main loop.
417 while (m_avgrid.run == true) {
418 NextAvalancheGridPoint(m_avgrid);
419 }
420
421 if (m_Saturated)
422 std::cerr << m_className
423 << "::StartGridAvalanche::Avalanche maximum size of " << m_MaxSize
424 << " electrons reached at " << m_SaturationTime << " ns.\n";
425
426 std::cerr << m_className
427 << "::StartGridAvalanche::Final avalanche size = " << m_avgrid.N
428 << " at t = " << m_avgrid.time << " ns.\n";
429
430 return;
431}
432
433void AvalancheGrid::DiffusionFactors(Grid& av) {
434 if (!m_diffusion) {
435 av.transverseDiffusion.push_back(1);
436 return;
437 }
438
439 // Get transverse diffusion factors, yielding in the spreading of charge.
440 if (!av.gridset || av.xStepSize <= 0) return;
441
442 auto cdfunctop = TF1("cdftop", "ROOT::Math::normal_cdf(x, [0],[1])", -5, 5);
443
444 cdfunctop.SetParameters(m_DiffSigma, 0.0);
445
446 double factor = 1;
447 int index = 0;
448
449 double x1, x2;
450 while (factor > 1e-3) { // 1e-3 is the precision cutoff.
451
452 x1 = -av.xStepSize / 2 + index * av.xStepSize;
453 x2 = av.xStepSize / 2 + index * av.xStepSize;
454
455 factor = (std::erf(x2 / (m_DiffSigma * std::sqrt(2))) -
456 std::erf(x1 / (m_DiffSigma * std::sqrt(2)))) /
457 2;
458
459 if (m_debug)
460 std::cerr << m_className
461 << "::DiffusionFactors::Transvers diffusion factor: " << factor
462 << ", comparison: "
463 << cdfunctop.Eval(0 - av.xStepSize / 2 + index * av.xStepSize) -
464 cdfunctop.Eval(0 + av.xStepSize / 2 +
465 index * av.xStepSize)
466 << ", top: "
467 << cdfunctop.Eval(0 - av.xStepSize / 2 + index * av.xStepSize)
468 << ", bottom: "
469 << cdfunctop.Eval(0 + av.xStepSize / 2 + index * av.xStepSize)
470 << ".\n";
471 av.transverseDiffusion.push_back(factor);
472
473 index++;
474 }
475
476 std::cerr << m_className
477 << "::DiffusionFactors::Transvers diffusion spreads to "
478 << av.transverseDiffusion.size() << " points.\n";
479
480 return;
481}
482
483void AvalancheGrid::CreateAvalanche(const double x, const double y,
484 const double z, const double t,
485 const int n) {
486 m_driftAvalanche = true;
487
488 if (m_avgrid.time == 0 && m_avgrid.time != t && m_debug)
489 std::cerr << m_className
490 << "::CreateAvalanche::Overwriting start time of avalanche for t "
491 "= 0 to "
492 << t << ".\n";
493 m_avgrid.time = t;
494
495 if (SnapToGrid(m_avgrid, x, y, z, 0, n) && m_debug)
496 std::cerr << m_className
497 << "::CreateAvalanche::Electron added at (t,x,y,z) = (" << t
498 << "," << x << "," << y << "," << z << ").\n";
499
500 // std::cerr<< m_className<< "::CreateAvalanche::expected contribution is "<<
501 // exp((m_Townsend-m_Attachment)*z) << ".\n";
502}
504 // Get the information of the electrons from the AvalancheMicroscopic class.
505 if (!m_avmc) return;
506
507 if (!m_importAvalanche) m_importAvalanche = true;
508
509 int np = m_avmc->GetNumberOfElectronEndpoints();
510
511 if (np == 0) return;
512
513 // Get initial positions of electrons
514 double x1, y1, z1, t1;
515 double x2, y2, z2, t2;
516 double e1, e2;
517 int status;
518
519 double vel = 0.;
520
521 for (int i = 0; i < np; ++i) {
522 m_avmc->GetElectronEndpoint(i, x1, y1, z1, t1, e1, x2, y2, z2, t2, e2,
523 status);
524
525 vel = (z2 - z1) / (t2 - t1);
526
527 m_avgrid.time = t2;
528
529 if (SnapToGrid(m_avgrid, x2, y2, z2, vel) && m_debug)
530 std::cerr << m_className
531 << "::GetElectronsFromAvalancheMicroscopic::Electron added at "
532 "(x,y,z) = ("
533 << x2 << "," << y2 << "," << z2 << ").\n";
534 }
535}
536
537void AvalancheGrid::GetParametersFromSensor() {
538 if (!m_sensor || m_SensorParameters) return;
539
540 double e[3], v;
541 int status;
542 Medium* m = nullptr;
543
544 m_sensor->ElectricField(
545 m_avgrid.xgrid[m_avgrid.xsteps / 2], m_avgrid.ygrid[m_avgrid.ysteps / 2],
546 m_avgrid.zgrid[m_avgrid.zsteps / 2], e[0], e[1], e[2], v, m, status);
547
548 if (m_Townsend == -1)
549 m->ElectronTownsend(e[0], e[1], e[2], 0., 0., 0., m_Townsend);
550
551 if (m_Attachment == -1)
552 m->ElectronAttachment(e[0], e[1], e[2], 0., 0., 0., m_Attachment);
553
554 if (m_Velocity == 0) {
555 double vx, vy, vz;
556 m->ElectronVelocity(e[0], e[1], e[2], 0., 0., 0., vx, vy, vz);
557
558 double vel = sqrt(vx * vx + vy * vy + vz * vz);
559 if (vel != std::abs(vx) && vel != std::abs(vy) && vel != std::abs(vz)) return;
560 int nx = (int)round(vx / vel);
561 int ny = (int)round(vy / vel);
562 int nz = (int)round(vz / vel);
563 m_velNormal = {nx, ny, nz};
564 m_Velocity = -std::abs(vel);
565 }
566
567 std::cerr << m_className << "::GetParametersFromSensor::Electric field = ("
568 << e[0] / 1000 << ", " << e[1] / 1000 << ", " << e[2] / 1000
569 << ") [kV/cm].\n";
570
571 std::cerr << m_className
572 << "::GetParametersFromSensor::Townsend = " << m_Townsend
573 << " [1/cm], Attachment = " << m_Attachment
574 << " [1/cm], Velocity = " << m_Velocity << " [cm/ns].\n";
575
576 m_SensorParameters = true;
577}
578
579void AvalancheGrid::SortPositionVector() {
580 for (int i = 0; i < 3; i++) {
581 sort(m_avgrid.gridPosition[i].begin(), m_avgrid.gridPosition[i].end());
582 m_avgrid.gridPosition[i].erase(unique(m_avgrid.gridPosition[i].begin(),
583 m_avgrid.gridPosition[i].end()),
584 m_avgrid.gridPosition[i].end());
585 }
586}
587
589 std::cerr << m_className << "::Reset::Resetting AvalancheGrid.\n";
590
591 m_avgrid.n.clear();
592 m_avgrid.transverseDiffusion.clear();
593 m_avgrid.time = 0;
594 m_avgrid.N = 0;
595 m_avgrid.run = true;
596
597 m_Saturated = false;
598 m_SaturationTime = -1;
599
600 m_driftAvalanche = false;
601
602 std::vector<int> nhx(m_avgrid.xsteps, 0);
603 std::vector<std::vector<int>> nhy(m_avgrid.ysteps, nhx);
604 std::vector<std::vector<std::vector<int>>> nhz(m_avgrid.zsteps, nhy);
605 m_avgrid.n = nhz;
606
607 for (int i = 0; i < 3; i++) {
608 m_avgrid.gridPosition[i].clear();
609 }
610
611 // Get the diffusion factors for neighboring points on the grid.
612 DiffusionFactors(m_avgrid);
613}
614} // namespace Garfield
void GetElectronsFromAvalancheMicroscopic()
Import electron data from AvalancheMicroscopic class.
void SetGrid(const double xmin, const double xmax, const int xsteps, const double ymin, const double ymax, const int ysteps, const double zmin, const double zmax, const int zsteps)
Import electron data from AvalancheMicroscopic class.
void CreateAvalanche(const double x, const double y, const double z, const double t=0, const int n=1)
void GetElectronEndpoint(const unsigned int i, double &x0, double &y0, double &z0, double &t0, double &e0, double &x1, double &y1, double &z1, double &t1, double &e1, int &status) const
unsigned int GetNumberOfElectronEndpoints() const
Abstract base class for media.
Definition: Medium.hh:13
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)
Drift velocity [cm / ns].
Definition: Medium.cc:379
virtual bool ElectronTownsend(const double ex, const double ey, const double ez, const double bx, const double by, const double bz, double &alpha)
Ionisation coefficient [cm-1].
Definition: Medium.cc:403
virtual bool ElectronAttachment(const double ex, const double ey, const double ez, const double bx, const double by, const double bz, double &eta)
Attachment coefficient [cm-1].
Definition: Medium.cc:416
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).
Definition: Sensor.cc:65
void AddSignal(const double q, const double t0, const double t1, const double x0, const double y0, const double z0, const double x1, const double y1, const double z1, const bool integrateWeightingField, const bool useWeightingPotential=false)
Add the signal from a charge-carrier step.
Definition: Sensor.cc:452
double RndmUniformPos()
Draw a random number uniformly distributed in the range (0, 1).
Definition: Random.hh:17
double RndmGaussian()
Draw a Gaussian random variate with mean zero and standard deviation one.
Definition: Random.hh:24
DoubleAc sqrt(const DoubleAc &f)
Definition: DoubleAc.cpp:314