14void AvalancheGrid::SetZGrid(Grid &av,
const double ztop,
const double zbottom,
18 av.zStepSize = (ztop - zbottom) / zsteps;
20 for (
int i = 0; i < zsteps; i++) {
21 av.zgrid.push_back(zbottom + i * av.zStepSize);
25void AvalancheGrid::SetYGrid(Grid &av,
const double ytop,
const double ybottom,
29 av.yStepSize = (ytop - ybottom) / ysteps;
31 if (av.yStepSize == 0) av.yStepSize = 1;
33 for (
int i = 0; i < ysteps; i++) {
34 av.ygrid.push_back(ybottom + i * av.yStepSize);
38void AvalancheGrid::SetXGrid(Grid &av,
const double xtop,
const double xbottom,
42 av.xStepSize = (xtop - xbottom) / xsteps;
44 if (av.xStepSize == 0) av.xStepSize = 1;
46 for (
int i = 0; i < xsteps; i++) {
47 av.xgrid.push_back(xbottom + i * av.xStepSize);
52 const int xsteps,
const double ymin,
53 const double ymax,
const int ysteps,
54 const double zmin,
const double zmax,
56 m_avgrid.gridset =
true;
58 if (zmin >= zmax || zsteps <= 0 || xmin > xmax || xsteps <= 0 ||
59 ymin > ymax || ysteps <= 0) {
60 std::cerr << m_className
61 <<
"::SetGrid:Error: Grid is not properly defined.\n";
67 SetZGrid(m_avgrid, zmax, zmin, zsteps);
68 SetYGrid(m_avgrid, ymax, ymin, ysteps);
69 SetXGrid(m_avgrid, xmax, xmin, xsteps);
72 std::cerr << m_className <<
"::SetGrid: Grid created:\n";
73 std::cerr <<
" x range = (" << xmin <<
"," << xmax <<
").\n";
74 std::cerr <<
" y range = (" << ymin <<
"," << ymax <<
").\n";
75 std::cerr <<
" z range = (" << zmin <<
"," << zmax <<
").\n";
80 const double alpha,
const double eta) {
86 const double k = eta / alpha;
87 const double ndx = exp((alpha - eta) *
93 for (
int i = 0; i < nsize; i++) {
100 double condition = k * (ndx - 1) / (ndx - k);
103 newnsize += (int)(1 + log((ndx - k) * (1 - s) / (ndx * (1 - k))) /
104 log(1 - (1 - k) / (ndx - k)));
109 const double sigma =
sqrt((1 + k) * ndx * (ndx - 1) / (1 - k));
116bool AvalancheGrid::SnapToGrid(Grid &av,
const double x,
const double y,
117 const double z,
const double ,
121 std::cerr << m_className <<
"::SnapToGrid:Error: grid is not defined.\n";
126 int indexX, indexY, indexZ = 0;
129 indexX = round((x - av.xgrid.front()) / av.xStepSize);
130 indexY = floor((y - av.ygrid.front()) / av.yStepSize);
131 indexZ = round((z - av.zgrid.front()) / av.zStepSize);
134 std::cerr << m_className <<
"::SnapToGrid: ix = " << indexX
135 <<
", iy = " << indexY <<
", iz = " << indexZ <<
".\n\n";
136 if (indexX < 0 || indexX >= av.xsteps || indexY < 0 || indexY >= av.ysteps ||
137 indexZ < 0 || indexZ >= av.zsteps) {
139 std::cerr << m_className <<
"::SnapToGrid: Point is outside the grid.\n";
143 AvalancheNode newNode;
147 if (!GetParameters(newNode)) {
150 std::cerr << m_className
151 <<
"::SnapToGrid: Could not retrieve parameters from sensor.\n";
158 double step =
z - av.zgrid[indexZ];
160 if (newNode.velNormal[0] != 0) {
161 step =
x - av.xgrid[indexX];
162 }
else if (newNode.velNormal[1] != 0) {
163 step =
y - av.ygrid[indexY];
170 std::cerr << m_className <<
"::SnapToGrid: n from 1 to 0 -> cancel.\n";
174 newNode.n = nholder < m_MaxSize ? nholder : m_MaxSize;
177 bool alreadyExists =
false;
179 for (AvalancheNode &existingNode : m_activeNodes) {
180 if (existingNode.ix == newNode.ix && existingNode.iy == newNode.iy &&
181 existingNode.iz == newNode.iz) {
182 alreadyExists =
true;
183 existingNode.n += newNode.n;
188 newNode.time = av.time;
189 if (!alreadyExists) m_activeNodes.push_back(newNode);
192 std::cerr << m_className <<
"::SnapToGrid: n from 1 to " << nholder <<
".\n"
193 <<
" Snapped to (x,y,z) = (" <<
x <<
" -> " << av.xgrid[indexX]
194 <<
", " <<
y <<
" -> " << av.ygrid[indexY] <<
", " <<
z <<
" -> "
195 << av.zgrid[indexZ] <<
").\n";
200void AvalancheGrid::NextAvalancheGridPoint(Grid &av) {
206 for (AvalancheNode &node : m_activeNodes) {
215 std::cerr << m_className <<
"::NextAvalancheGridPoint:(ix,iy,iz) = ("
216 << node.ix <<
"," << node.iy <<
"," << node.iz <<
").\n";
221 if (Nholder == 0)
continue;
227 if (!m_layerIndix && av.N < m_MaxSize) {
231 if (m_MaxSize - av.N < holdnsize - node.n)
232 holdnsize = m_MaxSize - av.N + node.n;
236 }
else if (m_layerIndix && m_NLayer[node.layer - 1] < m_MaxSize) {
240 if (m_MaxSize - m_NLayer[node.layer - 1] < holdnsize - node.n)
241 holdnsize = m_MaxSize - m_NLayer[node.layer - 1] + node.n;
248 if (m_SaturationTime == -1) m_SaturationTime = node.time + node.dt;
252 m_sensor->AddSignal(-(Nholder + node.n) / 2, node.time, node.time + node.dt,
253 av.xgrid[node.ix], av.ygrid[node.iy], av.zgrid[node.iz],
254 av.xgrid[node.ix + node.velNormal[0]],
255 av.ygrid[node.iy + node.velNormal[1]],
256 av.zgrid[node.iz + node.velNormal[2]],
false,
true);
260 if (m_layerIndix) m_NLayer[node.layer - 1] += node.n - Nholder;
262 av.N += node.n - Nholder;
268 if (m_debug) std::cerr <<
"n = " << Nholder <<
" -> " << node.n <<
".\n";
272 node.ix += node.velNormal[0];
273 node.iy += node.velNormal[1];
274 node.iz += node.velNormal[2];
277 if (m_debug) std::cerr <<
"t = " << node.time <<
" -> ";
278 node.time += node.dt;
279 if (m_debug) std::cerr << node.time <<
".\n";
281 DeactivateNode(node);
283 if (m_debug) std::cerr <<
"N = " << av.N <<
".\n\n";
286void AvalancheGrid::DeactivateNode(AvalancheNode &node) {
288 if (node.n == 0) node.active =
false;
290 if (node.velNormal[2] != 0) {
291 if ((node.velNormal[2] < 0 && node.iz == 0) ||
292 (node.velNormal[2] > 0 && node.iz == m_avgrid.zsteps - 1))
294 }
else if (node.velNormal[1] != 0) {
295 if ((node.velNormal[1] < 0 && node.iy == 0) ||
296 (node.velNormal[1] > 0 && node.iy == m_avgrid.ysteps - 1))
299 if ((node.velNormal[0] < 0 && node.ix == 0) ||
300 (node.velNormal[0] > 0 && node.ix == m_avgrid.xsteps - 1))
307 m_sensor->ElectricField(m_avgrid.xgrid[node.ix], m_avgrid.ygrid[node.iy],
308 m_avgrid.zgrid[node.iz], e[0], e[1], e[2], v, m,
311 if (status == -5 || status == -6) {
315 if (m_debug && !node.active)
316 std::cerr << m_className <<
"::DeactivateNode: Node deactivated.\n";
321 if ((!m_importAvalanche && !m_driftAvalanche) || !m_sensor)
return;
323 std::cerr << m_className
324 <<
"::StartGridAvalanche::Starting grid based simulation with "
325 << m_avgrid.N <<
" initial electrons.\n";
326 if (m_avgrid.N <= 0) {
327 std::cerr << m_className <<
"::StartGridAvalanche::Cancelled.\n";
331 m_nestart = m_avgrid.N;
334 while (m_avgrid.run ==
true) {
337 <<
"============ \n" << m_className
338 <<
"::StartGridAvalanche: Looping over nodes.\n ============ \n";
339 NextAvalancheGridPoint(m_avgrid);
342 std::vector<double> tlist = {};
343 for (AvalancheNode &node : m_activeNodes) {
344 tlist.push_back(node.time);
346 double maxTime = *max_element(std::begin(tlist), std::end(tlist));
349 std::cerr << m_className
350 <<
"::StartGridAvalanche::Avalanche maximum size of " << m_MaxSize
351 <<
" electrons reached at " << m_SaturationTime <<
" ns.\n";
353 std::cerr << m_className
354 <<
"::StartGridAvalanche::Final avalanche size = " << m_avgrid.N
355 <<
" ended at t = " << maxTime <<
" ns.\n";
361 const double z,
const double t,
363 m_driftAvalanche =
true;
365 if (m_avgrid.time == 0 && m_avgrid.time != t && m_debug)
366 std::cerr << m_className
367 <<
"::CreateAvalanche::Overwriting start time of avalanche for t "
368 "= 0 to " << t <<
".\n";
371 if (SnapToGrid(m_avgrid, x, y, z, 0, n) && m_debug)
372 std::cerr << m_className
373 <<
"::CreateAvalanche::Electron added at (t,x,y,z) = (" << t
374 <<
"," << x <<
"," << y <<
"," << z <<
").\n";
382 if (!m_importAvalanche) m_importAvalanche =
true;
388 if (electron.status != -17)
continue;
389 const auto& p1 = electron.path.at(0);
390 const auto& p2 = electron.path.back();
391 const double vel = (p2.z - p1.z) / (p2.t - p1.t);
392 m_avgrid.time = p2.t;
394 if (SnapToGrid(m_avgrid, p2.x, p2.y, p2.z, vel) && m_debug) {
395 std::cerr << m_className
396 <<
"::ImportElectronsFromAvalancheMicroscopic: Electron added at "
397 "(x,y,z) = (" << p2.x <<
"," << p2.y <<
"," << p2.z <<
").\n";
402bool AvalancheGrid::GetParameters(AvalancheNode &node) {
403 if (!m_sensor)
return false;
405 double x = m_avgrid.xgrid[node.ix];
406 double y = m_avgrid.ygrid[node.iy];
407 double z = m_avgrid.zgrid[node.iz];
410 std::cerr << m_className
411 <<
"::GetParametersFromSensor::Getting parameters from "
412 "(x,y,z) = (" << x <<
"," << y <<
"," << z <<
").\n";
417 m_sensor->
ElectricField(x, y, z, e[0], e[1], e[2], v, m, status);
420 std::cerr << m_className <<
"::GetParametersFromSensor::status = " << status
423 if (status == -5 || status == -6)
428 node.townsend = m_Townsend;
435 node.attachment = m_Attachment;
442 node.velocity = m_Velocity;
443 node.velNormal = m_velNormal;
448 double vel =
sqrt(vx * vx + vy * vy + vz * vz);
449 if (vel == 0.)
return false;
450 if (vel != std::abs(vx) && vel != std::abs(vy) && vel != std::abs(vz))
452 int nx = (int)round(vx / vel);
453 int ny = (int)round(vy / vel);
454 int nz = (int)round(vz / vel);
456 node.velNormal = {nx, ny, nz};
457 node.velocity = -std::abs(vel);
460 if (node.velNormal[0] != 0) {
461 node.stepSize = m_avgrid.xStepSize;
462 }
else if (node.velNormal[1] != 0) {
463 node.stepSize = m_avgrid.yStepSize;
465 node.stepSize = m_avgrid.zStepSize;
469 std::cerr << m_className <<
"::GetParametersFromSensor:\n"
470 <<
" stepSize = " << node.stepSize <<
" [cm].\n"
471 <<
" velNormal = (" << node.velNormal[0] <<
", "
472 << node.velNormal[1] <<
", " << node.velNormal[2] <<
") [1].\n";
474 node.dt = std::abs(node.stepSize / node.velocity);
477 if (m_debug || !m_printPar) {
478 std::cerr << m_className <<
"::GetParametersFromSensor:\n"
479 <<
" Electric field = (" << 1.e-3 * e[0] <<
", "
480 << 1.e-3 * e[1] <<
", " << 1.e-3 * e[2] <<
") [kV/cm].\n"
481 <<
" Townsend = " << node.townsend
482 <<
" [1/cm], Attachment = " << node.attachment
483 <<
" [1/cm], Velocity = " << node.velocity <<
" [cm/ns].\n";
486 std::cerr << m_className <<
"::StartGridAvalanche::Time steps per loop "
487 << node.dt <<
" ns.\n";
494 std::cerr << m_className <<
"::Reset::Resetting AvalancheGrid.\n";
500 m_SaturationTime = -1;
502 m_driftAvalanche =
false;
504 m_activeNodes.clear();
505 m_layerIndix =
false;
513 for (AvalancheNode &node : m_activeNodes) {
514 double y = m_avgrid.ygrid[node.iy];
517 nLayer[im - 1] += node.n;
void AvalancheElectron(const double x, const double y, const double z, const double t=0, const int n=1)
void ImportElectronsFromAvalancheMicroscopic(AvalancheMicroscopic *avmc)
Import electron data from AvalancheMicroscopic class.
void StartGridAvalanche()
void AsignLayerIndex(ComponentParallelPlate *RPC)
Asigning layer index to all Avalanche nodes.
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.
int GetAvalancheSize()
Returns the final number of electrons in the avalanche.
Calculate electron drift lines and avalanches using microscopic tracking.
const std::vector< Electron > & GetElectrons() const
Component for parallel-plate geometries.
bool getLayer(const double y, int &m, double &epsM)
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).
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)