Garfield++ v1r0
A toolkit for the detailed simulation of particle detectors based on ionisation measurement in gases and semiconductors
Loading...
Searching...
No Matches
TrackPAI.cc
Go to the documentation of this file.
1#include <iostream>
2#include <fstream>
3#include <cmath>
4
5#include "Sensor.hh"
6#include "TrackPAI.hh"
9#include "Random.hh"
10
11namespace Garfield {
12
14 : ready(false),
15 x(0.),
16 y(0.),
17 z(0.),
18 t(0.),
19 dx(0.),
20 dy(0),
21 dz(1.),
22 e(0.),
23 speed(0.),
24 emax(0.),
25 imfp(0.),
26 dedx(0.),
27 nSteps(1000),
28 mediumName(""),
29 mediumDensity(0.),
30 electronDensity(0.) {
31
32 className = "TrackPAI";
33
34 electrons.clear();
35 holes.clear();
36}
37
38bool TrackPAI::NewTrack(const double x0, const double y0, const double z0,
39 const double t0, const double dx0, const double dy0,
40 const double dz0) {
41
42 ready = false;
43
44 // Make sure the sensor has been set.
45 if (sensor == 0) {
46 std::cerr << className << "::NewTrack:\n";
47 std::cerr << " Sensor is not defined.\n";
48 return false;
49 }
50
51 // Get the medium at this location and check if it is "ionisable".
52 Medium* medium = 0;
53 if (!sensor->GetMedium(x0, y0, z0, medium)) {
54 std::cerr << className << "::NewTrack:\n";
55 std::cerr << " No medium at initial position.\n";
56 return false;
57 }
58 if (!medium->IsIonisable()) {
59 std::cerr << className << "::NewTrack:\n";
60 std::cerr << " Medium at initial position is not ionisable.\n";
61 return false;
62 }
63
64 if (medium->GetName() != mediumName ||
65 medium->GetNumberDensity() != mediumDensity) {
66 isChanged = true;
67 if (!SetupMedium(medium)) {
68 std::cerr << className << "::NewTrack:\n";
69 std::cerr << " Properties of medium " << medium->GetName()
70 << " are not available.\n";
71 return false;
72 }
73 mediumName = medium->GetName();
74 mediumDensity = medium->GetNumberDensity();
75 }
76
77 ready = true;
78
79 if (isChanged) {
80 if (!SetupCrossSectionTable()) {
81 std::cerr << className << "::NewTrack:\n";
82 std::cerr << " Calculation of ionisation cross-section failed.\n";
83 ready = false;
84 return false;
85 }
86 isChanged = false;
87 }
88
89 x = x0;
90 y = y0;
91 z = z0;
92 t = t0;
93 const double d = sqrt(dx0 * dx0 + dy0 * dy0 + dz0 * dz0);
94 if (d < Small) {
95 if (debug) {
96 std::cout << className << "::NewTrack:\n";
97 std::cout << " Direction vector has zero norm.\n";
98 std::cout << " Initial direction is randomized.\n";
99 }
100 const double ctheta = 1. - 2. * RndmUniform();
101 const double stheta = sqrt(1. - ctheta * ctheta);
102 const double phi = TwoPi * RndmUniform();
103 dx = cos(phi) * stheta;
104 dy = sin(phi) * stheta;
105 dz = ctheta;
106 } else {
107 // Normalize the direction vector.
108 dx = dx0 / d;
109 dy = dy0 / d;
110 dz = dz0 / d;
111 }
112 return true;
113}
114
115bool TrackPAI::GetCluster(double& xcls, double& ycls, double& zcls,
116 double& tcls, int& ncls, double& edep,
117 double& extra) {
118
119 ncls = 0;
120 edep = extra = 0.;
121
122 // Clear the stack.
123 electrons.clear();
124 holes.clear();
125
126 if (!ready) {
127 std::cerr << className << "::GetCluster:\n";
128 std::cerr << " Track not initialized.\n";
129 std::cerr << " Call NewTrack first.\n";
130 return false;
131 }
132
133 if (isChanged) {
134 if (SetupCrossSectionTable()) {
135 isChanged = false;
136 } else {
137 std::cerr << className << "::GetCluster:\n";
138 std::cerr << " Calculation of ionisation cross-section failed.\n";
139 return false;
140 }
141 }
142
143 // Draw a step length and propagate the particle.
144 const double d = -imfp * log(RndmUniformPos());
145 x += d * dx;
146 y += d * dy;
147 z += d * dz;
148 t += d / speed;
149
150 // Check the medium at this location.
151 Medium* medium = 0;
152 if (!sensor->GetMedium(x, y, z, medium)) {
153 ready = false;
154 return false;
155 }
156 if (medium->GetName() != mediumName ||
157 medium->GetNumberDensity() != mediumDensity || !medium->IsIonisable()) {
158 ready = false;
159 return false;
160 }
161
162 // Check if the particle is still inside the drift area.
163 if (!sensor->IsInArea(x, y, z)) {
164 ready = false;
165 return false;
166 }
167
168 xcls = x;
169 ycls = y;
170 zcls = z;
171 tcls = t;
172
173 // Sample the energy deposition.
174 double f = 0.;
175 const double u = RndmUniform();
176 if (u < cdf.back()) {
177 if (u <= cdf[0]) {
178 edep = energies[0];
179 } else if (u >= 1.) {
180 edep = energies.back();
181 } else {
182 // Find the energy loss by interpolation
183 // from the cumulative distribution table
184 int iLow = 0, iUp = cdf.size(), iMid;
185 while (iUp - iLow > 1) {
186 iMid = (iUp + iLow) >> 1;
187 if (u >= cdf[iMid]) {
188 iLow = iMid;
189 } else {
190 iUp = iMid;
191 }
192 }
193 if (edep < 100.) {
194 edep = energies[iLow] + (u - cdf[iLow]) *
195 (energies[iUp] - energies[iLow]) /
196 (cdf[iUp] - cdf[iLow]);
197 f = rutherford[iLow] + (edep - energies[iLow]) *
198 (rutherford[iUp] - rutherford[iLow]) /
199 (energies[iUp] - energies[iLow]);
200 } else {
201 edep = log(energies[iLow]) +
202 (log(u) - log(cdf[iLow])) *
203 (log(energies[iUp]) - log(energies[iLow])) /
204 (log(cdf[iUp]) - log(cdf[iLow]));
205 edep = exp(edep);
206 f = rutherford[iLow] + (log(edep) - log(energies[iLow])) *
207 (rutherford[iUp] - rutherford[iLow]) /
208 (log(energies[iUp]) - log(energies[iLow]));
209 }
210 }
211 } else {
212 // Use the free-electron differential cross-section.
213 f = 1.;
214 edep = SampleAsymptoticCs(u);
215 }
216 // Update the particle energy.
217 e -= edep;
218
219 // Number of electron/hole (or electron/ion pairs) produced.
220 ncls = 1;
221
222 if (debug) {
223 std::cout << className << "::GetCluster:\n";
224 std::cout << " Fraction of Rutherford scattering: " << f << "\n";
225 }
226 return true;
227}
228
229bool TrackPAI::SetupMedium(Medium* medium) {
230
231 // Make sure that the medium is defined.
232 if (medium == 0) {
233 std::cerr << className << "::SetupMedium:\n";
234 std::cerr << " Medium pointer is null.\n";
235 return false;
236 }
237
238 // Get the density and effective Z.
239 electronDensity = medium->GetNumberDensity() * medium->GetAtomicNumber();
240 if (electronDensity <= 0.) {
241 std::cerr << className << "::SetupMedium:\n";
242 std::cerr << " Medium has an unphysical electron density ("
243 << electronDensity << ")\n";
244 return false;
245 }
246
247 // Get the dielectric function.
248 double emin, emax;
249 if (!medium->GetOpticalDataRange(emin, emax)) {
250 std::cerr << className << "::SetupMedium:\n";
251 std::cerr << " Could not load optical data for medium " << mediumName
252 << ".\n";
253 return false;
254 }
255
256 // Make sure the minimum energy is positive.
257 if (emin < Small) emin = Small;
258
259 // Reset the arrays.
260 energies.clear();
261 opticalDataTable.clear();
262 opticalData newEpsilon;
263
264 // Use logarithmically spaced energy steps.
265 const double r = pow(emax / emin, 1. / double(nSteps));
266 double eps1, eps2;
267
268 double eC = 0.5 * emin * (1. + r);
269 for (int i = 0; i < nSteps; ++i) {
270 medium->GetDielectricFunction(eC, eps1, eps2);
271 newEpsilon.eps1 = eps1;
272 newEpsilon.eps2 = eps2;
273 opticalDataTable.push_back(newEpsilon);
274 energies.push_back(eC);
275 eC *= r;
276 }
277
278 // Compute the integral of loss function times energy.
279 opticalDataTable[0].integral = 0.;
280 double integral = 0.;
281 double f1 = energies[0] *
282 LossFunction(opticalDataTable[0].eps1, opticalDataTable[0].eps2);
283 double f2 = f1;
284 double eM, fM;
285 for (int i = 1; i < nSteps; ++i) {
286 f2 = energies[i] *
287 LossFunction(opticalDataTable[i].eps1, opticalDataTable[i].eps2);
288 eM = 0.5 * (energies[i - 1] + energies[i]);
289 medium->GetDielectricFunction(eM, eps1, eps2);
290 fM = eM * LossFunction(eps1, eps2);
291 // Simpson's rule
292 integral += (f1 + 4 * fM + f2) * (energies[i] - energies[i - 1]) / 6.;
293 opticalDataTable[i].integral = integral;
294 f1 = f2;
295 }
296
297 // Check the consistency of the optical data by means of the TRK sum rule
298 const double trk = 2 * Pi2 * FineStructureConstant * pow(HbarC, 3) *
299 electronDensity / ElectronMass;
300 if (fabs(integral - trk) > 0.2 * trk) {
301 std::cerr << className << "::SetupMedium:\n";
302 std::cerr << " Deviation from Thomas-Reiche-Kuhn sum rule by > 20%.\n";
303 std::cerr << " Optical data are probably incomplete or erroneous!\n";
304 }
305
306 return true;
307}
308
310
311 if (!ready) {
312 std::cerr << className << "::GetClusterDensity:\n";
313 std::cerr << " Track has not been initialized.\n";
314 return 0.;
315 }
316
317 if (isChanged) {
318 if (SetupCrossSectionTable()) {
319 isChanged = false;
320 } else {
321 std::cerr << className << "::GetClusterDensity:\n";
322 std::cerr << " Ionisation cross-section could not be calculated.\n";
323 return 0.;
324 }
325 }
326
327 return 1. / imfp;
328}
329
331
332 if (!ready) {
333 std::cerr << className << "::GetStoppingPower:\n";
334 std::cerr << " Track has not been initialised.\n";
335 return 0.;
336 }
337
338 if (isChanged) {
339 if (SetupCrossSectionTable()) {
340 isChanged = false;
341 } else {
342 std::cerr << className << "::GetStoppingPower:\n";
343 std::cerr << " Ionisation cross-section could not be calculated.\n";
344 return 0.;
345 }
346 }
347
348 return dedx;
349}
350
351bool TrackPAI::SetupCrossSectionTable() {
352
353 if (!ready) {
354 std::cerr << className << "::SetupCrossSectionTable:\n";
355 std::cerr << " Medium not set up.\n";
356 return false;
357 }
358
359 const double c1 = 2. * Pi2 * FineStructureConstant * pow(HbarC, 3) *
360 electronDensity / ElectronMass;
361 const double c2 = q * q * FineStructureConstant / (beta2 * Pi * HbarC);
362
363 // Get the max. allowed energy transfer.
364 emax = ComputeMaxTransfer();
365
366 std::ofstream outfile;
367 if (debug) outfile.open("dcs.txt", std::ios::out);
368
369 // Compute the differential cross-section.
370 std::vector<double> dcs;
371 dcs.clear();
372 rutherford.clear();
373
374 for (int i = 0; i < nSteps; ++i) {
375 // Define shorthand variables for photon energy and dielectric function.
376 const double egamma = energies[i];
377 const double eps1 = opticalDataTable[i].eps1;
378 const double eps2 = opticalDataTable[i].eps2;
379 const double integral = opticalDataTable[i].integral;
380
381 // First, calculate the distant-collision terms.
382 double dcsLog = 0., dcsDensity = 0., dcsCerenkov = 0.;
383 if (eps2 > 0.) {
384 // Normal case (loss function > 0).
385 // Non-relativistic logarithmic term.
386 dcsLog =
387 LossFunction(eps1, eps2) * log(2 * ElectronMass * beta2 / egamma);
388 // Relativistic logarithmic term (density effect)
389 const double u = 1. - beta2 * eps1;
390 const double v = beta2 * eps2;
391 dcsDensity = -0.5 * LossFunction(eps1, eps2) * log(u * u + v * v);
392 // "Cerenkov" term
393 dcsCerenkov =
394 (beta2 - eps1 / (eps1 * eps1 + eps2 * eps2)) * (HalfPi - atan(u / v));
395 } else if (eps1 > 1. / beta2) {
396 // Imaginary part is zero, only the Cerenkov term contributes.
397 dcsCerenkov = Pi * (beta2 - 1. / eps1);
398 }
399
400 // Calculate the close-collision term (quasi-free scattering)
401 double dcsRuth = 0.;
402 double f = 0.;
403 if (egamma > 0. && integral > 0.) {
404 dcsRuth = integral / (egamma * egamma);
405 f = dcsRuth / (dcsLog + dcsDensity + dcsCerenkov);
406 }
407 rutherford.push_back(f);
408 dcs.push_back(dcsLog + dcsDensity + dcsCerenkov + dcsRuth);
409 // If requested, write the cross-section terms to file.
410 if (debug) {
411 outfile << egamma << " " << eps1 << " " << eps2 << " " << dcsLog* c2
412 << " " << dcsDensity* c2 << " " << dcsCerenkov* c2 << " "
413 << dcsRuth* c2 << "\n";
414 }
415 }
416 if (debug) outfile.close();
417
418 // Compute the cumulative distribution,
419 // total cross-section and stopping power.
420 cdf.clear();
421 cdf.push_back(0.);
422 dedx = 0.;
423 double cs = 0.;
424 for (int i = 1; i < nSteps; ++i) {
425 cs += 0.5 * (dcs[i - 1] + dcs[i]) * (energies[i] - energies[i - 1]);
426 cdf.push_back(cs);
427 dedx += 0.5 * (dcs[i - 1] * energies[i - 1] + dcs[i] * energies[i]) *
428 (energies[i] - energies[i - 1]);
429 }
430
431 // Add the contribution of high energy transfers to the stopping power
432 // and the total cross-section
433 const double elim = energies.back();
434 if (elim < emax) {
435 cs += c1 * ComputeCsTail(elim, emax);
436 dedx += c1 * ComputeDeDxTail(elim, emax);
437 } else {
438 std::cerr << className << "::SetupCrossSectionTable:\n";
439 std::cerr << " Max. energy transfer lower than optical data range.\n";
440 }
441
442 if (cs <= 0.) {
443 std::cerr << "TrackPAI:SetupCrossSectionTable:\n";
444 std::cerr << " Total cross-section <= 0.\n";
445 return false;
446 }
447
448 // Normalise the cumulative distribution.
449 for (int i = nSteps; i--;) cdf[i] /= cs;
450
451 cs *= c2;
452 dedx *= c2;
453
454 // Compute the inelastic mean free path
455 imfp = 1. / cs;
456
457 return true;
458}
459
460double TrackPAI::ComputeMaxTransfer() const {
461
462 if (isElectron) {
463 // Max. transfer for electrons is half the kinetic energy.
464 return 0.5 * (energy - mass);
465 }
466
467 // Other particles.
468 const double bg2 = beta2 / (1. - beta2);
469 const double mass2 = mass * mass;
470
471 return 2. * mass2 * ElectronMass * bg2 /
472 (mass2 + ElectronMass * ElectronMass + 2. * energy * ElectronMass);
473}
474
475double TrackPAI::ComputeCsTail(const double emin, const double emax) {
476
477 if (isElectron) {
478 // Electrons
479 const double ek = energy - mass;
480 return 1. / emin - 1. / emax - 2 * emin / (ek * ek) -
481 emin * emin / ((ek - emin) * ek * ek);
482 } else if (mass == ElectronMass) {
483 // Positrons
484 const double ek = energy - mass;
485 return 1. / emin - 1. / emax + 3 * (emax - emin) / (ek * ek) -
486 (emax - emin) * (ek * (emax + emin) +
487 (emin * emin + emin * emax + emax * emax) / 3.) /
488 pow(ek, 4) -
489 (2. / ek) * log(emax / emin);
490 }
491
492 switch (spin) {
493 case 0:
494 // Spin 0
495 return 1. / emin - 1. / emax - beta2 * log(emax / emin) / emax;
496 break;
497 case 1:
498 // Spin 1/2
499 return 1. / emin - 1. / emax - beta2 * log(emax / emin) / emax +
500 (emax - emin) / (2 * energy * energy);
501 break;
502 case 2: {
503 // Spin 1
504 const double e2 = 2 * energy * energy;
505 const double ec = mass * mass / ElectronMass;
506 const double a = 1. / (3 * ec);
507 const double b = (emax - emin);
508 return 1. / emin - 1. / emax + a * b * (emin + e2 + emax) / e2 -
509 beta2 * a * b / emax + (a - beta2 / emax) * log(emax / emin);
510 break;
511 }
512 default:
513 break;
514 }
515 // Rutherford type cross-section
516 return 1. / emin - 1. / emax;
517}
518
519double TrackPAI::ComputeDeDxTail(const double emin, const double emax) {
520
521 if (isElectron) {
522 const double ek = energy - mass;
523 return -log(emin * (ek - emin) / (ek * ek)) +
524 (1. / (8 * (emin - ek) * ek * ek)) *
525 (-4 * pow(emin, 3) + 4 * emin * emin * ek +
526 emin * ek * ek * (17. - 16. * CLog2) +
527 pow(ek, 3) * (-9. + 16. * CLog2));
528 } else if (mass == ElectronMass) {
529 // Positron
530 const double ek = energy - mass;
531 return log(ek / emin) -
532 (ek - emin) * (ek - emin) *
533 (3. * emin * emin - 2. * emin * ek + 11. * ek * ek) /
534 (12. * pow(ek, 4));
535 }
536
537 switch (spin) {
538 case 0:
539 return log(emax / emin) - beta2 * (emax - emin) / emax;
540 break;
541 case 1:
542 // Spin 1/2
543 return log(emax / emin) - beta2 * (emax - emin) / emax +
544 (emax * emax - emin * emin) / (2 * energy * energy);
545 break;
546 case 2: {
547 // Spin 1
548 double e2 = energy * energy;
549 double ec = mass * mass / ElectronMass;
550 return log(emax / emin) + (pow(emax, 3) - pow(emin, 3)) / (9. * e2 * ec) +
551 (emax * emax - emin * emin) / (6. * e2) +
552 (emax - emin) * (2. - (1. + emin / emax + 6 * ec / emax) * beta2) /
553 (6. * ec);
554 break;
555 }
556 default:
557 break;
558 }
559
560 // Rutherford cross-section
561 return log(emax / emin);
562}
563
564double TrackPAI::SampleAsymptoticCs(double u) {
565
566 const double emin = energies.back();
567 // Rescale the random number
568 u = (u - cdf.back()) / (1. - cdf.back());
569
570 if (isElectron) {
571 return SampleAsymptoticCsElectron(emin, u);
572 } else if (mass == ElectronMass) {
573 return SampleAsymptoticCsPositron(emin, u);
574 }
575
576 switch (spin) {
577 case 0:
578 // Spin 0
579 return SampleAsymptoticCsSpinZero(emin, u);
580 break;
581 case 1:
582 // Spin 1/2
583 return SampleAsymptoticCsSpinHalf(emin, u);
584 break;
585 case 2:
586 // Spin 1
587 return SampleAsymptoticCsSpinOne(emin, u);
588 break;
589 default:
590 break;
591 }
592 // Rutherford cross-section (analytic inversion)
593 return emin * emax / (u * emin + (1. - u) * emax);
594}
595
596double TrackPAI::SampleAsymptoticCsSpinZero(const double emin, double u) {
597
598 const double a = emin / emax;
599 const double b = beta2 * a;
600 u *= (1. - a + b * log(a));
601 double eLow = emin, eUp = emax;
602 double eM;
603 while (eUp - eLow > 1.) {
604 eM = 0.5 * (eUp + eLow);
605 if (u >= 1. - emin / eM - b * log(eM / emin)) {
606 eLow = eM;
607 } else {
608 eUp = eM;
609 }
610 }
611
612 return 0.5 * (eLow + eUp);
613}
614
615double TrackPAI::SampleAsymptoticCsSpinHalf(const double emin, double u) {
616
617 const double a = emin / emax;
618 const double b = beta2 * a;
619 const double c = emin / (2. * energy * energy);
620 u *= 1. - a + b * log(a) + (emax - emin) * c;
621 double eLow = emin, eUp = emax;
622 double eM;
623 while (eUp - eLow > 1.) {
624 eM = 0.5 * (eUp + eLow);
625 if (u >= 1. - emin / eM - b * log(eM / emin) + (eM - emin) * c) {
626 eLow = eM;
627 } else {
628 eUp = eM;
629 }
630 }
631
632 return 0.5 * (eLow + eUp);
633}
634
635double TrackPAI::SampleAsymptoticCsSpinOne(const double emin, double u) {
636
637 const double e2 = 2 * energy * energy;
638 const double ec = mass * mass / ElectronMass;
639 const double a = 2 * ec / e2 - beta2 / emax;
640 const double b = 1.5 * ec / emin;
641 const double c = 1. - 1.5 * ec * beta2 / emax;
642 u *= (emax - emin) * (0.5 * (emin + emax) / e2 + a + b / emax) +
643 c * log(emax / emin);
644 double eLow = emin, eUp = emax;
645 double eM;
646 while (eUp - eLow > 1.) {
647 eM = 0.5 * (eUp + eLow);
648 if (u >=
649 (eM - emin) * ((emin + eM) / e2 + a + b / eM) + c * log(eM / emin)) {
650 eLow = eM;
651 } else {
652 eUp = eM;
653 }
654 }
655
656 return 0.5 * (eLow + eUp);
657}
658
659double TrackPAI::SampleAsymptoticCsElectron(const double emin, double u) {
660
661 const double ek = energy - mass;
662 const double ek2 = ek * ek;
663 const double a = ek / (emin * (ek - emin));
664 const double norm = 1. / emin - 0.5 / ek - emin * emin / ((ek - emin) * ek2) -
665 2. * emin / ek2;
666 u *= norm;
667 double eLow = emin, eUp = emax, eM;
668 while (eUp - eLow > 1.) {
669 eM = 0.5 * (eUp + eLow);
670 if (u >= a - 1. / eM + (eM - emin) / ek2 + 1. / (ek - eM)) {
671 eLow = eM;
672 } else {
673 eUp = eM;
674 }
675 }
676 return 0.5 * (eLow + eUp);
677}
678
679double TrackPAI::SampleAsymptoticCsPositron(const double emin, double u) {
680
681 const double ek = energy - mass;
682 const double ek2 = ek * ek;
683 const double ek3 = ek2 * ek;
684 const double ek4 = 3 * ek3 * ek;
685 const double emin2 = emin * emin;
686 const double a = 1. / emin;
687 const double b = 3. / ek2;
688 const double c = 2. / ek;
689 u *= 1. / emin - 1. / emax + 3 * (emax - emin) / ek2 -
690 (emax - emin) * (emax + emin) / ek3 +
691 (emax - emin) * (emin * emin + emin * emax + emax * emax) / ek4 -
692 (2. / ek) * log(emax / emin);
693 double eLow = emin, eUp = emax;
694 double eM, eM2;
695 while (eUp - eLow > 1.) {
696 eM = 0.5 * (eUp + eLow);
697 eM2 = eM * eM;
698 if (u >= a - 1. / eM + b * (eM - emin) - (eM2 - emin2) / ek3 +
699 (eM - emin) * (emin2 + emin * eM + eM2) / ek4 -
700 c * log(eM / emin)) {
701 eLow = eM;
702 } else {
703 eUp = eM;
704 }
705 }
706
707 return 0.5 * (eLow + eUp);
708}
709
710double TrackPAI::LossFunction(const double eps1, const double eps2) {
711
712 const double eps = eps1 * eps1 + eps2 * eps2;
713 if (eps <= 0.) {
714 std::cerr << className << "::LossFunction:\n";
715 std::cerr << " Dielectric function is zero.\n";
716 return 0.;
717 }
718 return eps2 / (eps1 * eps1 + eps2 * eps2);
719}
720}
DoubleAc cos(const DoubleAc &f)
Definition: DoubleAc.cpp:431
DoubleAc pow(const DoubleAc &f, double p)
Definition: DoubleAc.cpp:336
DoubleAc sqrt(const DoubleAc &f)
Definition: DoubleAc.cpp:313
DoubleAc sin(const DoubleAc &f)
Definition: DoubleAc.cpp:383
DoubleAc exp(const DoubleAc &f)
Definition: DoubleAc.cpp:376
DoubleAc fabs(const DoubleAc &f)
Definition: DoubleAc.h:616
virtual double GetNumberDensity() const
Definition: Medium.hh:47
virtual bool GetOpticalDataRange(double &emin, double &emax, const unsigned int &i=0)
Definition: Medium.cc:1402
virtual double GetAtomicNumber() const
Definition: Medium.hh:42
virtual bool GetDielectricFunction(const double &e, double &eps1, double &eps2, const unsigned int &i=0)
Definition: Medium.cc:1419
bool IsIonisable() const
Definition: Medium.hh:59
std::string GetName() const
Definition: Medium.hh:22
bool IsInArea(const double x, const double y, const double z)
Definition: Sensor.cc:254
bool GetMedium(const double x, const double y, const double z, Medium *&medium)
Definition: Sensor.cc:141
bool GetCluster(double &xcls, double &ycls, double &zcls, double &tcls, int &ncls, double &ecls, double &extra)
Definition: TrackPAI.cc:115
double GetStoppingPower()
Definition: TrackPAI.cc:330
bool NewTrack(const double x0, const double y0, const double z0, const double t0, const double dx0, const double dy0, const double dz0)
Definition: TrackPAI.cc:38
double GetClusterDensity()
Definition: TrackPAI.cc:309
double energy
Definition: Track.hh:66
bool isChanged
Definition: Track.hh:73
std::string className
Definition: Track.hh:61
double mass
Definition: Track.hh:65
double q
Definition: Track.hh:63
double beta2
Definition: Track.hh:67
bool isElectron
Definition: Track.hh:68
bool debug
Definition: Track.hh:78
Sensor * sensor
Definition: Track.hh:71
double RndmUniform()
Definition: Random.hh:16
double RndmUniformPos()
Definition: Random.hh:19