Garfield++ 5.0
A toolkit for the detailed simulation of particle detectors based on ionisation measurement in gases and semiconductors
Loading...
Searching...
No Matches
Medium.cc
Go to the documentation of this file.
1#include <algorithm>
2#include <cmath>
3#include <iomanip>
4#include <iostream>
5#include <utility>
6
9#include "Garfield/Medium.hh"
10#include "Garfield/Numerics.hh"
11#include "Garfield/Random.hh"
13
14namespace {
15
16void PrintNotImplemented(const std::string& cls, const std::string& fcn) {
17 std::cerr << cls << "::" << fcn << ": Function is not implemented.\n";
18}
19
20void PrintOutOfRange(const std::string& cls, const std::string& fcn,
21 const size_t i, const size_t j, const size_t k) {
22 std::cerr << cls << "::" << fcn << ": Index (" << i << ", " << j << ", " << k
23 << ") out of range.\n";
24}
25
26void PrintDataNotAvailable(const std::string& cls, const std::string& fcn) {
27 std::cerr << cls << "::" << fcn << ": Data not available.\n";
28}
29
30bool CheckFields(const std::vector<double>& fields, const std::string& hdr,
31 const std::string& lbl) {
32 if (fields.empty()) {
33 std::cerr << hdr << ": Number of " << lbl << " must be > 0.\n";
34 return false;
35 }
36
37 // Make sure the values are not negative.
38 if (fields.front() < 0.) {
39 std::cerr << hdr << ": " << lbl << " must be >= 0.\n";
40 return false;
41 }
42
43 const size_t nEntries = fields.size();
44 // Make sure the values are in strictly monotonic, ascending order.
45 if (nEntries > 1) {
46 for (size_t i = 1; i < nEntries; ++i) {
47 if (fields[i] <= fields[i - 1]) {
48 std::cerr << hdr << ": " << lbl << " are not in ascending order.\n";
49 return false;
50 }
51 }
52 }
53 return true;
54}
55}
56
57namespace Garfield {
58
59int Medium::m_idCounter = -1;
60
62 // Initialise the tables.
63 m_bFields.assign(1, 0.);
64 m_bAngles.assign(1, HalfPi);
65
66 // Set the default grid.
67 SetFieldGrid(100., 100000., 20, true, 0., 0., 1, HalfPi, HalfPi, 1);
68}
69
71
72void Medium::SetTemperature(const double t) {
73 if (t <= 0.) {
74 std::cerr << m_className << "::SetTemperature:\n"
75 << " Temperature [K] must be greater than zero.\n";
76 return;
77 }
78 m_temperature = t;
79 m_isChanged = true;
80}
81
82void Medium::SetPressure(const double p) {
83 if (p <= 0.) {
84 std::cerr << m_className << "::SetPressure:\n"
85 << " Pressure [Torr] must be greater than zero.\n";
86 return;
87 }
88 m_pressure = p;
89 m_isChanged = true;
90}
91
92void Medium::SetDielectricConstant(const double eps) {
93 if (eps < 1.) {
94 std::cerr << m_className << "::SetDielectricConstant:\n"
95 << " Dielectric constant must be >= 1.\n";
96 return;
97 }
98 m_epsilon = eps;
99 m_isChanged = true;
100}
101
103 return m_density * AtomicMassUnit * m_a;
104}
105
106void Medium::GetComponent(const unsigned int i, std::string& label, double& f) {
107 if (i >= m_nComponents) {
108 std::cerr << m_className << "::GetComponent: Index out of range.\n";
109 }
110
111 label = m_name;
112 f = 1.;
113}
114
115void Medium::SetAtomicNumber(const double z) {
116 if (z < 1.) {
117 std::cerr << m_className << "::SetAtomicNumber:\n"
118 << " Atomic number must be >= 1.\n";
119 return;
120 }
121 m_z = z;
122 m_isChanged = true;
123}
124
125void Medium::SetAtomicWeight(const double a) {
126 if (a <= 0.) {
127 std::cerr << m_className << "::SetAtomicWeight:\n"
128 << " Atomic weight must be greater than zero.\n";
129 return;
130 }
131 m_a = a;
132 m_isChanged = true;
133}
134
135void Medium::SetNumberDensity(const double n) {
136 if (n <= 0.) {
137 std::cerr << m_className << "::SetNumberDensity:\n"
138 << " Density [cm-3] must be greater than zero.\n";
139 return;
140 }
141 m_density = n;
142 m_isChanged = true;
143}
144
145void Medium::SetMassDensity(const double rho) {
146 if (rho <= 0.) {
147 std::cerr << m_className << "::SetMassDensity:\n"
148 << " Density [g/cm3] must be greater than zero.\n";
149 return;
150 }
151
152 if (m_a <= 0.) {
153 std::cerr << m_className << "::SetMassDensity:\n"
154 << " Atomic weight is not defined.\n";
155 return;
156 }
157 m_density = rho / (AtomicMassUnit * m_a);
158 m_isChanged = true;
159}
160
161void Medium::PlotVelocity(const std::string& opt, TPad* pad) {
162 ViewMedium view;
163 view.SetMedium(this);
164 if (pad) view.SetCanvas(pad);
165 view.PlotVelocity(opt, 'e');
166}
167
168void Medium::PlotDiffusion(const std::string& opt, TPad* pad) {
169 ViewMedium view;
170 view.SetMedium(this);
171 if (pad) view.SetCanvas(pad);
172 view.PlotDiffusion(opt, 'e');
173}
174
175void Medium::PlotTownsend(const std::string& opt, TPad* pad) {
176 ViewMedium view;
177 view.SetMedium(this);
178 if (pad) view.SetCanvas(pad);
179 view.PlotTownsend(opt, 'e');
180}
181
182void Medium::PlotAttachment(const std::string& opt, TPad* pad) {
183 ViewMedium view;
184 view.SetMedium(this);
185 if (pad) view.SetCanvas(pad);
186 view.PlotAttachment(opt, 'e');
187}
188
189void Medium::PlotAlphaEta(const std::string& opt, TPad* pad) {
190 ViewMedium view;
191 view.SetMedium(this);
192 if (pad) view.SetCanvas(pad);
193 view.PlotAlphaEta(opt, 'e');
194}
195
196bool Medium::Velocity(const double ex, const double ey, const double ez,
197 const double bx, const double by, const double bz,
198 const std::vector<std::vector<std::vector<double> > >& velE,
199 const std::vector<std::vector<std::vector<double> > >& velB,
200 const std::vector<std::vector<std::vector<double> > >& velX,
201 const double q, double& vx, double& vy, double& vz) const {
202
203 vx = vy = vz = 0.;
204 // Make sure there is at least a table of velocities along E.
205 if (velE.empty()) return false;
206
207 // Compute the magnitude of the electric field.
208 const double e = sqrt(ex * ex + ey * ey + ez * ez);
209 const double e0 = ScaleElectricField(e);
210 if (e < Small || e0 < Small) return false;
211
212 // Compute the magnitude of the magnetic field.
213 const double b = sqrt(bx * bx + by * by + bz * bz);
214 // Compute the angle between B field and E field.
215 const double ebang = GetAngle(ex, ey, ez, bx, by, bz, e, b);
216
217 // Calculate the velocity along E.
218 double ve = 0.;
219 if (!Interpolate(e0, b, ebang, velE, ve, m_intpVel, m_extrVel)) {
220 std::cerr << m_className << "::Velocity: Interpolation along E failed.\n";
221 return false;
222 }
223 if (b < Small) {
224 // No magnetic field.
225 const double mu = q * ve / e;
226 vx = mu * ex;
227 vy = mu * ey;
228 vz = mu * ez;
229 return true;
230 } else if (velX.empty() || velB.empty() ||
231 (m_bFields.size() == 1 && fabs(m_bFields[0]) < Small)) {
232 // Magnetic field, velocities along ExB, Bt not available.
233 Langevin(ex, ey, ez, bx, by, bz, q * ve / e, vx, vy, vz);
234 return true;
235 }
236
237 // Magnetic field, velocities along ExB and Bt available.
238 // Compute unit vectors along E, E x B and Bt.
239 double ue[3] = {ex / e, ey / e, ez / e};
240 double uexb[3] = {ey * bz - ez * by, ez * bx - ex * bz, ex * by - ey * bx};
241 const double exb =
242 sqrt(uexb[0] * uexb[0] + uexb[1] * uexb[1] + uexb[2] * uexb[2]);
243 if (exb > 0.) {
244 uexb[0] /= exb;
245 uexb[1] /= exb;
246 uexb[2] /= exb;
247 } else {
248 uexb[0] = ue[0];
249 uexb[1] = ue[1];
250 uexb[2] = ue[2];
251 }
252
253 double ubt[3] = {uexb[1] * ez - uexb[2] * ey,
254 uexb[2] * ex - uexb[0] * ez,
255 uexb[0] * ey - uexb[1] * ex};
256 const double bt = sqrt(ubt[0] * ubt[0] + ubt[1] * ubt[1] + ubt[2] * ubt[2]);
257 if (bt > 0.) {
258 ubt[0] /= bt;
259 ubt[1] /= bt;
260 ubt[2] /= bt;
261 } else {
262 ubt[0] = ue[0];
263 ubt[1] = ue[1];
264 ubt[2] = ue[2];
265 }
266
267 if (m_debug) {
268 std::cout << m_className << "::Velocity:\n";
269 std::printf(" unit vector along E: (%15.5f, %15.5f, %15.5f)\n",
270 ue[0], ue[1], ue[2]);
271 std::printf(" unit vector along E x B: (%15.5f, %15.5f, %15.5f)\n",
272 uexb[0], uexb[1], uexb[2]);
273 std::printf(" unit vector along Bt: (%15.5f, %15.5f, %15.5f)\n",
274 ubt[0], ubt[1], ubt[2]);
275 }
276
277 // Calculate the velocities in all directions.
278 double vexb = 0.;
279 if (!Interpolate(e0, b, ebang, velX, vexb, m_intpVel, m_extrVel)) {
280 std::cerr << m_className << "::Velocity: Interpolation along ExB failed.\n";
281 return false;
282 }
283 vexb *= q;
284 double vbt = 0.;
285 if (!Interpolate(e0, b, ebang, velB, vbt, m_intpVel, m_extrVel)) {
286 std::cerr << m_className << "::Velocity: Interpolation along Bt failed.\n";
287 return false;
288 }
289 if (ex * bx + ey * by + ez * bz > 0.) {
290 vbt = fabs(vbt);
291 } else {
292 vbt = -fabs(vbt);
293 }
294 vbt *= q * q;
295 vx = q * (ve * ue[0] + vbt * ubt[0] + vexb * uexb[0]);
296 vy = q * (ve * ue[1] + vbt * ubt[1] + vexb * uexb[1]);
297 vz = q * (ve * ue[2] + vbt * ubt[2] + vexb * uexb[2]);
298 return true;
299}
300
301void Medium::Langevin(const double ex, const double ey, const double ez,
302 double bx, double by, double bz, const double mu,
303 double& vx, double& vy, double& vz) {
304
305 bx *= Tesla2Internal;
306 by *= Tesla2Internal;
307 bz *= Tesla2Internal;
308 const double b2 = bx * bx + by * by + bz * bz;
309 const double mu2 = mu * mu;
310 const double eb = bx * ex + by * ey + bz * ez;
311 const double f = mu / (1. + mu2 * b2);
312 vx = f * (ex + mu * (ey * bz - ez * by) + mu2 * bx * eb);
313 vy = f * (ey + mu * (ez * bx - ex * bz) + mu2 * by * eb);
314 vz = f * (ez + mu * (ex * by - ey * bx) + mu2 * bz * eb);
315}
316
317void Medium::Langevin(const double ex, const double ey, const double ez,
318 double bx, double by, double bz,
319 const double mu, const double muH,
320 double& vx, double& vy, double& vz) {
321
322 bx *= Tesla2Internal;
323 by *= Tesla2Internal;
324 bz *= Tesla2Internal;
325 const double b2 = bx * bx + by * by + bz * bz;
326 const double mu2 = muH * muH;
327 const double f = mu / (1. + mu2 * b2);
328 const double eb = bx * ex + by * ey + bz * ez;
329 vx = f * (ex + muH * (ey * bz - ez * by) + mu2 * bx * eb);
330 vy = f * (ey + muH * (ez * bx - ex * bz) + mu2 * by * eb);
331 vz = f * (ez + muH * (ex * by - ey * bx) + mu2 * bz * eb);
332}
333
334bool Medium::Diffusion(const double ex, const double ey, const double ez,
335 const double bx, const double by, const double bz,
336 const std::vector<std::vector<std::vector<double> > >& difL,
337 const std::vector<std::vector<std::vector<double> > >& difT,
338 double& dl, double& dt) const {
339
340 dl = dt = 0.;
341 // Compute the magnitude of the electric field.
342 const double e = sqrt(ex * ex + ey * ey + ez * ez);
343 const double e0 = ScaleElectricField(e);
344 if (e < Small || e0 < Small) return true;
345
346 // Compute the magnitude of the magnetic field.
347 const double b = m_tab2d ? sqrt(bx * bx + by * by + bz * bz) : 0.;
348 // Compute the angle between B field and E field.
349 const double ebang = m_tab2d ? GetAngle(ex, ey, ez, bx, by, bz, e, b) : 0.;
350
351 // Interpolate.
352 if (!difL.empty()) {
353 if (!Interpolate(e0, b, ebang, difL, dl, m_intpDif, m_extrDif)) dl = 0.;
354 }
355 if (!difT.empty()) {
356 if (!Interpolate(e0, b, ebang, difT, dt, m_intpDif, m_extrDif)) dt = 0.;
357 }
358
359 // If no data available, calculate
360 // the diffusion coefficients using the Einstein relation
361 if (difL.empty() || difT.empty()) {
362 const double d = sqrt(2. * BoltzmannConstant * m_temperature / e);
363 if (difL.empty()) dl = d;
364 if (difT.empty()) dt = d;
365 }
366 // Verify values and apply scaling.
367 dl = ScaleDiffusion(std::max(dl, 0.));
368 dt = ScaleDiffusion(std::max(dt, 0.));
369 return true;
370}
371
372bool Medium::Diffusion(const double ex, const double ey, const double ez,
373 const double bx, const double by, const double bz,
374 const std::vector<std::vector<std::vector<std::vector<double> > > >& diff,
375 double cov[3][3]) const {
376
377 // Initialise the tensor.
378 cov[0][0] = cov[0][1] = cov[0][2] = 0.;
379 cov[1][0] = cov[1][1] = cov[1][2] = 0.;
380 cov[2][0] = cov[2][1] = cov[2][2] = 0.;
381
382 if (diff.empty()) return false;
383
384 // Compute the magnitude of the electric field.
385 const double e = sqrt(ex * ex + ey * ey + ez * ez);
386 const double e0 = ScaleElectricField(e);
387 if (e < Small || e0 < Small) return true;
388
389 // Compute the magnitude of the magnetic field.
390 const double b = m_tab2d ? sqrt(bx * bx + by * by + bz * bz) : 0.;
391 // Compute the angle between B field and E field.
392 const double ebang = m_tab2d ? GetAngle(ex, ey, ez, bx, by, bz, e, b) : 0.;
393
394 for (int j = 0; j < 6; ++j) {
395 // Interpolate.
396 double y = 0.;
397 if (!Interpolate(e0, b, ebang, diff[j], y, m_intpDif, m_extrDif)) y = 0.;
398 // Apply scaling.
400 if (j < 3) {
401 cov[j][j] = y;
402 } else if (j == 3) {
403 cov[0][1] = cov[1][0] = y;
404 } else if (j == 4) {
405 cov[0][2] = cov[2][0] = y;
406 } else if (j == 5) {
407 cov[1][2] = cov[2][1] = y;
408 }
409 }
410 return true;
411}
412
413bool Medium::Alpha(const double ex, const double ey, const double ez,
414 const double bx, const double by, const double bz,
415 const std::vector<std::vector<std::vector<double> > >& tab,
416 unsigned int intp, const unsigned int thr,
417 const std::pair<unsigned int, unsigned int>& extr,
418 double& alpha) const {
419
420 alpha = 0.;
421 if (tab.empty()) return false;
422
423 // Compute the magnitude of the electric field.
424 const double e = sqrt(ex * ex + ey * ey + ez * ez);
425 const double e0 = ScaleElectricField(e);
426 if (e < Small || e0 < Small) return true;
427
428 // Compute the magnitude of the magnetic field.
429 const double b = m_tab2d ? sqrt(bx * bx + by * by + bz * bz) : 0.;
430 // Compute the angle between B field and E field.
431 const double ebang = m_tab2d ? GetAngle(ex, ey, ez, bx, by, bz, e, b) : 0.;
432
433 // Interpolate.
434 if (e0 < m_eFields[thr]) intp = 1;
435 if (!Interpolate(e0, b, ebang, tab, alpha, intp, extr)) alpha = -30.;
436 if (alpha < -20.) {
437 alpha = 0.;
438 } else {
439 alpha = exp(alpha);
440 }
441 return true;
442}
443
444bool Medium::ElectronVelocity(const double ex, const double ey, const double ez,
445 const double bx, const double by, const double bz,
446 double& vx, double& vy, double& vz) {
447
448 return Velocity(ex, ey, ez, bx, by, bz, m_eVelE, m_eVelB, m_eVelX, -1.,
449 vx, vy, vz);
450}
451
452bool Medium::ElectronDiffusion(const double ex, const double ey,
453 const double ez, const double bx,
454 const double by, const double bz, double& dl,
455 double& dt) {
456
457 return Diffusion(ex, ey, ez, bx, by, bz, m_eDifL, m_eDifT, dl, dt);
458}
459
460bool Medium::ElectronDiffusion(const double ex, const double ey,
461 const double ez, const double bx,
462 const double by, const double bz,
463 double cov[3][3]) {
464
465 return Diffusion(ex, ey, ez, bx, by, bz, m_eDifM, cov);
466}
467
468bool Medium::ElectronTownsend(const double ex, const double ey, const double ez,
469 const double bx, const double by, const double bz,
470 double& alpha) {
471
472 if (!Alpha(ex, ey, ez, bx, by, bz, m_eAlp, m_intpAlp, m_eThrAlp, m_extrAlp,
473 alpha)) {
474 return false;
475 }
476 // Apply scaling.
477 alpha = ScaleTownsend(alpha);
478 return true;
479}
480
481bool Medium::ElectronAttachment(const double ex, const double ey,
482 const double ez, const double bx,
483 const double by, const double bz, double& eta) {
484
485 if (!Alpha(ex, ey, ez, bx, by, bz, m_eAtt, m_intpAtt, m_eThrAtt, m_extrAtt,
486 eta)) {
487 return false;
488 }
489 // Apply scaling.
490 eta = ScaleAttachment(eta);
491 return true;
492}
493
494bool Medium::ElectronLorentzAngle(const double ex, const double ey,
495 const double ez, const double bx,
496 const double by, const double bz,
497 double& lor) {
498 lor = 0.;
499 if (m_eLor.empty()) return false;
500
501 // Compute the magnitude of the electric field.
502 const double e = sqrt(ex * ex + ey * ey + ez * ez);
503 const double e0 = ScaleElectricField(e);
504 if (e < Small || e0 < Small) return true;
505
506 // Compute the magnitude of the magnetic field.
507 const double b = m_tab2d ? sqrt(bx * bx + by * by + bz * bz) : 0.;
508 // Compute the angle between B field and E field.
509 const double ebang = m_tab2d ? GetAngle(ex, ey, ez, bx, by, bz, e, b) : 0.;
510
511 // Interpolate.
512 if (!Interpolate(e0, b, ebang, m_eLor, lor, m_intpLor, m_extrLor)) lor = 0.;
513 // Apply scaling.
514 lor = ScaleLorentzAngle(lor);
515 return true;
516}
517
519 if (m_eVelE.empty()) return -1.;
520 return m_eVelE[0][0][0] / UnScaleElectricField(m_eFields[0]);
521}
522
523double Medium::GetElectronEnergy(const double px, const double py,
524 const double pz, double& vx, double& vy,
525 double& vz, const int band) {
526 if (band > 0) {
527 std::cerr << m_className << "::GetElectronEnergy:\n";
528 std::cerr << " Unknown band index.\n";
529 }
530
531 vx = SpeedOfLight * px / ElectronMass;
532 vy = SpeedOfLight * py / ElectronMass;
533 vz = SpeedOfLight * pz / ElectronMass;
534
535 return 0.5 * (px * px + py * py + pz * pz) / ElectronMass;
536}
537
538void Medium::GetElectronMomentum(const double e, double& px, double& py,
539 double& pz, int& band) {
540 const double p = sqrt(2. * ElectronMass * e) / SpeedOfLight;
541 RndmDirection(px, py, pz, p);
542 band = -1;
543}
544
545double Medium::GetElectronNullCollisionRate(const int /*band*/) {
546 if (m_debug) PrintNotImplemented(m_className, "GetElectronNullCollisionRate");
547 return 0.;
548}
549
550double Medium::GetElectronCollisionRate(const double /*e*/,
551 const int /*band*/) {
552 if (m_debug) PrintNotImplemented(m_className, "GetElectronCollisionRate");
553 return 0.;
554}
555
556bool Medium::ElectronCollision(const double e, int& type, int& level,
557 double& e1, double& dx, double& dy, double& dz,
558 std::vector<std::pair<Particle, double> >& /*secondaries*/,
559 int& ndxc, int& band) {
560 type = level = -1;
561 e1 = e;
562 ndxc = band = 0;
563 RndmDirection(dx, dy, dz);
564
565 if (m_debug) PrintNotImplemented(m_className, "GetElectronCollision");
566 return false;
567}
568
569bool Medium::GetDeexcitationProduct(const unsigned int /*i*/, double& t,
570 double& s, int& type,
571 double& energy) const {
572 if (m_debug) PrintNotImplemented(m_className, "GetDeexcitationProduct");
573 t = s = energy = 0.;
574 type = 0;
575 return false;
576}
577
578bool Medium::HoleVelocity(const double ex, const double ey, const double ez,
579 const double bx, const double by, const double bz,
580 double& vx, double& vy, double& vz) {
581
582 return Velocity(ex, ey, ez, bx, by, bz, m_hVelE, m_hVelB, m_hVelX, +1.,
583 vx, vy, vz);
584}
585
586bool Medium::HoleDiffusion(const double ex, const double ey, const double ez,
587 const double bx, const double by, const double bz,
588 double& dl, double& dt) {
589 return Diffusion(ex, ey, ez, bx, by, bz, m_hDifL, m_hDifT, dl, dt);
590}
591
592bool Medium::HoleDiffusion(const double ex, const double ey, const double ez,
593 const double bx, const double by, const double bz,
594 double cov[3][3]) {
595
596 return Diffusion(ex, ey, ez, bx, by, bz, m_hDifM, cov);
597}
598
599bool Medium::HoleTownsend(const double ex, const double ey, const double ez,
600 const double bx, const double by, const double bz,
601 double& alpha) {
602
603 if (!Alpha(ex, ey, ez, bx, by, bz, m_hAlp, m_intpAlp, m_hThrAlp, m_extrAlp,
604 alpha)) {
605 return false;
606 }
607 // Apply scaling.
608 alpha = ScaleTownsend(alpha);
609 return true;
610}
611
612bool Medium::HoleAttachment(const double ex, const double ey, const double ez,
613 const double bx, const double by, const double bz,
614 double& eta) {
615
616 if (!Alpha(ex, ey, ez, bx, by, bz, m_hAtt, m_intpAtt, m_hThrAtt, m_extrAtt,
617 eta)) {
618 return false;
619 }
620 // Apply scaling.
621 eta = ScaleAttachment(eta);
622 return true;
623}
624
626 if (m_hVelE.empty()) return -1.;
627 return m_hVelE[0][0][0] / UnScaleElectricField(m_eFields[0]);
628}
629
630bool Medium::IonVelocity(const double ex, const double ey, const double ez,
631 const double bx, const double by, const double bz,
632 double& vx, double& vy, double& vz) {
633 vx = vy = vz = 0.;
634 if (m_iMob.empty()) return false;
635 // Compute the magnitude of the electric field.
636 const double e = sqrt(ex * ex + ey * ey + ez * ez);
637 const double e0 = ScaleElectricField(e);
638 if (e < Small || e0 < Small) return true;
639 // Compute the magnitude of the electric field.
640 const double b = sqrt(bx * bx + by * by + bz * bz);
641
642 // Compute the angle between B field and E field.
643 const double ebang = m_tab2d ? GetAngle(ex, ey, ez, bx, by, bz, e, b) : 0.;
644 double mu = 0.;
645 if (!Interpolate(e0, b, ebang, m_iMob, mu, m_intpMob, m_extrMob)) mu = 0.;
646
647 constexpr double q = 1.;
648 mu *= q;
649 if (b < Small) {
650 vx = mu * ex;
651 vy = mu * ey;
652 vz = mu * ez;
653 } else {
654 Langevin(ex, ey, ez, bx, by, bz, mu, vx, vy, vz);
655 }
656
657 return true;
658}
659
660bool Medium::IonDiffusion(const double ex, const double ey, const double ez,
661 const double bx, const double by, const double bz,
662 double& dl, double& dt) {
663
664 return Diffusion(ex, ey, ez, bx, by, bz, m_iDifL, m_iDifT, dl, dt);
665}
666
667bool Medium::IonDissociation(const double ex, const double ey, const double ez,
668 const double bx, const double by, const double bz,
669 double& diss) {
670
671 if (!Alpha(ex, ey, ez, bx, by, bz, m_iDis, m_intpDis, m_iThrDis, m_extrDis,
672 diss)) {
673 return false;
674 }
675 // Apply scaling.
676 diss = ScaleDissociation(diss);
677 return true;
678}
679
681 return m_iMob.empty() ? -1. : m_iMob[0][0][0];
682}
683
685 const double ex, const double ey, const double ez,
686 const double bx, const double by, const double bz,
687 double& vx, double& vy, double& vz) {
688 vx = vy = vz = 0.;
689 if (m_iMob.empty() && m_nMob.empty()) return false;
690
691 // Compute the magnitude of the electric field.
692 const double e = sqrt(ex * ex + ey * ey + ez * ez);
693 const double e0 = ScaleElectricField(e);
694 if (e < Small || e0 < Small) return true;
695 // Compute the magnitude of the electric field.
696 const double b = sqrt(bx * bx + by * by + bz * bz);
697
698 // Compute the angle between B field and E field.
699 const double ebang = m_tab2d ? GetAngle(ex, ey, ez, bx, by, bz, e, b) : 0.;
700 double mu = 0.;
701 if (m_nMob.empty()) {
702 if (!Interpolate(e0, b, ebang, m_iMob, mu, m_intpMob, m_extrMob)) mu = 0.;
703 } else {
704 if (!Interpolate(e0, b, ebang, m_nMob, mu, m_intpMob, m_extrMob)) mu = 0.;
705 }
706 constexpr double q = -1.;
707 mu *= q;
708 if (b < Small) {
709 vx = mu * ex;
710 vy = mu * ey;
711 vz = mu * ez;
712 } else {
713 Langevin(ex, ey, ez, bx, by, bz, mu, vx, vy, vz);
714 }
715 return true;
716}
717
719 return m_nMob.empty() ? IonMobility() : m_nMob[0][0][0];
720}
721
722bool Medium::GetOpticalDataRange(double& emin, double& emax,
723 const unsigned int i) {
724 if (i >= m_nComponents) {
725 std::cerr << m_className << "::GetOpticalDataRange: Index out of range.\n";
726 return false;
727 }
728
729 if (m_debug) PrintNotImplemented(m_className, "GetOpticalDataRange");
730 emin = emax = 0.;
731 return false;
732}
733
734bool Medium::GetDielectricFunction(const double e, double& eps1, double& eps2,
735 const unsigned int i) {
736 if (i >= m_nComponents) {
737 std::cerr << m_className << "::GetDielectricFunction: Index out of range.\n";
738 return false;
739 }
740
741 if (e < 0.) {
742 std::cerr << m_className << "::GetDielectricFunction: Energy must be > 0.\n";
743 return false;
744 }
745
746 if (m_debug) PrintNotImplemented(m_className, "GetDielectricFunction");
747 eps1 = 1.;
748 eps2 = 0.;
749 return false;
750}
751
752bool Medium::GetPhotoAbsorptionCrossSection(const double e, double& sigma,
753 const unsigned int i) {
754 if (i >= m_nComponents) {
755 std::cerr << m_className << "::GetPhotoAbsorptionCrossSection:\n";
756 std::cerr << " Component " << i << " does not exist.\n";
757 return false;
758 }
759
760 if (e < 0.) {
761 std::cerr << m_className << "::GetPhotoAbsorptionCrossSection:\n";
762 std::cerr << " Energy must be > 0.\n";
763 return false;
764 }
765
766 if (m_debug) {
767 PrintNotImplemented(m_className, "GetPhotoAbsorptionCrossSection");
768 }
769 sigma = 0.;
770 return false;
771}
772
773double Medium::GetPhotonCollisionRate(const double e) {
774 double sigma = 0.;
775 if (!GetPhotoAbsorptionCrossSection(e, sigma)) return 0.;
776
777 return sigma * m_density * SpeedOfLight;
778}
779
780bool Medium::GetPhotonCollision(const double e, int& type, int& level,
781 double& e1, double& ctheta, int& nsec,
782 double& esec) {
783 type = level = -1;
784 e1 = e;
785 ctheta = 1.;
786 nsec = 0;
787 esec = 0.;
788 return false;
789}
790
791void Medium::SetFieldGrid(double emin, double emax, const size_t ne, bool logE,
792 double bmin, double bmax, const size_t nb,
793 double amin, double amax, const size_t na) {
794 // Check if the requested E-field range makes sense.
795 if (ne <= 0) {
796 std::cerr << m_className << "::SetFieldGrid:\n"
797 << " Number of E-fields must be > 0.\n";
798 return;
799 }
800
801 if (emin < 0. || emax < 0.) {
802 std::cerr << m_className << "::SetFieldGrid:\n"
803 << " Electric fields must be positive.\n";
804 return;
805 }
806
807 if (emax < emin) {
808 std::cerr << m_className << "::SetFieldGrid: Swapping min./max. E-field.\n";
809 std::swap(emin, emax);
810 }
811
812 double estep = 0.;
813 if (logE) {
814 // Logarithmic scale
815 if (emin < Small) {
816 std::cerr << m_className << "::SetFieldGrid:\n"
817 << " Min. E-field must be non-zero for log. scale.\n";
818 return;
819 }
820 if (ne == 1) {
821 std::cerr << m_className << "::SetFieldGrid:\n"
822 << " Number of E-fields must be > 1 for log. scale.\n";
823 return;
824 }
825 estep = pow(emax / emin, 1. / (ne - 1.));
826 } else {
827 // Linear scale
828 if (ne > 1) estep = (emax - emin) / (ne - 1.);
829 }
830
831 // Check if the requested B-field range makes sense.
832 if (nb <= 0) {
833 std::cerr << m_className << "::SetFieldGrid:\n"
834 << " Number of B-fields must be > 0.\n";
835 return;
836 }
837 if (bmax < 0. || bmin < 0.) {
838 std::cerr << m_className << "::SetFieldGrid:\n"
839 << " Magnetic fields must be positive.\n";
840 return;
841 }
842 if (bmax < bmin) {
843 std::cerr << m_className << "::SetFieldGrid: Swapping min./max. B-field.\n";
844 std::swap(bmin, bmax);
845 }
846
847 const double bstep = nb > 1 ? (bmax - bmin) / (nb - 1.) : 0.;
848
849 // Check if the requested angular range makes sense.
850 if (na <= 0) {
851 std::cerr << m_className << "::SetFieldGrid:\n"
852 << " Number of angles must be > 0.\n";
853 return;
854 }
855 if (amax < 0. || amin < 0.) {
856 std::cerr << m_className << "::SetFieldGrid:"
857 << " Angles must be positive.\n";
858 return;
859 }
860 if (amax < amin) {
861 std::cerr << m_className << "::SetFieldGrid: Swapping min./max. angle.\n";
862 std::swap(amin, amax);
863 }
864 const double astep = na > 1 ? (amax - amin) / (na - 1.) : 0;
865
866 // Setup the field grids.
867 std::vector<double> eFields(ne);
868 std::vector<double> bFields(nb);
869 std::vector<double> bAngles(na);
870 for (size_t i = 0; i < ne; ++i) {
871 eFields[i] = logE ? emin * pow(estep, i) : emin + i * estep;
872 }
873 for (size_t i = 0; i < nb; ++i) {
874 bFields[i] = bmin + i * bstep;
875 }
876 for (size_t i = 0; i < na; ++i) {
877 bAngles[i] = amin + i * astep;
878 }
879 SetFieldGrid(eFields, bFields, bAngles);
880}
881
882void Medium::SetFieldGrid(const std::vector<double>& efields,
883 const std::vector<double>& bfields,
884 const std::vector<double>& angles) {
885 const std::string hdr = m_className + "::SetFieldGrid";
886 if (!CheckFields(efields, hdr, "E-fields")) return;
887 if (!CheckFields(bfields, hdr, "B-fields")) return;
888 if (!CheckFields(angles, hdr, "angles")) return;
889
890 if (m_debug) {
891 std::cout << m_className << "::SetFieldGrid:\n E-fields:\n";
892 for (const auto efield : efields) std::cout << " " << efield << "\n";
893 std::cout << " B-fields:\n";
894 for (const auto bfield : bfields) std::cout << " " << bfield << "\n";
895 std::cout << " Angles:\n";
896 for (const auto angle : angles) std::cout << " " << angle << "\n";
897 }
898
899 // Clone the existing tables.
900 // Electrons
901 Clone(m_eVelE, efields, bfields, angles, m_intpVel, m_extrVel, 0.,
902 "electron velocity along E");
903 Clone(m_eVelB, efields, bfields, angles, m_intpVel, m_extrVel, 0.,
904 "electron velocity along Bt");
905 Clone(m_eVelX, efields, bfields, angles, m_intpVel, m_extrVel, 0.,
906 "electron velocity along ExB");
907 Clone(m_eDifL, efields, bfields, angles, m_intpDif, m_extrDif, 0.,
908 "electron longitudinal diffusion");
909 Clone(m_eDifT, efields, bfields, angles, m_intpDif, m_extrDif, 0.,
910 "electron transverse diffusion");
911 Clone(m_eAlp, efields, bfields, angles, m_intpAlp, m_extrAlp, -30.,
912 "electron Townsend coefficient");
913 Clone(m_eAtt, efields, bfields, angles, m_intpAtt, m_extrAtt, -30.,
914 "electron attachment coefficient");
915 Clone(m_eLor, efields, bfields, angles, m_intpLor, m_extrLor, 0.,
916 "electron Lorentz angle");
917 if (!m_eDifM.empty()) {
918 Clone(m_eDifM, 6, efields, bfields, angles, m_intpDif, m_extrDif, 0.,
919 "electron diffusion tensor");
920 }
921
922 // Holes
923 Clone(m_hVelE, efields, bfields, angles, m_intpVel, m_extrVel, 0.,
924 "hole velocity along E");
925 Clone(m_hVelB, efields, bfields, angles, m_intpVel, m_extrVel, 0.,
926 "hole velocity along Bt");
927 Clone(m_hVelX, efields, bfields, angles, m_intpVel, m_extrVel, 0.,
928 "hole velocity along ExB");
929 Clone(m_hDifL, efields, bfields, angles, m_intpDif, m_extrDif, 0.,
930 "hole longitudinal diffusion");
931 Clone(m_hDifT, efields, bfields, angles, m_intpDif, m_extrDif, 0.,
932 "hole transverse diffusion");
933 Clone(m_hAlp, efields, bfields, angles, m_intpAlp, m_extrAlp, -30.,
934 "hole Townsend coefficient");
935 Clone(m_hAtt, efields, bfields, angles, m_intpAtt, m_extrAtt, -30.,
936 "hole attachment coefficient");
937 if (!m_hDifM.empty()) {
938 Clone(m_hDifM, 6, efields, bfields, angles, m_intpDif, m_extrDif, 0.,
939 "hole diffusion tensor");
940 }
941
942 // Ions
943 Clone(m_iMob, efields, bfields, angles, m_intpMob, m_extrMob, 0.,
944 "ion mobility");
945 Clone(m_iDifL, efields, bfields, angles, m_intpDif, m_extrDif, 0.,
946 "ion longitudinal diffusion");
947 Clone(m_iDifT, efields, bfields, angles, m_intpDif, m_extrDif, 0.,
948 "ion transverse diffusion");
949 Clone(m_iDis, efields, bfields, angles, m_intpDis, m_extrDis, -30.,
950 "ion dissociation");
951
952 if (bfields.size() > 1 || angles.size() > 1) m_tab2d = true;
953 m_eFields = efields;
954 m_bFields = bfields;
955 m_bAngles = angles;
956}
957
958void Medium::GetFieldGrid(std::vector<double>& efields,
959 std::vector<double>& bfields,
960 std::vector<double>& angles) {
961 efields = m_eFields;
962 bfields = m_bFields;
963 angles = m_bAngles;
964}
965
966bool Medium::SetEntry(const size_t i, const size_t j, const size_t k,
967 const std::string& fcn,
968 std::vector<std::vector<std::vector<double> > >& tab,
969 const double val) {
970
971 if (i >= m_eFields.size() || j >= m_bFields.size() || k >= m_bAngles.size()) {
972 PrintOutOfRange(m_className, "Set" + fcn, i, j, k);
973 return false;
974 }
975 if (tab.empty()) {
976 Init(m_eFields.size(), m_bFields.size(), m_bAngles.size(), tab, val);
977 }
978 tab[k][j][i] = val;
979 return true;
980}
981
982bool Medium::GetEntry(const size_t i, const size_t j, const size_t k,
983 const std::string& fcn,
984 const std::vector<std::vector<std::vector<double> > >& tab,
985 double& val) const {
986 val = 0.;
987 if (i >= m_eFields.size() || j >= m_bFields.size() || k >= m_bAngles.size()) {
988 PrintOutOfRange(m_className, "Get" + fcn, i, j, k);
989 return false;
990 }
991 if (tab.empty()) {
992 if (m_debug) PrintDataNotAvailable(m_className, "Get" + fcn);
993 return false;
994 }
995 val = tab[k][j][i];
996 return true;
997}
998
1017
1018void Medium::Clone(std::vector<std::vector<std::vector<double> > >& tab,
1019 const std::vector<double>& efields,
1020 const std::vector<double>& bfields,
1021 const std::vector<double>& angles,
1022 const unsigned int intp,
1023 const std::pair<unsigned int, unsigned int>& extr,
1024 const double init, const std::string& lbl) {
1025 if (m_debug) {
1026 std::cout << m_className << "::Clone: Copying " << lbl << " to new grid.\n";
1027 }
1028
1029 if (tab.empty()) {
1030 if (m_debug) std::cout << m_className << "::Clone: Table is empty.\n";
1031 return;
1032 }
1033 // Get the dimensions of the new grid.
1034 const auto nE = efields.size();
1035 const auto nB = bfields.size();
1036 const auto nA = angles.size();
1037
1038 // Create a temporary table to store the values at the new grid points.
1039 std::vector<std::vector<std::vector<double> > > tabClone;
1040 Init(nE, nB, nA, tabClone, init);
1041
1042 // Fill the temporary table.
1043 for (size_t i = 0; i < nE; ++i) {
1044 const double e = efields[i];
1045 for (size_t j = 0; j < nB; ++j) {
1046 const double b = bfields[j];
1047 for (size_t k = 0; k < nA; ++k) {
1048 const double a = angles[k];
1049 double val = 0.;
1050 if (!Interpolate(e, b, a, tab, val, intp, extr)) {
1051 std::cerr << m_className << "::Clone:\n"
1052 << " Interpolation of " << lbl << " failed.\n"
1053 << " Cannot copy value to new grid at E = " << e
1054 << ", B = " << b << ", angle: " << a << "\n";
1055 continue;
1056 }
1057 tabClone[k][j][i] = val;
1058 }
1059 }
1060 }
1061 // Copy the values to the original table.
1062 tab.swap(tabClone);
1063}
1064
1066 std::vector<std::vector<std::vector<std::vector<double> > > >& tab,
1067 const size_t n, const std::vector<double>& efields,
1068 const std::vector<double>& bfields, const std::vector<double>& angles,
1069 const unsigned int intp, const std::pair<unsigned int, unsigned int>& extr,
1070 const double init, const std::string& lbl) {
1071 // If the table does not exist, do nothing.
1072 if (tab.empty()) return;
1073
1074 // Get the dimensions of the new grid.
1075 const auto nE = efields.size();
1076 const auto nB = bfields.size();
1077 const auto nA = angles.size();
1078
1079 // Create a temporary table to store the values at the new grid points.
1080 std::vector<std::vector<std::vector<std::vector<double> > > > tabClone;
1081 Init(nE, nB, nA, n, tabClone, init);
1082
1083 // Fill the temporary table.
1084 for (size_t l = 0; l < n; ++l) {
1085 for (size_t i = 0; i < nE; ++i) {
1086 const double e = efields[i];
1087 for (size_t j = 0; j < nB; ++j) {
1088 const double b = bfields[j];
1089 for (size_t k = 0; k < nA; ++k) {
1090 const double a = angles[k];
1091 double val = 0.;
1092 if (!Interpolate(e, b, a, tab[l], val, intp, extr)) {
1093 std::cerr << m_className << "::Clone:\n"
1094 << " Interpolation of " << lbl << " failed.\n"
1095 << " Cannot copy value to new grid at index " << l
1096 << ", E = " << e << ", B = " << b << ", angle: " << a
1097 << "\n";
1098 continue;
1099 }
1100 tabClone[l][k][j][i] = val;
1101 }
1102 }
1103 }
1104 }
1105 // Copy the values to the original table.
1106 tab.swap(tabClone);
1107}
1108
1109bool Medium::SetIonMobility(const size_t ie, const size_t ib,
1110 const size_t ia, const double mu) {
1111 // Check the index.
1112 if (ie >= m_eFields.size() || ib >= m_bFields.size() ||
1113 ia >= m_bAngles.size()) {
1114 PrintOutOfRange(m_className, "SetIonMobility", ie, ib, ia);
1115 return false;
1116 }
1117
1118 if (m_iMob.empty()) {
1119 std::cerr << m_className << "::SetIonMobility:\n"
1120 << " Ion mobility table not initialised.\n";
1121 return false;
1122 }
1123
1124 if (mu == 0.) {
1125 std::cerr << m_className << "::SetIonMobility: Zero value not allowed.\n";
1126 return false;
1127 }
1128
1129 m_iMob[ia][ib][ie] = mu;
1130 if (m_debug) {
1131 std::cout << m_className << "::SetIonMobility:\n Ion mobility at E = "
1132 << m_eFields[ie] << " V/cm, B = "
1133 << m_bFields[ib] << " T, angle "
1134 << m_bAngles[ia] << " set to " << mu << " cm2/(V ns).\n";
1135 }
1136 return true;
1137}
1138
1139bool Medium::SetIonMobility(const std::vector<double>& efields,
1140 const std::vector<double>& mobs,
1141 const bool negativeIons) {
1142 if (efields.size() != mobs.size()) {
1143 std::cerr << m_className << "::SetIonMobility:\n"
1144 << " E-field and mobility arrays have different sizes.\n";
1145 return false;
1146 }
1147
1148 if (negativeIons) {
1150 } else {
1152 }
1153 const auto nE = m_eFields.size();
1154 const auto nB = m_bFields.size();
1155 const auto nA = m_bAngles.size();
1156 if (negativeIons) {
1157 Init(nE, nB, nA, m_nMob, 0.);
1158 } else {
1159 Init(nE, nB, nA, m_iMob, 0.);
1160 }
1161 for (size_t i = 0; i < nE; ++i) {
1162 const double e = m_eFields[i];
1163 const double mu = Interpolate1D(e, mobs, efields, m_intpMob, m_extrMob);
1164 if (negativeIons) {
1165 m_nMob[0][0][i] = mu;
1166 } else {
1167 m_iMob[0][0][i] = mu;
1168 }
1169 }
1170 if (!m_tab2d) return true;
1171 for (size_t i = 0; i < nA; ++i) {
1172 for (size_t j = 0; j < nB; ++j) {
1173 for (size_t k = 0; k < nE; ++k) {
1174 if (negativeIons) {
1175 m_nMob[i][j][k] = m_nMob[0][0][k];
1176 } else {
1177 m_iMob[i][j][k] = m_iMob[0][0][k];
1178 }
1179 }
1180 }
1181 }
1182 return true;
1183}
1184
1185void Medium::SetExtrapolationMethodVelocity(const std::string& low,
1186 const std::string& high) {
1187 SetExtrapolationMethod(low, high, m_extrVel, "Velocity");
1188}
1189
1191 const std::string& high) {
1192 SetExtrapolationMethod(low, high, m_extrDif, "Diffusion");
1193}
1194
1195void Medium::SetExtrapolationMethodTownsend(const std::string& low,
1196 const std::string& high) {
1197 SetExtrapolationMethod(low, high, m_extrAlp, "Townsend");
1198}
1199
1201 const std::string& high) {
1202 SetExtrapolationMethod(low, high, m_extrAtt, "Attachment");
1203}
1204
1206 const std::string& high) {
1207 SetExtrapolationMethod(low, high, m_extrMob, "IonMobility");
1208}
1209
1211 const std::string& high) {
1212 SetExtrapolationMethod(low, high, m_extrDis, "IonDissociation");
1213}
1214
1215void Medium::SetExtrapolationMethod(const std::string& low,
1216 const std::string& high,
1217 std::pair<unsigned int, unsigned int>& extr,
1218 const std::string& fcn) {
1219 unsigned int i = 0;
1220 if (GetExtrapolationIndex(low, i)) {
1221 extr.first = i;
1222 } else {
1223 std::cerr << m_className << "::SetExtrapolationMethod" << fcn << ":\n"
1224 << " Unknown extrapolation method (" << low << ")\n";
1225 }
1226 unsigned int j = 0;
1227 if (GetExtrapolationIndex(high, j)) {
1228 extr.second = j;
1229 } else {
1230 std::cerr << m_className << "::SetExtrapolationMethod" << fcn << ":\n"
1231 << " Unknown extrapolation method (" << high << ")\n";
1232 }
1233}
1234
1235bool Medium::GetExtrapolationIndex(std::string str, unsigned int& nb) const {
1236 // Convert to upper-case.
1237 std::transform(str.begin(), str.end(), str.begin(), toupper);
1238
1239 if (str == "CONST" || str == "CONSTANT") {
1240 nb = 0;
1241 } else if (str == "LIN" || str == "LINEAR") {
1242 nb = 1;
1243 } else if (str == "EXP" || str == "EXPONENTIAL") {
1244 nb = 2;
1245 } else {
1246 return false;
1247 }
1248
1249 return true;
1250}
1251
1253 const std::vector<std::vector<std::vector<double> > >& tab) const {
1254
1255 if (tab.empty()) return 0;
1256 const auto nE = m_eFields.size();
1257 const auto nB = m_bFields.size();
1258 const auto nA = m_bAngles.size();
1259 for (size_t i = 0; i < nE; ++i) {
1260 bool below = false;
1261 for (size_t k = 0; k < nA; ++k) {
1262 for (size_t j = 0; j < nB; ++j) {
1263 if (tab[k][j][i] < -20.) {
1264 below = true;
1265 break;
1266 }
1267 }
1268 if (below) break;
1269 }
1270 if (below) continue;
1271 return i;
1272 }
1273 return nE - 1;
1274}
1275
1276void Medium::SetInterpolationMethodVelocity(const unsigned int intrp) {
1277 if (intrp > 0) m_intpVel = intrp;
1278}
1279
1280void Medium::SetInterpolationMethodDiffusion(const unsigned int intrp) {
1281 if (intrp > 0) m_intpDif = intrp;
1282}
1283
1284void Medium::SetInterpolationMethodTownsend(const unsigned int intrp) {
1285 if (intrp > 0) m_intpAlp = intrp;
1286}
1287
1288void Medium::SetInterpolationMethodAttachment(const unsigned int intrp) {
1289 if (intrp > 0) m_intpAtt = intrp;
1290}
1291
1292void Medium::SetInterpolationMethodIonMobility(const unsigned int intrp) {
1293 if (intrp > 0) m_intpMob = intrp;
1294}
1295
1297 if (intrp > 0) m_intpDis = intrp;
1298}
1299
1300double Medium::GetAngle(const double ex, const double ey, const double ez,
1301 const double bx, const double by, const double bz,
1302 const double emag, const double bmag) const {
1303 const double eb = emag * bmag;
1304 if (eb <= 0.) return m_bAngles[0];
1305 const double einb = fabs(ex * bx + ey * by + ez * bz);
1306 if (einb > 0.2 * eb) {
1307 double exb[3] = {ex * by - ey * bx, ex * bz - ez * bx, ez * by - ey * bz};
1308 return asin(
1309 std::min(1., sqrt(exb[0] * exb[0] + exb[1] * exb[1] + exb[2] * exb[2]) / eb));
1310 }
1311 return acos(std::min(1., einb / eb));
1312}
1313
1315 const double e, const double b, const double a,
1316 const std::vector<std::vector<std::vector<double> > >& table, double& y,
1317 const unsigned int intp,
1318 const std::pair<unsigned int, unsigned int>& extr) const {
1319 if (table.empty()) {
1320 y = 0.;
1321 return false; // TODO: true!
1322 }
1323
1324 if (m_tab2d) {
1326 m_bAngles.size(), m_bFields.size(), m_eFields.size(),
1327 a, b, e, y, intp);
1328 } else {
1329 y = Interpolate1D(e, table[0][0], m_eFields, intp, extr);
1330 }
1331 return true;
1332}
1333
1335 const double e, const std::vector<double>& table,
1336 const std::vector<double>& fields, const unsigned int intpMeth,
1337 const std::pair<unsigned int, unsigned int>& extr) const {
1338 // This function is a generalized version of the Fortran functions
1339 // GASVEL, GASVT1, GASVT2, GASLOR, GASMOB, GASDFT, and GASDFL
1340 // for the case of a 1D table. All variables are generic.
1341
1342 const auto nSizeTable = fields.size();
1343
1344 if (e < 0. || nSizeTable < 1) return 0.;
1345
1346 double result = 0.;
1347
1348 if (nSizeTable == 1) {
1349 // Only one point
1350 result = table[0];
1351 } else if (e < fields[0]) {
1352 // Extrapolation towards small fields
1353 if (fields[0] >= fields[1]) {
1354 if (m_debug) {
1355 std::cerr << m_className << "::Interpolate1D:\n";
1356 std::cerr << " First two field values coincide.\n";
1357 std::cerr << " No extrapolation to lower fields.\n";
1358 }
1359 result = table[0];
1360 } else if (extr.first == 1) {
1361 // Linear extrapolation
1362 const double extr4 = (table[1] - table[0]) / (fields[1] - fields[0]);
1363 const double extr3 = table[0] - extr4 * fields[0];
1364 result = extr3 + extr4 * e;
1365 } else if (extr.first == 2) {
1366 // Logarithmic extrapolation
1367 const double extr4 = log(table[1] / table[0]) / (fields[1] - fields[0]);
1368 const double extr3 = log(table[0] - extr4 * fields[0]);
1369 result = std::exp(std::min(50., extr3 + extr4 * e));
1370 } else {
1371 result = table[0];
1372 }
1373 } else if (e > fields[nSizeTable - 1]) {
1374 // Extrapolation towards large fields
1375 if (fields[nSizeTable - 1] <= fields[nSizeTable - 2]) {
1376 if (m_debug) {
1377 std::cerr << m_className << "::Interpolate1D:\n";
1378 std::cerr << " Last two field values coincide.\n";
1379 std::cerr << " No extrapolation to higher fields.\n";
1380 }
1381 result = table[nSizeTable - 1];
1382 } else if (extr.second == 1) {
1383 // Linear extrapolation
1384 const double extr2 = (table[nSizeTable - 1] - table[nSizeTable - 2]) /
1385 (fields[nSizeTable - 1] - fields[nSizeTable - 2]);
1386 const double extr1 =
1387 table[nSizeTable - 1] - extr2 * fields[nSizeTable - 1];
1388 result = extr1 + extr2 * e;
1389 } else if (extr.second == 2) {
1390 // Logarithmic extrapolation
1391 const double extr2 = log(table[nSizeTable - 1] / table[nSizeTable - 2]) /
1392 (fields[nSizeTable - 1] - fields[nSizeTable - 2]);
1393 const double extr1 =
1394 log(table[nSizeTable - 1]) - extr2 * fields[nSizeTable - 1];
1395 result = exp(std::min(50., extr1 + extr2 * e));
1396 } else {
1397 result = table[nSizeTable - 1];
1398 }
1399 } else {
1400 // Intermediate points, spline interpolation (not implemented).
1401 // Intermediate points, Newtonian interpolation
1402 result = Numerics::Divdif(table, fields, nSizeTable, e, intpMeth);
1403 }
1404
1405 return result;
1406}
1407
1408void Medium::Init(const size_t nE, const size_t nB, const size_t nA,
1409 std::vector<std::vector<std::vector<double> > >& tab,
1410 const double val) {
1411 if (nE == 0 || nB == 0 || nA == 0) {
1412 std::cerr << m_className << "::Init: Invalid grid.\n";
1413 return;
1414 }
1415 tab.assign(
1416 nA, std::vector<std::vector<double> >(nB, std::vector<double>(nE, val)));
1417}
1418
1420 const size_t nE, const size_t nB, const size_t nA, const size_t nT,
1421 std::vector<std::vector<std::vector<std::vector<double> > > >& tab,
1422 const double val) {
1423 if (nE == 0 || nB == 0 || nA == 0 || nT == 0) {
1424 std::cerr << m_className << "::Init: Invalid grid.\n";
1425 return;
1426 }
1427
1428 tab.assign(nT, std::vector<std::vector<std::vector<double> > >(
1429 nA, std::vector<std::vector<double> >(
1430 nB, std::vector<double>(nE, val))));
1431}
1432}
virtual double IonMobility()
Low-field ion mobility [cm2 V-1 ns-1].
Definition Medium.cc:680
void ResetHoleAttachment()
Definition Medium.hh:465
virtual void GetComponent(const unsigned int i, std::string &label, double &f)
Get the name and fraction of a given component.
Definition Medium.cc:106
bool Interpolate(const double e, const double b, const double a, const std::vector< std::vector< std::vector< double > > > &table, double &y, const unsigned int intp, const std::pair< unsigned int, unsigned int > &extr) const
Definition Medium.cc:1314
double m_density
Definition Medium.hh:550
void ResetIonMobility()
Definition Medium.hh:467
virtual bool GetPhotonCollision(const double e, int &type, int &level, double &e1, double &ctheta, int &nsec, double &esec)
Definition Medium.cc:780
virtual double UnScaleElectricField(const double e) const
Definition Medium.hh:500
void ResetElectronAttachment()
Definition Medium.hh:451
virtual double GetMassDensity() const
Get the mass density [g/cm3].
Definition Medium.cc:102
std::vector< double > m_bFields
Definition Medium.hh:573
void ResetIonDiffusion()
Definition Medium.hh:468
virtual void GetElectronMomentum(const double e, double &px, double &py, double &pz, int &band)
Definition Medium.cc:538
void SetTemperature(const double t)
Set the temperature [K].
Definition Medium.cc:72
void ResetElectronLorentzAngle()
Definition Medium.hh:452
double m_pressure
Definition Medium.hh:542
virtual bool HoleTownsend(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:599
unsigned int m_intpMob
Definition Medium.hh:629
virtual double ScaleAttachment(const double eta) const
Definition Medium.hh:505
bool GetEntry(const size_t i, const size_t j, const size_t k, const std::string &fcn, const std::vector< std::vector< std::vector< double > > > &tab, double &val) const
Definition Medium.cc:982
void SetExtrapolationMethodIonDissociation(const std::string &extrLow, const std::string &extrHigh)
Definition Medium.cc:1210
void SetInterpolationMethodIonDissociation(const unsigned int intrp)
Definition Medium.cc:1296
double Interpolate1D(const double e, const std::vector< double > &table, const std::vector< double > &fields, const unsigned int intpMeth, const std::pair< unsigned int, unsigned int > &extr) const
Definition Medium.cc:1334
double GetAngle(const double ex, const double ey, const double ez, const double bx, const double by, const double bz, const double e, const double b) const
Definition Medium.cc:1300
virtual double ScaleDiffusion(const double d) const
Definition Medium.hh:502
virtual double ElectronMobility()
Low-field mobility [cm2 V-1 ns-1].
Definition Medium.cc:518
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)
Drift velocity [cm / ns].
Definition Medium.cc:578
virtual double ScaleLorentzAngle(const double lor) const
Definition Medium.hh:506
unsigned int m_intpDis
Definition Medium.hh:630
virtual bool ElectronLorentzAngle(const double ex, const double ey, const double ez, const double bx, const double by, const double bz, double &lor)
Lorentz angle.
Definition Medium.cc:494
bool Diffusion(const double ex, const double ey, const double ez, const double bx, const double by, const double bz, const std::vector< std::vector< std::vector< double > > > &difL, const std::vector< std::vector< std::vector< double > > > &difT, double &dl, double &dt) const
Definition Medium.cc:334
std::vector< std::vector< std::vector< double > > > m_eAlp
Definition Medium.hh:582
void ResetHoleVelocity()
Definition Medium.hh:454
std::vector< std::vector< std::vector< double > > > m_hAlp
Definition Medium.hh:594
void ResetIonDissociation()
Definition Medium.hh:472
virtual bool GetDielectricFunction(const double e, double &eps1, double &eps2, const unsigned int i=0)
Get the complex dielectric function at a given energy.
Definition Medium.cc:734
virtual void SetNumberDensity(const double n)
Set the number density [cm-3].
Definition Medium.cc:135
std::string m_name
Definition Medium.hh:538
unsigned int m_intpDif
Definition Medium.hh:625
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:444
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)
Ion drift velocity [cm / ns].
Definition Medium.cc:630
std::pair< unsigned int, unsigned int > m_extrAtt
Definition Medium.hh:618
void SetExtrapolationMethodTownsend(const std::string &extrLow, const std::string &extrHigh)
Definition Medium.cc:1195
virtual void SetAtomicNumber(const double z)
Set the effective atomic number.
Definition Medium.cc:115
std::vector< std::vector< std::vector< double > > > m_iDifT
Definition Medium.hh:602
void SetExtrapolationMethodIonMobility(const std::string &extrLow, const std::string &extrHigh)
Definition Medium.cc:1205
void PlotVelocity(const std::string &carriers, TPad *pad)
Plot the drift velocity as function of the electric field.
Definition Medium.cc:161
unsigned int m_hThrAtt
Definition Medium.hh:611
std::pair< unsigned int, unsigned int > m_extrVel
Definition Medium.hh:615
virtual double ScaleElectricField(const double e) const
Definition Medium.hh:499
virtual double ScaleDiffusionTensor(const double d) const
Definition Medium.hh:503
std::vector< std::vector< std::vector< double > > > m_hDifL
Definition Medium.hh:592
virtual double GetElectronNullCollisionRate(const int band=0)
Null-collision rate [ns-1].
Definition Medium.cc:545
size_t SetThreshold(const std::vector< std::vector< std::vector< double > > > &tab) const
Definition Medium.cc:1252
std::vector< std::vector< std::vector< double > > > m_eVelE
Definition Medium.hh:577
std::vector< std::vector< std::vector< double > > > m_eVelX
Definition Medium.hh:578
std::vector< std::vector< std::vector< double > > > m_eDifL
Definition Medium.hh:580
void Init(const size_t nE, const size_t nB, const size_t nA, std::vector< std::vector< std::vector< double > > > &tab, const double val)
Definition Medium.cc:1408
virtual bool ElectronCollision(const double e, int &type, int &level, double &e1, double &dx, double &dy, double &dz, std::vector< std::pair< Particle, double > > &secondaries, int &ndxc, int &band)
Sample the collision type. Update energy and direction vector.
Definition Medium.cc:556
virtual double ScaleTownsend(const double alpha) const
Definition Medium.hh:504
unsigned int m_intpVel
Definition Medium.hh:624
virtual double GetPhotonCollisionRate(const double e)
Definition Medium.cc:773
void SetDielectricConstant(const double eps)
Set the relative static dielectric constant.
Definition Medium.cc:92
virtual bool GetDeexcitationProduct(const unsigned int i, double &t, double &s, int &type, double &energy) const
Definition Medium.cc:569
virtual double GetElectronCollisionRate(const double e, const int band=0)
Collision rate [ns-1] for given electron energy.
Definition Medium.cc:550
bool GetExtrapolationIndex(std::string str, unsigned int &nb) const
Definition Medium.cc:1235
void SetInterpolationMethodVelocity(const unsigned int intrp)
Set the degree of polynomial interpolation (usually 2).
Definition Medium.cc:1276
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)
Longitudinal and transverse diffusion coefficients [cm1/2].
Definition Medium.cc:452
void SetInterpolationMethodDiffusion(const unsigned int intrp)
Definition Medium.cc:1280
double m_epsilon
Definition Medium.hh:544
void SetExtrapolationMethodDiffusion(const std::string &extrLow, const std::string &extrHigh)
Definition Medium.cc:1190
std::vector< double > m_eFields
Definition Medium.hh:572
void GetFieldGrid(std::vector< double > &efields, std::vector< double > &bfields, std::vector< double > &angles)
Get the fields and E-B angles used in the transport tables.
Definition Medium.cc:958
static int m_idCounter
Definition Medium.hh:531
std::vector< std::vector< std::vector< double > > > m_hDifT
Definition Medium.hh:593
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:468
void ResetElectronDiffusion()
Definition Medium.hh:445
void SetFieldGrid(double emin, double emax, const size_t ne, bool logE, double bmin=0., double bmax=0., const size_t nb=1, double amin=HalfPi, double amax=HalfPi, const size_t na=1)
Set the range of fields to be covered by the transport tables.
Definition Medium.cc:791
virtual bool GetOpticalDataRange(double &emin, double &emax, const unsigned int i=0)
Get the energy range [eV] of the available optical data.
Definition Medium.cc:722
std::vector< std::vector< std::vector< double > > > m_eAtt
Definition Medium.hh:583
virtual void SetMassDensity(const double rho)
Set the mass density [g/cm3].
Definition Medium.cc:145
void PlotAlphaEta(const std::string &carriers, TPad *pad)
Plot Townsend and attachment coefficients.
Definition Medium.cc:189
virtual double ScaleDissociation(const double diss) const
Definition Medium.hh:507
bool Alpha(const double ex, const double ey, const double ez, const double bx, const double by, const double bz, const std::vector< std::vector< std::vector< double > > > &tab, unsigned int intp, const unsigned int thr, const std::pair< unsigned int, unsigned int > &extr, double &alpha) const
Definition Medium.cc:413
std::vector< double > m_bAngles
Definition Medium.hh:574
Medium()
Constructor.
Definition Medium.cc:61
std::vector< std::vector< std::vector< double > > > m_iDifL
Definition Medium.hh:601
std::vector< std::vector< std::vector< double > > > m_hVelE
Definition Medium.hh:589
std::vector< std::vector< std::vector< double > > > m_eLor
Definition Medium.hh:584
std::vector< std::vector< std::vector< double > > > m_eDifT
Definition Medium.hh:581
virtual double GetElectronEnergy(const double px, const double py, const double pz, double &vx, double &vy, double &vz, const int band=0)
Dispersion relation (energy vs. wave vector)
Definition Medium.cc:523
void SetInterpolationMethodIonMobility(const unsigned int intrp)
Definition Medium.cc:1292
unsigned int m_intpAtt
Definition Medium.hh:627
void SetExtrapolationMethodVelocity(const std::string &extrLow, const std::string &extrHigh)
Definition Medium.cc:1185
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:481
virtual double HoleMobility()
Low-field mobility [cm2 V-1 ns-1].
Definition Medium.cc:625
virtual double NegativeIonMobility()
Low-field negative ion mobility [cm2 V-1 ns-1].
Definition Medium.cc:718
std::pair< unsigned int, unsigned int > m_extrDis
Definition Medium.hh:621
void PlotDiffusion(const std::string &carriers, TPad *pad)
Plot the diffusion coefficients as function of the electric field.
Definition Medium.cc:168
std::vector< std::vector< std::vector< double > > > m_hAtt
Definition Medium.hh:595
void SetPressure(const double p)
Definition Medium.cc:82
void SetExtrapolationMethod(const std::string &low, const std::string &high, std::pair< unsigned int, unsigned int > &extr, const std::string &fcn)
Definition Medium.cc:1215
virtual bool NegativeIonVelocity(const double ex, const double ey, const double ez, const double bx, const double by, const double bz, double &vx, double &vy, double &vz)
Negative ion drift velocity [cm / ns].
Definition Medium.cc:684
std::pair< unsigned int, unsigned int > m_extrAlp
Definition Medium.hh:617
std::vector< std::vector< std::vector< double > > > m_eVelB
Definition Medium.hh:579
unsigned int m_eThrAtt
Definition Medium.hh:609
void PlotAttachment(const std::string &carriers, TPad *pad)
Plot the attachment coefficient(s) as function of the electric field.
Definition Medium.cc:182
virtual void SetAtomicWeight(const double a)
Set the effective atomic weight.
Definition Medium.cc:125
bool SetIonMobility(const std::vector< double > &fields, const std::vector< double > &mobilities, const bool negativeIons=false)
Definition Medium.cc:1139
void SetExtrapolationMethodAttachment(const std::string &extrLow, const std::string &extrHigh)
Definition Medium.cc:1200
void ResetNegativeIonMobility()
Definition Medium.hh:473
std::pair< unsigned int, unsigned int > m_extrLor
Definition Medium.hh:619
unsigned int m_nComponents
Definition Medium.hh:536
unsigned int m_intpLor
Definition Medium.hh:628
std::string m_className
Definition Medium.hh:529
std::pair< unsigned int, unsigned int > m_extrDif
Definition Medium.hh:616
void SetInterpolationMethodAttachment(const unsigned int intrp)
Definition Medium.cc:1288
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)
Longitudinal and transverse diffusion coefficients [cm1/2].
Definition Medium.cc:586
unsigned int m_iThrDis
Definition Medium.hh:612
virtual bool IonDissociation(const double ex, const double ey, const double ez, const double bx, const double by, const double bz, double &diss)
Dissociation coefficient.
Definition Medium.cc:667
virtual void ResetTables()
Reset all tables of transport parameters.
Definition Medium.cc:999
std::vector< std::vector< std::vector< double > > > m_hVelX
Definition Medium.hh:590
virtual ~Medium()
Destructor.
Definition Medium.cc:70
std::pair< unsigned int, unsigned int > m_extrMob
Definition Medium.hh:620
void Clone(std::vector< std::vector< std::vector< double > > > &tab, const std::vector< double > &efields, const std::vector< double > &bfields, const std::vector< double > &angles, const unsigned int intp, const std::pair< unsigned int, unsigned int > &extr, const double init, const std::string &label)
Definition Medium.cc:1018
void ResetHoleDiffusion()
Definition Medium.hh:459
std::vector< std::vector< std::vector< std::vector< double > > > > m_eDifM
Definition Medium.hh:586
std::vector< std::vector< std::vector< double > > > m_hVelB
Definition Medium.hh:591
bool Velocity(const double ex, const double ey, const double ez, const double bx, const double by, const double bz, const std::vector< std::vector< std::vector< double > > > &velE, const std::vector< std::vector< std::vector< double > > > &velB, const std::vector< std::vector< std::vector< double > > > &velX, const double q, double &vx, double &vy, double &vz) const
Definition Medium.cc:196
std::vector< std::vector< std::vector< std::vector< double > > > > m_hDifM
Definition Medium.hh:597
unsigned int m_hThrAlp
Definition Medium.hh:610
std::vector< std::vector< std::vector< double > > > m_iMob
Definition Medium.hh:600
bool SetEntry(const size_t i, const size_t j, const size_t k, const std::string &fcn, std::vector< std::vector< std::vector< double > > > &tab, const double val)
Definition Medium.cc:966
void ResetElectronTownsend()
Definition Medium.hh:450
unsigned int m_eThrAlp
Definition Medium.hh:608
void PlotTownsend(const std::string &carriers, TPad *pad)
Plot the Townsend coefficient(s) as function of the electric field.
Definition Medium.cc:175
virtual bool HoleAttachment(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:612
void ResetHoleTownsend()
Definition Medium.hh:464
void ResetElectronVelocity()
Definition Medium.hh:440
void SetInterpolationMethodTownsend(const unsigned int intrp)
Definition Medium.cc:1284
virtual bool GetPhotoAbsorptionCrossSection(const double e, double &sigma, const unsigned int i=0)
Definition Medium.cc:752
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)
Longitudinal and transverse diffusion coefficients [cm1/2].
Definition Medium.cc:660
double m_temperature
Definition Medium.hh:540
std::vector< std::vector< std::vector< double > > > m_iDis
Definition Medium.hh:603
static void Langevin(const double ex, const double ey, const double ez, double bx, double by, double bz, const double mu, double &vx, double &vy, double &vz)
Definition Medium.cc:301
std::vector< std::vector< std::vector< double > > > m_nMob
Definition Medium.hh:605
unsigned int m_intpAlp
Definition Medium.hh:626
void SetCanvas(TPad *pad)
Set the canvas to be painted on.
Definition ViewBase.hh:28
Plot transport coefficients as function of electric and magnetic field.
Definition ViewMedium.hh:17
void PlotAttachment(const std::string &carriers, const char xaxis)
Plot the attachment coefficient.
void SetMedium(Medium *m)
Set the medium from which to retrieve the transport coefficients.
Definition ViewMedium.cc:45
void PlotAlphaEta(const std::string &carriers, const char xaxis)
Plot Townsend and attachment coefficients.
void PlotTownsend(const std::string &carriers, const char xaxis)
Plot the Townsend coefficient.
void PlotDiffusion(const std::string &carriers, const char xaxis)
Plot the transverse and longitudinal diffusion coefficients.
void PlotVelocity(const std::string &carriers, const char xaxis)
bool Boxin3(const std::vector< std::vector< std::vector< double > > > &value, const std::vector< double > &xAxis, const std::vector< double > &yAxis, const std::vector< double > &zAxis, const int nx, const int ny, const int nz, const double xx, const double yy, const double zz, double &f, const int iOrder)
Definition Numerics.cc:1545
double Divdif(const std::vector< double > &f, const std::vector< double > &a, int nn, double x, int mm)
Definition Numerics.cc:1255
void RndmDirection(double &dx, double &dy, double &dz, const double length=1.)
Draw a random (isotropic) direction vector.
Definition Random.hh:128