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