Garfield++ 4.0
A toolkit for the detailed simulation of particle detectors based on ionisation measurement in gases and semiconductors
Loading...
Searching...
No Matches
TrackHeed.cc
Go to the documentation of this file.
1#include <iostream>
2
6
17
18#include "HeedChamber.hh"
19#include "HeedFieldMap.h"
20
23#include "Garfield/Random.hh"
24#include "Garfield/Sensor.hh"
25#include "Garfield/ViewDrift.hh"
26
27#include "Garfield/TrackHeed.hh"
28
29namespace {
30
31void ClearBank(std::vector<Heed::gparticle*>& bank) {
32 for (auto particle : bank)
33 if (particle) delete particle;
34 bank.clear();
35}
36}
37
38// Global functions and variables required by Heed
39namespace Heed {
40
41// Particle id number for book-keeping
43}
44
45// Actual class implementation
46
47namespace Garfield {
48
50 m_className = "TrackHeed";
51 m_conductionElectrons.reserve(1000);
52 m_conductionIons.reserve(1000);
53
54 m_fieldMap.reset(new Heed::HeedFieldMap());
55}
56
58
59bool TrackHeed::NewTrack(const double x0, const double y0, const double z0,
60 const double t0, const double dx0, const double dy0,
61 const double dz0) {
62 m_hasActiveTrack = false;
63 m_ready = false;
64
65 // Make sure the sensor has been set.
66 if (!m_sensor) {
67 std::cerr << m_className << "::NewTrack: Sensor is not defined.\n";
68 return false;
69 }
70
71 bool update = false;
72 if (!UpdateBoundingBox(update)) return false;
73
74 // Make sure the initial position is inside an ionisable medium.
75 Medium* medium = nullptr;
76 if (!m_sensor->GetMedium(x0, y0, z0, medium)) {
77 std::cerr << m_className << "::NewTrack:\n"
78 << " No medium at initial position.\n";
79 return false;
80 } else if (!medium->IsIonisable()) {
81 std::cerr << m_className << "::NewTrack:\n"
82 << " Medium at initial position is not ionisable.\n";
83 return false;
84 }
85
86 // Check if the medium has changed since the last call.
87 if (medium->GetName() != m_mediumName ||
88 fabs(medium->GetMassDensity() - m_mediumDensity) > 1.e-9) {
89 m_isChanged = true;
90 }
91
92 // If medium, particle or bounding box have changed,
93 // update the cross-sections.
94 if (m_isChanged) {
95 if (!Initialise(medium)) return false;
96 m_isChanged = false;
97 m_mediumName = medium->GetName();
98 m_mediumDensity = medium->GetMassDensity();
99 }
100
101 ClearParticleBank();
102
103 m_deltaElectrons.clear();
104 m_conductionElectrons.clear();
105 m_conductionIons.clear();
106
107 // Check the direction vector.
108 double dx = dx0, dy = dy0, dz = dz0;
109 const double d = sqrt(dx * dx + dy * dy + dz * dz);
110 if (d < Small) {
111 if (m_debug) {
112 std::cout << m_className << "::NewTrack:\n"
113 << " Direction vector has zero norm.\n"
114 << " Initial direction is randomized.\n";
115 }
116 // Null vector. Sample the direction isotropically.
117 RndmDirection(dx, dy, dz);
118 } else {
119 // Normalise the direction vector.
120 dx /= d;
121 dy /= d;
122 dz /= d;
123 }
124 Heed::vec velocity(dx, dy, dz);
125 velocity = velocity * Heed::CLHEP::c_light * GetBeta();
126
127 if (m_debug) {
128 std::cout << m_className << "::NewTrack:\n Track starts at (" << x0
129 << ", " << y0 << ", " << z0 << ") at time " << t0 << "\n"
130 << " Direction: (" << dx << ", " << dy << ", " << dz << ")\n";
131 }
132
133 // Initial position (shift with respect to bounding box center and
134 // convert from cm to mm).
135 Heed::point p0((x0 - m_cX) * 10., (y0 - m_cY) * 10., (z0 - m_cZ) * 10.);
136
137 // Setup the particle.
139 if (m_particleName == "e-") {
140 particleType = &Heed::electron_def;
141 } else if (m_particleName == "e+") {
142 particleType = &Heed::positron_def;
143 } else if (m_particleName == "mu-") {
144 particleType = &Heed::muon_minus_def;
145 } else if (m_particleName == "mu+") {
146 particleType = &Heed::muon_plus_def;
147 } else if (m_particleName == "pi-") {
148 particleType = &Heed::pi_minus_meson_def;
149 } else if (m_particleName == "pi+") {
150 particleType = &Heed::pi_plus_meson_def;
151 } else if (m_particleName == "K-") {
152 particleType = &Heed::K_minus_meson_def;
153 } else if (m_particleName == "K+") {
154 particleType = &Heed::K_plus_meson_def;
155 } else if (m_particleName == "p") {
156 particleType = &Heed::proton_def;
157 } else if (m_particleName == "pbar") {
158 particleType = &Heed::anti_proton_def;
159 } else if (m_particleName == "d") {
160 particleType = &Heed::deuteron_def;
161 } else if (m_particleName == "alpha") {
162 particleType = &Heed::alpha_particle_def;
163 } else if (m_particleName == "exotic") {
164 // User defined particle
167 particleType = &Heed::user_particle_def;
168 } else {
169 // Not a predefined particle, use muon definition.
170 if (m_q > 0.) {
171 particleType = &Heed::muon_minus_def;
172 } else {
173 particleType = &Heed::muon_plus_def;
174 }
175 }
176
177 Heed::HeedParticle particle(m_chamber.get(), p0, velocity, t0, particleType,
178 m_fieldMap.get());
179 // Set the step limits.
180 particle.set_step_limits(m_maxStep * Heed::CLHEP::cm,
181 m_radStraight * Heed::CLHEP::cm,
182 m_stepAngleStraight * Heed::CLHEP::rad,
183 m_stepAngleCurved * Heed::CLHEP::rad);
184 // Transport the particle.
185 if (m_useOneStepFly) {
186 particle.fly(m_particleBank, true);
187 } else {
188 particle.fly(m_particleBank);
189 }
190
191 m_bankIterator = m_particleBank.begin();
192 m_hasActiveTrack = true;
193 m_ready = true;
194
195 // Plot the new track.
196 if (m_viewer) PlotNewTrack(x0, y0, z0);
197 return true;
198}
199
201
202 if (!m_transferCs) {
203 std::cerr << m_className << "::GetClusterDensity:\n"
204 << " Ionisation cross-section is not available.\n";
205 return 0.;
206 }
207
208 return m_transferCs->quanC;
209}
210
212
213 if (!m_transferCs) {
214 std::cerr << m_className << "::GetStoppingPower:\n"
215 << " Ionisation cross-section is not available.\n";
216 return 0.;
217 }
218
219 return m_transferCs->meanC1 * 1.e6;
220}
221
222bool TrackHeed::GetCluster(double& xcls, double& ycls, double& zcls,
223 double& tcls, int& n, double& e, double& extra) {
224 int ni = 0;
225 return GetCluster(xcls, ycls, zcls, tcls, n, ni, e, extra);
226}
227
228bool TrackHeed::GetCluster(double& xcls, double& ycls, double& zcls,
229 double& tcls, int& ne, int& ni, double& e,
230 double& extra) {
231 // Initialise and reset.
232 xcls = ycls = zcls = tcls = 0.;
233 extra = 0.;
234 ne = ni = 0;
235 e = 0.;
236
237 m_deltaElectrons.clear();
238 m_conductionElectrons.clear();
239 m_conductionIons.clear();
240
241 // Make sure NewTrack has been called successfully.
242 if (!m_ready) {
243 std::cerr << m_className << "::GetCluster:\n"
244 << " Track has not been initialized. Call NewTrack first.\n";
245 return false;
246 }
247
248 if (m_particleBank.empty()) return false;
249 std::vector<Heed::gparticle*>::const_iterator end = m_particleBank.end();
250 if (m_bankIterator == end) return false;
251
252 // Look for the next cluster (i. e. virtual photon) in the list.
253 Heed::HeedPhoton* virtualPhoton = nullptr;
254 for (; m_bankIterator != end; ++m_bankIterator) {
255 // Convert the particle to a (virtual) photon.
256 virtualPhoton = dynamic_cast<Heed::HeedPhoton*>(*m_bankIterator);
257 if (!virtualPhoton) {
258 std::cerr << m_className << "::GetCluster:\n"
259 << " Particle is not a virtual photon. Program bug!\n";
260 // Try the next element.
261 continue;
262 }
263
264 // Get the location of the interaction (convert from mm to cm
265 // and shift with respect to bounding box center).
266 xcls = virtualPhoton->position().x * 0.1 + m_cX;
267 ycls = virtualPhoton->position().y * 0.1 + m_cY;
268 zcls = virtualPhoton->position().z * 0.1 + m_cZ;
269 tcls = virtualPhoton->time();
270 // Skip clusters outside the drift area or outside the active medium.
271 if (!IsInside(xcls, ycls, zcls)) continue;
272 // Add the first ion (at the position of the cluster).
273 m_conductionIons.emplace_back(
274 Heed::HeedCondElectron(Heed::point(virtualPhoton->position()), tcls));
275 ++m_bankIterator;
276 break;
277 }
278
279 // Stop if we did not find a virtual photon.
280 if (!virtualPhoton) return false;
281 // Plot the cluster, if requested.
282 if (m_viewer) PlotCluster(xcls, ycls, zcls);
283
284 std::vector<Heed::gparticle*> secondaries;
285 // Transport the virtual photon.
286 virtualPhoton->fly(secondaries);
287 // Get the transferred energy (convert from MeV to eV).
288 e = virtualPhoton->m_energy * 1.e6;
289
290 while (!secondaries.empty()) {
291 std::vector<Heed::gparticle*> newSecondaries;
292 // Loop over the secondaries.
293 for (auto secondary : secondaries) {
294 // Check if it is a delta electron.
295 auto delta = dynamic_cast<Heed::HeedDeltaElectron*>(secondary);
296 if (delta) {
297 extra += delta->kinetic_energy() * 1.e6;
298 const double x = delta->position().x * 0.1 + m_cX;
299 const double y = delta->position().y * 0.1 + m_cY;
300 const double z = delta->position().z * 0.1 + m_cZ;
301 if (!IsInside(x, y, z)) continue;
302 if (m_doDeltaTransport) {
303 // Transport the delta electron.
304 delta->fly(newSecondaries);
305 // Add the conduction electrons and ions to the list.
306 m_conductionElectrons.insert(m_conductionElectrons.end(),
307 delta->conduction_electrons.begin(),
308 delta->conduction_electrons.end());
309 m_conductionIons.insert(m_conductionIons.end(),
310 delta->conduction_ions.begin(),
311 delta->conduction_ions.end());
312 } else {
313 // Add the delta electron to the list, for later use.
314 deltaElectron newDeltaElectron;
315 newDeltaElectron.x = delta->position().x * 0.1 + m_cX;
316 newDeltaElectron.y = delta->position().y * 0.1 + m_cY;
317 newDeltaElectron.z = delta->position().z * 0.1 + m_cZ;
318 newDeltaElectron.t = delta->time();
319 newDeltaElectron.e = delta->kinetic_energy() * 1.e6;
320 newDeltaElectron.dx = delta->direction().x;
321 newDeltaElectron.dy = delta->direction().y;
322 newDeltaElectron.dz = delta->direction().z;
323 m_deltaElectrons.push_back(std::move(newDeltaElectron));
324 }
325 continue;
326 }
327 // Check if it is a real photon.
328 auto photon = dynamic_cast<Heed::HeedPhoton*>(secondary);
329 if (!photon) {
330 std::cerr << m_className << "::GetCluster:\n"
331 << " Particle is neither an electron nor a photon.\n";
332 continue;
333 }
334 extra += photon->m_energy * 1.e6;
335 const double x = photon->position().x * 0.1 + m_cX;
336 const double y = photon->position().y * 0.1 + m_cY;
337 const double z = photon->position().z * 0.1 + m_cZ;
338 if (!IsInside(x, y, z)) continue;
339 // Transport the photon.
340 if (m_usePhotonReabsorption) photon->fly(newSecondaries);
341 }
342 for (auto secondary : secondaries)
343 if (secondary) delete secondary;
344 secondaries.clear();
345 secondaries.swap(newSecondaries);
346 }
347 // Get the total number of electrons produced in this step.
348 ne = m_doDeltaTransport ? m_conductionElectrons.size()
349 : m_deltaElectrons.size();
350 ni = m_conductionIons.size();
351 return true;
352}
353
354bool TrackHeed::GetElectron(const unsigned int i, double& x, double& y,
355 double& z, double& t, double& e, double& dx,
356 double& dy, double& dz) {
357 // Make sure NewTrack has successfully been called.
358 if (!m_ready) {
359 std::cerr << m_className << "::GetElectron:\n"
360 << " Track has not been initialized. Call NewTrack first.\n";
361 return false;
362 }
363
364 if (m_doDeltaTransport) {
365 // Make sure an electron with this number exists.
366 if (i >= m_conductionElectrons.size()) {
367 std::cerr << m_className << "::GetElectron: Index out of range.\n";
368 return false;
369 }
370
371 x = m_conductionElectrons[i].x * 0.1 + m_cX;
372 y = m_conductionElectrons[i].y * 0.1 + m_cY;
373 z = m_conductionElectrons[i].z * 0.1 + m_cZ;
374 t = m_conductionElectrons[i].time;
375 e = 0.;
376 dx = dy = dz = 0.;
377
378 } else {
379 // Make sure a delta electron with this number exists.
380 if (i >= m_deltaElectrons.size()) {
381 std::cerr << m_className << "::GetElectron:\n"
382 << " Delta electron number out of range.\n";
383 return false;
384 }
385
386 x = m_deltaElectrons[i].x;
387 y = m_deltaElectrons[i].y;
388 z = m_deltaElectrons[i].z;
389 t = m_deltaElectrons[i].t;
390 e = m_deltaElectrons[i].e;
391 dx = m_deltaElectrons[i].dx;
392 dy = m_deltaElectrons[i].dy;
393 dz = m_deltaElectrons[i].dz;
394 }
395 return true;
396}
397
398bool TrackHeed::GetIon(const unsigned int i, double& x, double& y, double& z,
399 double& t) const {
400 // Make sure a "conduction" ion with this number exists.
401 if (i >= m_conductionIons.size()) {
402 std::cerr << m_className << "::GetIon: Index out of range.\n";
403 return false;
404 }
405
406 x = m_conductionIons[i].x * 0.1 + m_cX;
407 y = m_conductionIons[i].y * 0.1 + m_cY;
408 z = m_conductionIons[i].z * 0.1 + m_cZ;
409 t = m_conductionIons[i].time;
410 return true;
411}
412
413void TrackHeed::TransportDeltaElectron(const double x0, const double y0,
414 const double z0, const double t0,
415 const double e0, const double dx0,
416 const double dy0, const double dz0,
417 int& nel) {
418 int ni = 0;
419 return TransportDeltaElectron(x0, y0, z0, t0, e0, dx0, dy0, dz0, nel, ni);
420}
421
422void TrackHeed::TransportDeltaElectron(const double x0, const double y0,
423 const double z0, const double t0,
424 const double e0, const double dx0,
425 const double dy0, const double dz0,
426 int& nel, int& ni) {
427 nel = 0;
428 ni = 0;
429
430 // Check if delta electron transport was disabled.
431 if (!m_doDeltaTransport) {
432 std::cerr << m_className << "::TransportDeltaElectron:\n"
433 << " Delta electron transport has been switched off.\n";
434 return;
435 }
436
437 // Make sure the sensor has been set.
438 if (!m_sensor) {
439 std::cerr << m_className << "::TransportDeltaElectron:\n"
440 << " Sensor is not defined.\n";
441 m_ready = false;
442 return;
443 }
444
445 bool update = false;
446 if (!UpdateBoundingBox(update)) return;
447
448 // Make sure the initial position is inside an ionisable medium.
449 Medium* medium = nullptr;
450 if (!m_sensor->GetMedium(x0, y0, z0, medium)) {
451 std::cerr << m_className << "::TransportDeltaElectron:\n"
452 << " No medium at initial position.\n";
453 return;
454 } else if (!medium->IsIonisable()) {
455 std::cerr << "TrackHeed:TransportDeltaElectron:\n"
456 << " Medium at initial position is not ionisable.\n";
457 m_ready = false;
458 return;
459 }
460
461 // Check if the medium has changed since the last call.
462 if (medium->GetName() != m_mediumName ||
463 fabs(medium->GetMassDensity() - m_mediumDensity) > 1.e-9) {
464 m_isChanged = true;
465 update = true;
466 m_ready = false;
467 m_hasActiveTrack = false;
468 }
469
470 // If medium or bounding box have changed, update the "chamber".
471 if (update) {
472 if (!Initialise(medium)) return;
473 m_ready = true;
474 m_mediumName = medium->GetName();
475 m_mediumDensity = medium->GetMassDensity();
476 }
477
478 m_deltaElectrons.clear();
479 m_conductionElectrons.clear();
480 m_conductionIons.clear();
481
482 // Initial position (shift with respect to bounding box center and
483 // convert from cm to mm).
484 Heed::point p0((x0 - m_cX) * 10., (y0 - m_cY) * 10., (z0 - m_cZ) * 10.);
485
486 // Make sure the kinetic energy is positive.
487 if (e0 <= 0.) {
488 // Just create a conduction electron on the spot.
489 m_conductionElectrons.emplace_back(Heed::HeedCondElectron(p0, t0));
490 nel = 1;
491 return;
492 }
493
494 // Check the direction vector.
495 double dx = dx0, dy = dy0, dz = dz0;
496 const double d = sqrt(dx * dx + dy * dy + dz * dz);
497 if (d <= 0.) {
498 // Null vector. Sample the direction isotropically.
499 RndmDirection(dx, dy, dz);
500 } else {
501 // Normalise the direction vector.
502 dx /= d;
503 dy /= d;
504 dz /= d;
505 }
506 Heed::vec velocity(dx, dy, dz);
507
508 // Calculate the speed for the given kinetic energy.
509 const double gamma = 1. + e0 / ElectronMass;
510 const double beta = sqrt(1. - 1. / (gamma * gamma));
511 double speed = Heed::CLHEP::c_light * beta;
512 velocity = velocity * speed;
513
514 // Transport the electron.
515 std::vector<Heed::gparticle*> secondaries;
516 Heed::HeedDeltaElectron delta(m_chamber.get(), p0, velocity, t0, 0,
517 m_fieldMap.get());
518 delta.fly(secondaries);
519 ClearBank(secondaries);
520
521 m_conductionElectrons.swap(delta.conduction_electrons);
522 m_conductionIons.swap(delta.conduction_ions);
523 nel = m_conductionElectrons.size();
524 ni = m_conductionIons.size();
525}
526
527void TrackHeed::TransportPhoton(const double x0, const double y0,
528 const double z0, const double t0,
529 const double e0, const double dx0,
530 const double dy0, const double dz0, int& nel) {
531 int ni = 0;
532 TransportPhoton(x0, y0, z0, t0, e0, dx0, dy0, dz0, nel, ni);
533}
534
535void TrackHeed::TransportPhoton(const double x0, const double y0,
536 const double z0, const double t0,
537 const double e0, const double dx0,
538 const double dy0, const double dz0, int& nel,
539 int& ni) {
540 nel = 0;
541 ni = 0;
542
543 // Make sure the energy is positive.
544 if (e0 <= 0.) {
545 std::cerr << m_className << "::TransportPhoton:\n"
546 << " Photon energy must be positive.\n";
547 return;
548 }
549
550 // Make sure the sensor has been set.
551 if (!m_sensor) {
552 std::cerr << m_className << "::TransportPhoton: Sensor is not defined.\n";
553 m_ready = false;
554 return;
555 }
556
557 bool update = false;
558 if (!UpdateBoundingBox(update)) return;
559
560 // Make sure the initial position is inside an ionisable medium.
561 Medium* medium = nullptr;
562 if (!m_sensor->GetMedium(x0, y0, z0, medium)) {
563 std::cerr << m_className << "::TransportPhoton:\n"
564 << " No medium at initial position.\n";
565 return;
566 } else if (!medium->IsIonisable()) {
567 std::cerr << "TrackHeed:TransportPhoton:\n"
568 << " Medium at initial position is not ionisable.\n";
569 m_ready = false;
570 return;
571 }
572
573 // Check if the medium has changed since the last call.
574 if (medium->GetName() != m_mediumName ||
575 fabs(medium->GetMassDensity() - m_mediumDensity) > 1.e-9) {
576 m_isChanged = true;
577 update = true;
578 m_ready = false;
579 }
580
581 // If medium or bounding box have changed, update the "chamber".
582 if (update) {
583 if (!Initialise(medium)) return;
584 m_ready = true;
585 m_mediumName = medium->GetName();
586 m_mediumDensity = medium->GetMassDensity();
587 }
588
589 // Delete the particle bank.
590 // Clusters from the current track will be lost.
591 m_hasActiveTrack = false;
592 ClearParticleBank();
593 m_deltaElectrons.clear();
594 m_conductionElectrons.clear();
595 m_conductionIons.clear();
596
597 // Check the direction vector.
598 double dx = dx0, dy = dy0, dz = dz0;
599 const double d = sqrt(dx * dx + dy * dy + dz * dz);
600 if (d <= 0.) {
601 // Null vector. Sample the direction isotropically.
602 RndmDirection(dx, dy, dz);
603 } else {
604 // Normalise the direction vector.
605 dx /= d;
606 dy /= d;
607 dz /= d;
608 }
609 Heed::vec velocity(dx, dy, dz);
610 velocity = velocity * Heed::CLHEP::c_light;
611
612 // Initial position (shift with respect to bounding box center and
613 // convert from cm to mm).
614 Heed::point p0((x0 - m_cX) * 10., (y0 - m_cY) * 10., (z0 - m_cZ) * 10.);
615
616 // Create and transport the photon.
617 Heed::HeedPhoton photon(m_chamber.get(), p0, velocity, t0, 0, e0 * 1.e-6,
618 m_fieldMap.get());
619 std::vector<Heed::gparticle*> secondaries;
620 photon.fly(secondaries);
621
622 while (!secondaries.empty()) {
623 std::vector<Heed::gparticle*> newSecondaries;
624 // Loop over the particle bank and look for daughter particles.
625 std::vector<Heed::gparticle*>::iterator it;
626 for (it = secondaries.begin(); it != secondaries.end(); ++it) {
627 // Check if it is a delta electron.
628 auto delta = dynamic_cast<Heed::HeedDeltaElectron*>(*it);
629 if (delta) {
630 if (m_doDeltaTransport) {
631 // Transport the delta electron.
632 delta->fly(newSecondaries);
633 // Add the conduction electrons to the list.
634 m_conductionElectrons.insert(m_conductionElectrons.end(),
635 delta->conduction_electrons.begin(),
636 delta->conduction_electrons.end());
637 m_conductionIons.insert(m_conductionIons.end(),
638 delta->conduction_ions.begin(),
639 delta->conduction_ions.end());
640 } else {
641 // Add the delta electron to the list, for later use.
642 deltaElectron newDeltaElectron;
643 newDeltaElectron.x = delta->position().x * 0.1 + m_cX;
644 newDeltaElectron.y = delta->position().y * 0.1 + m_cY;
645 newDeltaElectron.z = delta->position().z * 0.1 + m_cZ;
646 newDeltaElectron.t = delta->time();
647 newDeltaElectron.e = delta->kinetic_energy() * 1.e6;
648 newDeltaElectron.dx = delta->direction().x;
649 newDeltaElectron.dy = delta->direction().y;
650 newDeltaElectron.dz = delta->direction().z;
651 m_deltaElectrons.push_back(std::move(newDeltaElectron));
652 }
653 continue;
654 }
655 // Check if it is a fluorescence photon.
656 auto fluorescencePhoton = dynamic_cast<Heed::HeedPhoton*>(*it);
657 if (!fluorescencePhoton) {
658 std::cerr << m_className << "::TransportPhoton:\n"
659 << " Unknown secondary particle.\n";
660 ClearBank(secondaries);
661 ClearBank(newSecondaries);
662 return;
663 }
664 fluorescencePhoton->fly(newSecondaries);
665 }
666 secondaries.swap(newSecondaries);
667 ClearBank(newSecondaries);
668 }
669 ClearBank(secondaries);
670 // Get the total number of electrons produced in this step.
671 nel = m_doDeltaTransport ? m_conductionElectrons.size()
672 : m_deltaElectrons.size();
673 ni = m_conductionIons.size();
674}
675
676void TrackHeed::EnableElectricField() { m_fieldMap->UseEfield(true); }
677void TrackHeed::DisableElectricField() { m_fieldMap->UseEfield(false); }
678void TrackHeed::EnableMagneticField() { m_fieldMap->UseBfield(true); }
679void TrackHeed::DisableMagneticField() { m_fieldMap->UseBfield(false); }
680
681void TrackHeed::SetEnergyMesh(const double e0, const double e1,
682 const int nsteps) {
683 if (fabs(e1 - e0) < Small) {
684 std::cerr << m_className << "::SetEnergyMesh:\n"
685 << " Invalid energy range:\n"
686 << " " << e0 << " < E [eV] < " << e1 << "\n";
687 return;
688 }
689
690 if (nsteps <= 0) {
691 std::cerr << m_className << "::SetEnergyMesh:\n"
692 << " Number of intervals must be > 0.\n";
693 return;
694 }
695
696 m_emin = std::min(e0, e1);
697 m_emax = std::max(e0, e1);
698 m_emin *= 1.e-6;
699 m_emax *= 1.e-6;
700 m_nEnergyIntervals = nsteps;
701}
702
703void TrackHeed::SetParticleUser(const double m, const double z) {
704 if (fabs(z) < Small) {
705 std::cerr << m_className << "::SetParticleUser:\n"
706 << " Particle cannot have zero charge.\n";
707 return;
708 }
709 if (m < Small) {
710 std::cerr << m_className << "::SetParticleUser:\n"
711 << " Particle mass must be greater than zero.\n";
712 }
713 m_q = z;
714 m_mass = m;
715 m_isElectron = false;
716 m_spin = 0;
717 m_particleName = "exotic";
718}
719
721 // Make sure the path to the Heed database is known.
722 std::string databasePath;
723 char* dbPath = std::getenv("HEED_DATABASE");
724 if (dbPath == NULL) {
725 // Try GARFIELD_HOME.
726 dbPath = std::getenv("GARFIELD_HOME");
727 if (dbPath == NULL) {
728 std::cerr << m_className << "::Initialise:\n"
729 << " Cannot retrieve database path "
730 << "(environment variables HEED_DATABASE and GARFIELD_HOME "
731 << "are not defined).\n Cannot proceed.\n";
732 return false;
733 }
734 databasePath = std::string(dbPath) + "/Heed/heed++/database";
735 } else {
736 databasePath = dbPath;
737 }
738 if (databasePath[databasePath.size() - 1] != '/') {
739 databasePath.append("/");
740 }
741
742 // Check once more that the medium exists.
743 if (!medium) {
744 std::cerr << m_className << "::Initialise: Null pointer.\n";
745 return false;
746 }
747
748 // Setup the energy mesh.
749 m_energyMesh.reset(new Heed::EnergyMesh(m_emin, m_emax, m_nEnergyIntervals));
750
751 if (medium->IsGas()) {
752 if (!SetupGas(medium)) return false;
753 } else {
754 if (!SetupMaterial(medium)) return false;
755 }
756
757 // Energy transfer cross-section
758 // Set a flag indicating whether the primary particle is an electron.
759 m_transferCs.reset(new Heed::EnTransfCS(1.e-6 * m_mass, GetGamma() - 1.,
760 m_isElectron, m_matter.get(),
761 long(m_q)));
762
763 if (!SetupDelta(databasePath)) return false;
764
765 if (m_debug) {
766 const double nc = m_transferCs->quanC;
767 const double dedx = m_transferCs->meanC * 1.e3;
768 const double dedx1 = m_transferCs->meanC1 * 1.e3;
769 const double w = m_matter->W * 1.e6;
770 const double f = m_matter->F;
771 const double minI = m_matter->min_ioniz_pot * 1.e6;
772 std::cout << m_className << "::Initialise:\n";
773 std::cout << " Cluster density: " << nc << " cm-1\n";
774 std::cout << " Stopping power (restricted): " << dedx << " keV/cm\n";
775 std::cout << " Stopping power (incl. tail): " << dedx1 << " keV/cm\n";
776 std::cout << " W value: " << w << " eV\n";
777 std::cout << " Fano factor: " << f << "\n";
778 std::cout << " Min. ionization potential: " << minI << " eV\n";
779 }
780
781 Heed::fixsyscoor primSys(Heed::point(0., 0., 0.), Heed::basis("primary"),
782 "primary");
783 m_chamber.reset(new HeedChamber(primSys, m_lX, m_lY, m_lZ,
784 *m_transferCs.get(), *m_deltaCs.get()));
785 m_fieldMap->SetSensor(m_sensor);
786 return true;
787}
788
789bool TrackHeed::SetupGas(Medium* medium) {
790 // Get temperature and pressure.
791 double pressure = medium->GetPressure();
792 pressure = (pressure / AtmosphericPressure) * Heed::CLHEP::atmosphere;
793 double temperature = medium->GetTemperature();
794
795 const int nComponents = medium->GetNumberOfComponents();
796 if (nComponents < 1) {
797 std::cerr << m_className << "::SetupGas:\n";
798 std::cerr << " Gas " << medium->GetName() << " has zero constituents.\n";
799 return false;
800 }
801
802 std::vector<Heed::MolecPhotoAbsCS*> molPacs(nComponents, nullptr);
803 std::vector<std::string> notations;
804 std::vector<double> fractions;
805
806 for (int i = 0; i < nComponents; ++i) {
807 std::string gasname;
808 double frac;
809 medium->GetComponent(i, gasname, frac);
810 // If necessary, change the Magboltz name to the Heed internal name.
811 if (gasname == "He-3") gasname = "He";
812 if (gasname == "CD4") gasname = "CH4";
813 if (gasname == "iC4H10" || gasname == "nC4H10") gasname = "C4H10";
814 if (gasname == "neoC5H12" || gasname == "nC5H12") gasname = "C5H12";
815 if (gasname == "H2O") gasname = "Water";
816 if (gasname == "D2") gasname = "H2";
817 if (gasname == "cC3H6") gasname = "C3H6";
818 // Find the corresponding photoabsorption cross-section.
819 if (gasname == "CF4")
820 molPacs[i] = &Heed::CF4_MPACS;
821 else if (gasname == "Ar")
822 molPacs[i] = &Heed::Ar_MPACS;
823 else if (gasname == "He")
824 molPacs[i] = &Heed::He_MPACS;
825 else if (gasname == "Ne")
826 molPacs[i] = &Heed::Ne_MPACS;
827 else if (gasname == "Kr")
828 molPacs[i] = &Heed::Kr_MPACS;
829 else if (gasname == "Xe")
830 molPacs[i] = &Heed::Xe_MPACS;
831 else if (gasname == "CH4")
832 molPacs[i] = &Heed::CH4_MPACS;
833 else if (gasname == "C2H6")
834 molPacs[i] = &Heed::C2H6_MPACS;
835 else if (gasname == "C3H8")
836 molPacs[i] = &Heed::C3H8_MPACS;
837 else if (gasname == "C4H10")
838 molPacs[i] = &Heed::C4H10_MPACS;
839 else if (gasname == "CO2")
840 molPacs[i] = &Heed::CO2_MPACS;
841 else if (gasname == "C5H12")
842 molPacs[i] = &Heed::C5H12_MPACS;
843 else if (gasname == "Water")
844 molPacs[i] = &Heed::H2O_MPACS;
845 else if (gasname == "O2")
846 molPacs[i] = &Heed::O2_MPACS;
847 else if (gasname == "N2" || gasname == "N2 (Phelps)")
848 molPacs[i] = &Heed::N2_MPACS;
849 else if (gasname == "NO")
850 molPacs[i] = &Heed::NO_MPACS;
851 else if (gasname == "N2O")
852 molPacs[i] = &Heed::N2O_MPACS;
853 else if (gasname == "C2H4")
854 molPacs[i] = &Heed::C2H4_MPACS;
855 else if (gasname == "C2H2")
856 molPacs[i] = &Heed::C2H2_MPACS;
857 else if (gasname == "H2")
858 molPacs[i] = &Heed::H2_MPACS;
859 else if (gasname == "CO")
860 molPacs[i] = &Heed::CO_MPACS;
861 else if (gasname == "Methylal")
862 molPacs[i] = &Heed::Methylal_MPACS;
863 else if (gasname == "DME")
864 molPacs[i] = &Heed::DME_MPACS;
865 else if (gasname == "C2F6")
866 molPacs[i] = &Heed::C2F6_MPACS;
867 else if (gasname == "SF6")
868 molPacs[i] = &Heed::SF6_MPACS;
869 else if (gasname == "NH3")
870 molPacs[i] = &Heed::NH3_MPACS;
871 else if (gasname == "C3H6")
872 molPacs[i] = &Heed::C3H6_MPACS;
873 else if (gasname == "CH3OH")
874 molPacs[i] = &Heed::CH3OH_MPACS;
875 else if (gasname == "C2H5OH")
876 molPacs[i] = &Heed::C2H5OH_MPACS;
877 else if (gasname == "C3H7OH")
878 molPacs[i] = &Heed::C3H7OH_MPACS;
879 else if (gasname == "Cs")
880 molPacs[i] = &Heed::Cs_MPACS;
881 else if (gasname == "F2")
882 molPacs[i] = &Heed::F2_MPACS;
883 else if (gasname == "CS2")
884 molPacs[i] = &Heed::CS2_MPACS;
885 else if (gasname == "COS")
886 molPacs[i] = &Heed::COS_MPACS;
887 else if (gasname == "CD4")
888 molPacs[i] = &Heed::CH4_MPACS;
889 else if (gasname == "BF3")
890 molPacs[i] = &Heed::BF3_MPACS;
891 else if (gasname == "C2HF5")
892 molPacs[i] = &Heed::C2HF5_MPACS;
893 else if (gasname == "C2H2F4")
894 molPacs[i] = &Heed::C2H2F4_MPACS;
895 else if (gasname == "CHF3")
896 molPacs[i] = &Heed::CHF3_MPACS;
897 else if (gasname == "CF3Br")
898 molPacs[i] = &Heed::CF3Br_MPACS;
899 else if (gasname == "C3F8")
900 molPacs[i] = &Heed::C3F8_MPACS;
901 else if (gasname == "O3")
902 molPacs[i] = &Heed::O3_MPACS;
903 else if (gasname == "Hg")
904 molPacs[i] = &Heed::Hg_MPACS;
905 else if (gasname == "H2S")
906 molPacs[i] = &Heed::H2S_MPACS;
907 else if (gasname == "GeH4")
908 molPacs[i] = &Heed::GeH4_MPACS;
909 else if (gasname == "SiH4")
910 molPacs[i] = &Heed::SiH4_MPACS;
911 else {
912 std::cerr << m_className << "::SetupGas:\n Photoabsorption "
913 << "cross-section for " << gasname << " not available.\n";
914 return false;
915 }
916 notations.push_back(gasname);
917 fractions.push_back(frac);
918 }
919 if (m_usePacsOutput) {
920 std::ofstream pacsfile;
921 pacsfile.open("heed_pacs.txt", std::ios::out);
922 const int nValues = m_energyMesh->get_q();
923 if (nValues > 0) {
924 for (int i = 0; i < nValues; ++i) {
925 double e = m_energyMesh->get_e(i);
926 pacsfile << 1.e6 * e << " ";
927 for (int j = 0; j < nComponents; ++j) {
928 pacsfile << molPacs[j]->get_ACS(e) << " " << molPacs[j]->get_ICS(e)
929 << " ";
930 }
931 pacsfile << "\n";
932 }
933 }
934 pacsfile.close();
935 }
936
937 const std::string gasname = FindUnusedMaterialName(medium->GetName());
938 m_gas.reset(new Heed::GasDef(gasname, gasname, nComponents, notations,
939 fractions, pressure, temperature, -1.));
940
941 const double w = std::max(medium->GetW() * 1.e-6, 0.);
942 double f = medium->GetFanoFactor();
943 if (f <= 0.) f = Heed::standard_factor_Fano;
944
945 m_matter.reset(
946 new Heed::HeedMatterDef(m_energyMesh.get(), m_gas.get(), molPacs, w, f));
947
948 return true;
949}
950
951bool TrackHeed::SetupMaterial(Medium* medium) {
952 // Get temperature and density.
953 double temperature = medium->GetTemperature();
954 const double density =
955 medium->GetMassDensity() * Heed::CLHEP::gram / Heed::CLHEP::cm3;
956
957 const int nComponents = medium->GetNumberOfComponents();
958 std::vector<Heed::AtomPhotoAbsCS*> atPacs(nComponents, nullptr);
959
960 std::vector<std::string> notations;
961 std::vector<double> fractions;
962 for (int i = 0; i < nComponents; ++i) {
963 std::string materialName;
964 double frac;
965 medium->GetComponent(i, materialName, frac);
966 if (materialName == "C") {
967 if (medium->GetName() == "Diamond") {
968 atPacs[i] = &Heed::Diamond_PACS;
969 } else if (materialName == "Diamond") {
970 atPacs[i] = &Heed::Carbon_PACS;
971 }
972 } else if (materialName == "Si") {
973 atPacs[i] = &Heed::Silicon_crystal_PACS;
974 // atPacs[i] = &Heed::Silicon_G4_PACS;
975 } else if (materialName == "Ga") {
976 atPacs[i] = &Heed::Gallium_for_GaAs_PACS;
977 } else if (materialName == "Ge") {
978 atPacs[i] = &Heed::Germanium_PACS;
979 } else if (materialName == "As") {
980 atPacs[i] = &Heed::Arsenic_for_GaAs_PACS;
981 } else if (materialName == "Cd") {
982 atPacs[i] = &Heed::Cadmium_for_CdTe_PACS;
983 } else if (materialName == "Te") {
985 } else {
986 std::cerr << m_className << "::SetupMaterial:\n";
987 std::cerr << " Photoabsorption cross-section data for " << materialName
988 << " are not implemented.\n";
989 return false;
990 }
991 notations.push_back(materialName);
992 fractions.push_back(frac);
993 }
994 if (m_usePacsOutput) {
995 std::ofstream pacsfile;
996 pacsfile.open("heed_pacs.txt", std::ios::out);
997 const int nValues = m_energyMesh->get_q();
998 if (nValues > 0) {
999 for (int i = 0; i < nValues; ++i) {
1000 double e = m_energyMesh->get_e(i);
1001 pacsfile << 1.e6 * e << " ";
1002 for (int j = 0; j < nComponents; ++j) {
1003 pacsfile << atPacs[j]->get_ACS(e) << " " << atPacs[j]->get_ICS(e)
1004 << " ";
1005 }
1006 pacsfile << "\n";
1007 }
1008 }
1009 pacsfile.close();
1010 }
1011 const std::string materialName = FindUnusedMaterialName(medium->GetName());
1012 m_material.reset(new Heed::MatterDef(materialName, materialName, nComponents,
1013 notations, fractions, density,
1014 temperature));
1015
1016 double w = medium->GetW() * 1.e-6;
1017 if (w < 0.) w = 0.;
1018 double f = medium->GetFanoFactor();
1019 if (f <= 0.) f = Heed::standard_factor_Fano;
1020
1021 m_matter.reset(new Heed::HeedMatterDef(m_energyMesh.get(), m_material.get(),
1022 atPacs, w, f));
1023
1024 return true;
1025}
1026
1027bool TrackHeed::SetupDelta(const std::string& databasePath) {
1028 // Load elastic scattering data.
1029 std::string filename = databasePath + "cbdel.dat";
1030 m_elScat.reset(new Heed::ElElasticScat(filename));
1031
1032 filename = databasePath + "elastic_disp.dat";
1033 m_lowSigma.reset(new Heed::ElElasticScatLowSigma(m_elScat.get(), filename));
1034
1035 // Load data for calculation of ionization.
1036 // Get W value and Fano factor.
1037 const double w = m_matter->W * 1.e6;
1038 const double f = m_matter->F;
1039 filename = databasePath + "delta_path.dat";
1040 m_pairProd.reset(new Heed::PairProd(filename, w, f));
1041
1042 m_deltaCs.reset(new Heed::HeedDeltaElectronCS(
1043 m_matter.get(), m_elScat.get(), m_lowSigma.get(), m_pairProd.get()));
1044 return true;
1045}
1046
1047double TrackHeed::GetW() const { return m_matter->W * 1.e6; }
1048double TrackHeed::GetFanoFactor() const { return m_matter->F; }
1049
1050double TrackHeed::GetPhotoAbsorptionCrossSection(const double en) const {
1051
1052 if (!m_matter) return 0.;
1053 // Convert eV to MeV.
1054 const double e = 1.e-6 * en;
1055 double cs = 0.;
1056 const auto n = m_matter->apacs.size();
1057 for (size_t i = 0; i < n; ++i) {
1058 const double w = m_matter->matter->weight_quan(i);
1059 cs += m_matter->apacs[i]->get_ACS(e) * w;
1060 }
1061 // Convert Mbarn to cm-2.
1062 return cs * 1.e-18;
1063}
1064
1065std::string TrackHeed::FindUnusedMaterialName(const std::string& namein) {
1066 std::string nameout = namein;
1067 unsigned int counter = 0;
1068 while (Heed::MatterDef::get_MatterDef(nameout)) {
1069 nameout = namein + "_" + std::to_string(counter);
1070 ++counter;
1071 }
1072 return nameout;
1073}
1074
1075void TrackHeed::ClearParticleBank() {
1077 ClearBank(m_particleBank);
1078 m_bankIterator = m_particleBank.end();
1079}
1080
1081bool TrackHeed::IsInside(const double x, const double y, const double z) {
1082 // Check if the point is inside the drift area.
1083 if (!m_sensor->IsInArea(x, y, z)) return false;
1084 // Check if the point is inside a medium.
1085 Medium* medium = nullptr;
1086 if (!m_sensor->GetMedium(x, y, z, medium)) return false;
1087 // Make sure the medium has not changed.
1088 if (medium->GetName() != m_mediumName ||
1089 fabs(medium->GetMassDensity() - m_mediumDensity) > 1.e-9 ||
1090 !medium->IsIonisable()) {
1091 return false;
1092 }
1093 return true;
1094}
1095
1096bool TrackHeed::UpdateBoundingBox(bool& update) {
1097 // Get the bounding box.
1098 double xmin = 0., ymin = 0., zmin = 0.;
1099 double xmax = 0., ymax = 0., zmax = 0.;
1100 if (!m_sensor->GetArea(xmin, ymin, zmin, xmax, ymax, zmax)) {
1101 std::cerr << m_className << "::UpdateBoundingBox: Drift area is not set.\n";
1102 m_ready = false;
1103 return false;
1104 }
1105 // Check if the bounding box has changed.
1106 const double lx = fabs(xmax - xmin);
1107 const double ly = fabs(ymax - ymin);
1108 const double lz = fabs(zmax - zmin);
1109 if (m_debug) {
1110 std::cout << m_className << "::UpdateBoundingBox:\n"
1111 << " Bounding box dimensions:\n"
1112 << " x: " << lx << " cm\n"
1113 << " y: " << ly << " cm\n"
1114 << " z: " << lz << " cm\n";
1115 }
1116 if (fabs(lx - m_lX) > Small || fabs(ly - m_lY) > Small ||
1117 fabs(lz - m_lZ) > Small) {
1118 m_lX = lx;
1119 m_lY = ly;
1120 m_lZ = lz;
1121 m_isChanged = true;
1122 update = true;
1123 m_hasActiveTrack = false;
1124 }
1125 // Update the center of the bounding box.
1126 m_cX = (std::isinf(xmin) || std::isinf(xmax)) ? 0. : 0.5 * (xmin + xmax);
1127 m_cY = (std::isinf(ymin) || std::isinf(ymax)) ? 0. : 0.5 * (ymin + ymax);
1128 m_cZ = (std::isinf(zmin) || std::isinf(zmax)) ? 0. : 0.5 * (zmin + zmax);
1129 if (m_debug) {
1130 std::cout << m_className << "::UpdateBoundingBox:\n"
1131 << " Center of bounding box:\n"
1132 << " x: " << m_cX << " cm\n"
1133 << " y: " << m_cY << " cm\n"
1134 << " z: " << m_cZ << " cm\n";
1135 }
1136
1137 m_fieldMap->SetSensor(m_sensor);
1138 m_fieldMap->SetCentre(m_cX, m_cY, m_cZ);
1139
1140 return true;
1141}
1142}
Abstract base class for media.
Definition: Medium.hh:13
virtual void GetComponent(const unsigned int i, std::string &label, double &f)
Get the name and fraction of a given component.
Definition: Medium.cc:105
virtual double GetMassDensity() const
Get the mass density [g/cm3].
Definition: Medium.cc:101
double GetFanoFactor()
Get the Fano factor.
Definition: Medium.hh:87
double GetW()
Get the W value.
Definition: Medium.hh:83
double GetPressure() const
Definition: Medium.hh:38
unsigned int GetNumberOfComponents() const
Get number of components of the medium.
Definition: Medium.hh:45
const std::string & GetName() const
Get the medium name/identifier.
Definition: Medium.hh:23
virtual bool IsGas() const
Is this medium a gas?
Definition: Medium.hh:25
bool IsIonisable() const
Is charge deposition by charged particles/photon enabled in this medium?
Definition: Medium.hh:78
double GetTemperature() const
Get the temperature [K].
Definition: Medium.hh:34
bool IsInArea(const double x, const double y, const double z)
Check if a point is inside the user area.
Definition: Sensor.cc:254
bool GetMedium(const double x, const double y, const double z, Medium *&medium)
Get the medium at (x, y, z).
Definition: Sensor.cc:159
bool GetArea(double &xmin, double &ymin, double &zmin, double &xmax, double &ymax, double &zmax)
Return the current user area.
Definition: Sensor.cc:228
void EnableMagneticField()
Take the magnetic field into account in the stepping algorithm.
Definition: TrackHeed.cc:678
void SetEnergyMesh(const double e0, const double e1, const int nsteps)
Definition: TrackHeed.cc:681
bool GetCluster(double &xcls, double &ycls, double &zcls, double &tcls, int &n, double &e, double &extra) override
Definition: TrackHeed.cc:222
void EnableElectricField()
Take the electric field into account in the stepping algorithm.
Definition: TrackHeed.cc:676
void DisableMagneticField()
Do not take the magnetic field into account in the stepping algorithm.
Definition: TrackHeed.cc:679
double GetPhotoAbsorptionCrossSection(const double e) const
Return the photoabsorption cross-section at a given energy.
Definition: TrackHeed.cc:1050
void TransportDeltaElectron(const double x0, const double y0, const double z0, const double t0, const double e0, const double dx0, const double dy0, const double dz0, int &ne, int &ni)
Definition: TrackHeed.cc:422
double GetFanoFactor() const
Return the Fano factor of the medium (of the last simulated track).
Definition: TrackHeed.cc:1048
bool Initialise(Medium *medium)
Compute the differential cross-section for a given medium.
Definition: TrackHeed.cc:720
bool NewTrack(const double x0, const double y0, const double z0, const double t0, const double dx0, const double dy0, const double dz0) override
Definition: TrackHeed.cc:59
bool GetElectron(const unsigned int i, double &x, double &y, double &z, double &t, double &e, double &dx, double &dy, double &dz)
Definition: TrackHeed.cc:354
void TransportPhoton(const double x0, const double y0, const double z0, const double t0, const double e0, const double dx0, const double dy0, const double dz0, int &ne, int &ni)
Definition: TrackHeed.cc:535
bool GetIon(const unsigned int i, double &x, double &y, double &z, double &t) const
Definition: TrackHeed.cc:398
virtual ~TrackHeed()
Destructor.
Definition: TrackHeed.cc:57
TrackHeed()
Constructor.
Definition: TrackHeed.cc:49
double GetW() const
Return the W value of the medium (of the last simulated track).
Definition: TrackHeed.cc:1047
void SetParticleUser(const double m, const double z)
Definition: TrackHeed.cc:703
double GetClusterDensity() override
Definition: TrackHeed.cc:200
void DisableElectricField()
Do not take the electric field into account in the stepping algorithm.
Definition: TrackHeed.cc:677
double GetStoppingPower() override
Get the stopping power (mean energy loss [eV] per cm).
Definition: TrackHeed.cc:211
Abstract base class for track generation.
Definition: Track.hh:14
Sensor * m_sensor
Definition: Track.hh:112
bool m_debug
Definition: Track.hh:118
double GetBeta() const
Return the speed ( ) of the projectile.
Definition: Track.hh:54
double GetGamma() const
Return the Lorentz factor of the projectile.
Definition: Track.hh:56
bool m_isElectron
Definition: Track.hh:109
bool m_isChanged
Definition: Track.hh:114
double m_q
Definition: Track.hh:104
ViewDrift * m_viewer
Definition: Track.hh:116
std::string m_particleName
Definition: Track.hh:110
void PlotCluster(const double x0, const double y0, const double z0)
Definition: Track.cc:192
std::string m_className
Definition: Track.hh:102
double m_mass
Definition: Track.hh:106
void PlotNewTrack(const double x0, const double y0, const double z0)
Definition: Track.cc:187
std::vector< HeedCondElectron > conduction_electrons
std::vector< HeedCondElectron > conduction_ions
Retrieve electric and magnetic field from Sensor.
Definition: HeedFieldMap.h:15
double m_energy
Photon energy [MeV].
Definition: HeedPhoton.h:36
static MatterDef * get_MatterDef(const std::string &fnotation)
Definition: MatterDef.cpp:120
Basis.
Definition: vec.h:313
vfloat time() const
Get the current time of the particle.
Definition: gparticle.h:188
const vec & position() const
Get the current position of the particle.
Definition: gparticle.h:186
virtual void fly(std::vector< gparticle * > &secondaries)
Transport the particle.
Definition: gparticle.h:155
void set_step_limits(const vfloat fmax_range, const vfloat frad_for_straight, const vfloat fmax_straight_arange, const vfloat fmax_circ_arange)
Set limits/parameters for trajectory steps.
Definition: gparticle.h:175
double kinetic_energy() const
Get the current kinetic energy.
Definition: mparticle.h:34
void set_mass(const double m)
void set_charge(const double z)
Point.
Definition: vec.h:368
Definition: vec.h:179
vfloat x
Definition: vec.h:192
vfloat z
Definition: vec.h:194
vfloat y
Definition: vec.h:193
void RndmDirection(double &dx, double &dy, double &dz, const double length=1.)
Draw a random (isotropic) direction vector.
Definition: Random.hh:107
Definition: BGMesh.cpp:6
ExAtomPhotoAbsCS Gallium_for_GaAs_PACS(31, shelllist_dir_name+"shelllist_solid.dat", pacs_table_dir_name+"Ga.dat", "Ga_for_GaAs")
Definition: PhotoAbsCSLib.h:52
ExAtomPhotoAbsCS Tellurium_for_CdTe_PACS(52, shelllist_dir_name+"shelllist_solid.dat", pacs_table_dir_name+"Te.dat", "Te_for_CdTe")
Definition: PhotoAbsCSLib.h:62
MolecPhotoAbsCS C2H2_MPACS
MolecPhotoAbsCS Methylal_MPACS
particle_def pi_minus_meson_def("pi_minus_meson", "pi-", 139.56755 *MeV/c_squared, -eplus, 0, 0, 0.0, spin_def(1.0, -1.0))
Definition: particle_def.h:121
MolecPhotoAbsCS CH3OH_MPACS
particle_def pi_plus_meson_def("pi_plus_meson", "pi+", 139.56755 *MeV/c_squared, eplus, 0, 0, 0.0, spin_def(1.0, 1.0))
Definition: particle_def.h:119
MolecPhotoAbsCS CF4_MPACS
ExAtomPhotoAbsCS Silicon_crystal_PACS(14, shelllist_dir_name+"shelllist_solid.dat", pacs_table_dir_name+"Si.dat", "Si_crystal")
Definition: PhotoAbsCSLib.h:45
particle_def muon_minus_def("muon_minus", "mu-", 105.658367 *MeV/c_squared, electron_charge, 1, 0, 0.5, spin_def(0.0, 0.0))
Definition: particle_def.h:108
MolecPhotoAbsCS CS2_MPACS
MolecPhotoAbsCS NH3_MPACS
MolecPhotoAbsCS CF3Br_MPACS
long last_particle_number
Definition: HeedParticle.h:9
particle_def alpha_particle_def("alpha_particle", "alpha", 3727.417 *MeV/c_squared, 2 *eplus, 0, 4, 0.0, spin_def(0.0, 0.0))
Definition: particle_def.h:127
particle_def anti_proton_def("", "p-", proton_def)
Definition: particle_def.h:111
MolecPhotoAbsCS Cs_MPACS
MolecPhotoAbsCS C2H6_MPACS
MolecPhotoAbsCS O2_MPACS
particle_def deuteron_def("deuteron", "dtr", 1875.613 *MeV/c_squared, eplus, 0, 2, 0.0, spin_def(0.0, 0.0))
Definition: particle_def.h:126
MolecPhotoAbsCS SiH4_MPACS
particle_def proton_def("proton", "p+", proton_mass_c2/c_squared, eplus, 0, 1, 0.5, spin_def(0.5, 0.5))
Definition: particle_def.h:110
MolecPhotoAbsCS SF6_MPACS
MolecPhotoAbsCS F2_MPACS
MolecPhotoAbsCS C2H2F4_MPACS
MolecPhotoAbsCS H2O_MPACS
MolecPhotoAbsCS C2H4_MPACS
MolecPhotoAbsCS C2F6_MPACS
MolecPhotoAbsCS CO2_MPACS
MolecPhotoAbsCS O3_MPACS
MolecPhotoAbsCS N2_MPACS
MolecPhotoAbsCS Hg_MPACS
MolecPhotoAbsCS COS_MPACS
particle_def K_minus_meson_def("K_minus_meson_def", "K-", K_plus_meson_def)
Definition: particle_def.h:124
MolecPhotoAbsCS N2O_MPACS
MolecPhotoAbsCS Kr_MPACS
ExAtomPhotoAbsCS Arsenic_for_GaAs_PACS(33, shelllist_dir_name+"shelllist_solid.dat", pacs_table_dir_name+"As.dat", "As_for_GaAs")
Definition: PhotoAbsCSLib.h:56
MolecPhotoAbsCS He_MPACS
particle_def K_plus_meson_def("K_plus_meson_def", "K+", 493.677 *MeV/c_squared, 1, 0, 0, 0.0, spin_def(0.5, -0.5))
Definition: particle_def.h:123
MolecPhotoAbsCS C2HF5_MPACS
particle_def user_particle_def("user_particle", "X", 139.56755 *MeV/c_squared, eplus, 0, 0, 0.0, spin_def(0.0, 0.0))
Definition: particle_def.h:130
ExAtomPhotoAbsCS Germanium_PACS(32, shelllist_dir_name+"shelllist.dat", pacs_table_dir_name+"Ge.dat")
ExAtomPhotoAbsCS Cadmium_for_CdTe_PACS(48, shelllist_dir_name+"shelllist_solid.dat", pacs_table_dir_name+"Cd.dat", "Cd_for_CdTe")
Definition: PhotoAbsCSLib.h:60
DoubleAc fabs(const DoubleAc &f)
Definition: DoubleAc.h:615
MolecPhotoAbsCS BF3_MPACS
MolecPhotoAbsCS H2_MPACS
MolecPhotoAbsCS H2S_MPACS
particle_def muon_plus_def("muon_plus", "mu+", muon_minus_def)
Definition: particle_def.h:109
particle_def positron_def("positron", "e+", electron_def)
Definition: particle_def.h:107
MolecPhotoAbsCS DME_MPACS
particle_def electron_def("electron", "e-", electron_mass_c2/c_squared, electron_charge, 1, 0, 0.5, spin_def(0.0, 0.0))
Definition: particle_def.h:106
MolecPhotoAbsCS C3H7OH_MPACS
MolecPhotoAbsCS C3F8_MPACS
MolecPhotoAbsCS NO_MPACS
MolecPhotoAbsCS Ne_MPACS
MolecPhotoAbsCS C3H6_MPACS
MolecPhotoAbsCS C4H10_MPACS
MolecPhotoAbsCS Xe_MPACS
ExAtomPhotoAbsCS Carbon_PACS(6, shelllist_dir_name+"shelllist.dat", pacs_table_dir_name+"C.dat")
Definition: PhotoAbsCSLib.h:27
MolecPhotoAbsCS Ar_MPACS
MolecPhotoAbsCS C3H8_MPACS
constexpr double standard_factor_Fano
Definition: PhotoAbsCS.h:575
MolecPhotoAbsCS C5H12_MPACS
MolecPhotoAbsCS C2H5OH_MPACS
MolecPhotoAbsCS CHF3_MPACS
MolecPhotoAbsCS CH4_MPACS
MolecPhotoAbsCS CO_MPACS
ExAtomPhotoAbsCS Diamond_PACS(6, shelllist_dir_name+"shelllist_solid.dat", pacs_table_dir_name+"C.dat", "Diamond")
Definition: PhotoAbsCSLib.h:35
MolecPhotoAbsCS GeH4_MPACS