13void AvalancheGrid::SetZGrid(Grid& av,
const double ztop,
const double zbottom,
17 av.zStepSize = (ztop - zbottom) / zsteps;
19 for (
int i = 0; i < zsteps; i++) {
20 av.zgrid.push_back(zbottom + i * av.zStepSize);
24void AvalancheGrid::SetYGrid(Grid& av,
const double ytop,
const double ybottom,
28 av.yStepSize = (ytop - ybottom) / ysteps;
30 if (av.yStepSize == 0) av.yStepSize = 1;
32 for (
int i = 0; i < ysteps; i++) {
33 av.ygrid.push_back(ybottom + i * av.yStepSize);
37void AvalancheGrid::SetXGrid(Grid& av,
const double xtop,
const double xbottom,
41 av.xStepSize = (xtop - xbottom) / xsteps;
43 if (av.xStepSize == 0) av.xStepSize = 1;
45 for (
int i = 0; i < xsteps; i++) {
46 av.xgrid.push_back(xbottom + i * av.xStepSize);
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);
59 const int xsteps,
const double ymin,
60 const double ymax,
const int ysteps,
61 const double zmin,
const double zmax,
63 m_avgrid.gridset =
true;
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";
74 SetZGrid(m_avgrid, zmax, zmin, zsteps);
75 SetYGrid(m_avgrid, ymax, ymin, ysteps);
76 SetXGrid(m_avgrid, xmax, xmin, xsteps);
78 if (m_sensor) GetParametersFromSensor();
81int AvalancheGrid::GetAvalancheSize(
double dx,
const int nsize,
82 const double alpha,
const double eta) {
88 const double k = eta / alpha;
89 const double ndx = exp((alpha - eta) *
95 for (
int i = 0; i < nsize; i++) {
102 double condition = k * (ndx - 1) / (ndx - k);
105 newnsize += (int)(1 + log((ndx - k) * (1 - s) / (ndx * (1 - k))) /
106 log(1 - (1 - k) / (ndx - k)));
111 const double sigma =
sqrt((1 + k) * ndx * (ndx - 1) / (1 - k));
118bool AvalancheGrid::SnapToGrid(Grid& av,
const double x,
const double y,
119 const double z,
const double ,
const int n) {
122 std::cerr << m_className <<
"::SnapToGrid:Error: grid is not defined.\n";
127 int indexX, indexY, indexZ = 0;
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);
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);
146 if (indexX < 0 || indexX >= av.xsteps || indexY < 0 || indexY >= av.ysteps ||
147 indexZ < 0 || indexZ >= av.zsteps)
150 av.gridPosition[2].push_back(indexX);
151 av.gridPosition[1].push_back(indexY);
152 av.gridPosition[0].push_back(indexZ);
157 double step =
z - av.zgrid[indexZ];
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];
165 const int nholder = GetAvalancheSize(step, n, m_Townsend, m_Attachment);
170 av.n[indexZ][indexY][indexX] += nholder;
172 std::cerr << m_className <<
"::SnapToGrid: n from 1 to " << nholder
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]
183void AvalancheGrid::NextAvalancheGridPoint(Grid& av) {
191 for (
int& iz : av.gridPosition[0]) {
196 if ((m_velNormal[2] < 0 && iz == 0) ||
197 (m_velNormal[2] > 0 && iz == av.zsteps - 1)) {
203 for (
int& iy : av.gridPosition[1]) {
204 if ((m_velNormal[1] < 0 && iy == 0) ||
205 (m_velNormal[1] > 0 && iy == av.ysteps - 1)) {
212 for (
int& ix : av.gridPosition[2]) {
213 if ((m_velNormal[0] < 0 && ix == 0) ||
214 (m_velNormal[0] > 0 && ix == av.xsteps - 1)) {
222 Nholder = av.n[iz][iy][ix];
224 if (Nholder == 0)
continue;
230 double holdnsize = 0.;
231 if (av.N < m_MaxSize) {
232 double step = av.zStepSize;
234 if (m_velNormal[0] != 0) {
236 }
else if (m_velNormal[1] != 0) {
240 holdnsize = GetAvalancheSize(step, av.n[iz][iy][ix], m_Townsend,
243 if (m_MaxSize - av.N < holdnsize - av.n[iz][iy][ix])
244 holdnsize = m_MaxSize - av.N + av.n[iz][iy][ix];
247 holdnsize = av.n[iz][iy][ix];
250 if (m_SaturationTime == -1)
251 m_SaturationTime = av.time + std::abs(av.zStepSize / av.velocity);
254 int chargeRemaining =
261 for (
int j = av.transverseDiffusion.size() - 1; j >= 0; j--) {
266 if (m_velNormal[2] != 0) {
269 }
else if (m_velNormal[1] != 0) {
277 if (ix - jx < 0 || ix + jx > av.xsteps - 1)
279 if (iy - jy < 0 || iy + jy > av.ysteps - 1)
continue;
280 if (iz - jz < 0 || iz + jz > av.xsteps - 1)
continue;
284 int nxd = (int)(av.transverseDiffusion[j] * holdnsize);
286 av.n[iz - 1][iy][ix - j] += nxd;
288 av.n[iz - 1][iy][ix + j] += nxd;
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);
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;
304 av.n[iz - 1][iy][ix] += chargeRemaining;
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],
313 av.N += holdnsize - Nholder;
320 if (av.N < m_MaxSize) {
321 int holdnsize = GetAvalancheSize(av.zStepSize, av.n[iz][iy][ix],
322 m_Townsend, m_Attachment);
324 if (m_MaxSize - av.N < holdnsize - av.n[iz][iy][ix])
325 holdnsize = m_MaxSize - av.N + av.n[iz][iy][ix];
327 av.n[iz + m_velNormal[2]][iy + m_velNormal[1]]
328 [ix + m_velNormal[0]] = holdnsize;
331 av.n[iz + m_velNormal[2]][iy + m_velNormal[1]]
332 [ix + m_velNormal[0]] = av.n[iz][iy][ix];
335 if (m_SaturationTime == -1)
336 m_SaturationTime = av.time + std::abs(av.zStepSize / av.velocity);
342 av.n[iz + m_velNormal[2]][iy + m_velNormal[1]]
343 [ix + m_velNormal[0]]) /
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);
349 av.N += av.n[iz + m_velNormal[2]][iy + m_velNormal[1]]
350 [ix + m_velNormal[0]] -
354 av.n[iz][iy][ix] = 0;
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];
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];
378 av.time += std::abs(av.zStepSize / av.velocity);
383 if ((!m_avmc && !m_driftAvalanche) || !m_sensor)
return;
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";
395 m_nestart = m_avgrid.N;
401 GetParametersFromSensor();
403 SortPositionVector();
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] <<
",";
415 m_avgrid.velocity = m_Velocity;
417 while (m_avgrid.run ==
true) {
418 NextAvalancheGridPoint(m_avgrid);
422 std::cerr << m_className
423 <<
"::StartGridAvalanche::Avalanche maximum size of " << m_MaxSize
424 <<
" electrons reached at " << m_SaturationTime <<
" ns.\n";
426 std::cerr << m_className
427 <<
"::StartGridAvalanche::Final avalanche size = " << m_avgrid.N
428 <<
" at t = " << m_avgrid.time <<
" ns.\n";
433void AvalancheGrid::DiffusionFactors(Grid& av) {
435 av.transverseDiffusion.push_back(1);
440 if (!av.gridset || av.xStepSize <= 0)
return;
442 auto cdfunctop = TF1(
"cdftop",
"ROOT::Math::normal_cdf(x, [0],[1])", -5, 5);
444 cdfunctop.SetParameters(m_DiffSigma, 0.0);
450 while (factor > 1e-3) {
452 x1 = -av.xStepSize / 2 + index * av.xStepSize;
453 x2 = av.xStepSize / 2 + index * av.xStepSize;
455 factor = (std::erf(x2 / (m_DiffSigma * std::sqrt(2))) -
456 std::erf(x1 / (m_DiffSigma * std::sqrt(2)))) /
460 std::cerr << m_className
461 <<
"::DiffusionFactors::Transvers diffusion factor: " << factor
463 << cdfunctop.Eval(0 - av.xStepSize / 2 + index * av.xStepSize) -
464 cdfunctop.Eval(0 + av.xStepSize / 2 +
465 index * av.xStepSize)
467 << cdfunctop.Eval(0 - av.xStepSize / 2 + index * av.xStepSize)
469 << cdfunctop.Eval(0 + av.xStepSize / 2 + index * av.xStepSize)
471 av.transverseDiffusion.push_back(factor);
476 std::cerr << m_className
477 <<
"::DiffusionFactors::Transvers diffusion spreads to "
478 << av.transverseDiffusion.size() <<
" points.\n";
484 const double z,
const double t,
486 m_driftAvalanche =
true;
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 "
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";
507 if (!m_importAvalanche) m_importAvalanche =
true;
514 double x1, y1, z1, t1;
515 double x2, y2, z2, t2;
521 for (
int i = 0; i < np; ++i) {
522 m_avmc->
GetElectronEndpoint(i, x1, y1, z1, t1, e1, x2, y2, z2, t2, e2,
525 vel = (z2 - z1) / (t2 - t1);
529 if (SnapToGrid(m_avgrid, x2, y2, z2, vel) && m_debug)
530 std::cerr << m_className
531 <<
"::GetElectronsFromAvalancheMicroscopic::Electron added at "
533 << x2 <<
"," << y2 <<
"," << z2 <<
").\n";
537void AvalancheGrid::GetParametersFromSensor() {
538 if (!m_sensor || m_SensorParameters)
return;
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);
548 if (m_Townsend == -1)
551 if (m_Attachment == -1)
554 if (m_Velocity == 0) {
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);
567 std::cerr << m_className <<
"::GetParametersFromSensor::Electric field = ("
568 << e[0] / 1000 <<
", " << e[1] / 1000 <<
", " << e[2] / 1000
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";
576 m_SensorParameters =
true;
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());
589 std::cerr << m_className <<
"::Reset::Resetting AvalancheGrid.\n";
592 m_avgrid.transverseDiffusion.clear();
598 m_SaturationTime = -1;
600 m_driftAvalanche =
false;
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);
607 for (
int i = 0; i < 3; i++) {
608 m_avgrid.gridPosition[i].clear();
612 DiffusionFactors(m_avgrid);
void GetElectronsFromAvalancheMicroscopic()
Import electron data from AvalancheMicroscopic class.
void StartGridAvalanche()
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.
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].
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].
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].
void ElectricField(const double x, const double y, const double z, double &ex, double &ey, double &ez, double &v, Medium *&medium, int &status)
Get the drift field and potential at (x, y, z).
void AddSignal(const double q, const double 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.
double RndmUniformPos()
Draw a random number uniformly distributed in the range (0, 1).
double RndmGaussian()
Draw a Gaussian random variate with mean zero and standard deviation one.
DoubleAc sqrt(const DoubleAc &f)