Garfield++ v1r0
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 "Sensor.hh"
19#include "ViewDrift.hh"
21#include "GarfieldConstants.hh"
22#include "Random.hh"
23#include "HeedChamber.hh"
24#include "TrackHeed.hh"
25
26namespace Garfield {
27
28namespace HeedInterface {
29
32
35}
36}
37
38// Global functions and variables required by Heed
39namespace Heed {
40
43
44void field_map(const point& pt, vec& efield, vec& bfield, vfloat& mrange) {
45
46 const double x = pt.v.x;
47 const double y = pt.v.y;
48 const double z = pt.v.z;
49
50 // Initialise the electric and magnetic field.
51 efield = vec(0., 0., 0.);
52 bfield = vec(0., 0., 0.);
53 mrange = DBL_MAX;
54
56 std::cerr << "TrackHeedGlobals::field_map:\n";
57 std::cerr << " Sensor pointer is null.\n";
58 return;
59 }
60
61 // TODO: check correct dimensions of E and B fields
63 double ex = 0., ey = 0., ez = 0.;
64 int status = 0;
66 x, y, z, ex, ey, ez, Garfield::HeedInterface::medium, status);
67 efield.x = ex * 1.e-5;
68 efield.y = ey * 1.e-5;
69 efield.z = ez * 1.e-5;
70 }
71
73 double bx = 0., by = 0., bz = 0.;
74 int status = 0;
75 Garfield::HeedInterface::sensor->MagneticField(x, y, z, bx, by, bz, status);
76 bfield.x = bx * 1.e-3;
77 bfield.y = by * 1.e-3;
78 bfield.z = bz * 1.e-3;
79 }
80}
81}
82
83// This function is called by Heed after each step
84void check_point(gparticle* /*gp*/) {}
85
86// Particle id number for book-keeping
87namespace Heed {
89}
91trajestep_limit gtrajlim(100. * Heed::cm, 1000. * Heed::cm, 0.1 * Heed::rad,
92 0.2 * Heed::rad);
93
94// Actual class implementation
95
96namespace Garfield {
97
99 : ready(false),
100 hasActiveTrack(false),
101 mediumDensity(-1.),
102 mediumName(""),
103 usePhotonReabsorption(true),
104 usePacsOutput(false),
105 useDelta(true),
106 nDeltas(0),
107 particle(0),
108 matter(0),
109 gas(0),
110 material(0),
111 m_atPacs(0),
112 m_molPacs(0),
113 emin(2.e-6),
114 emax(2.e-1),
115 nEnergyIntervals(200),
116 energyMesh(0),
117 transferCs(0),
118 elScat(0),
119 lowSigma(0),
120 pairProd(0),
121 deltaCs(0),
122 chamber(0),
123 lX(0.),
124 lY(0.),
125 lZ(0.),
126 cX(0.),
127 cY(0.),
128 cZ(0.) {
129
130 className = "TrackHeed";
131
135
136 deltaElectrons.clear();
137}
138
140
141 if (particle != 0) delete particle;
142 if (matter != 0) delete matter;
143 if (gas != 0) delete gas;
144 if (material != 0) delete material;
145 if (m_atPacs != 0) delete m_atPacs;
146 if (m_molPacs != 0) delete m_molPacs;
147 if (energyMesh != 0) delete energyMesh;
148 if (transferCs != 0) delete transferCs;
149 if (elScat != 0) delete elScat;
150 if (lowSigma != 0) delete lowSigma;
151 if (pairProd != 0) delete pairProd;
152 if (deltaCs != 0) delete deltaCs;
153 if (chamber != 0) delete chamber;
154
156}
157
158bool TrackHeed::NewTrack(const double x0, const double y0, const double z0,
159 const double t0, const double dx0, const double dy0,
160 const double dz0) {
161
162 hasActiveTrack = false;
163 ready = false;
164
165 // Make sure the sensor has been set.
166 if (sensor == 0) {
167 std::cerr << className << "::NewTrack:\n";
168 std::cerr << " Sensor is not defined.\n";
169 return false;
170 }
171
172 // Get the bounding box.
173 double xmin = 0., ymin = 0., zmin = 0.;
174 double xmax = 0., ymax = 0., zmax = 0.;
175 if (!sensor->GetArea(xmin, ymin, zmin, xmax, ymax, zmax)) {
176 std::cerr << className << "::NewTrack:\n";
177 std::cerr << " Drift area is not set.\n";
178 return false;
179 }
180 // Check if the bounding box has changed.
181 const double lx = fabs(xmax - xmin);
182 const double ly = fabs(ymax - ymin);
183 const double lz = fabs(zmax - zmin);
184 if (debug) {
185 std::cout << className << "::NewTrack:\n";
186 std::cout << " Bounding box dimensions:\n";
187 std::cout << " x: " << lx << " cm\n";
188 std::cout << " y: " << ly << " cm\n";
189 std::cout << " z: " << lz << " cm\n";
190 }
191 if (fabs(lx - lX) > Small || fabs(ly - lY) > Small || fabs(lz - lZ) > Small) {
192 lX = lx;
193 lY = ly;
194 lZ = lz;
195 isChanged = true;
196 }
197 // Update the center of the bounding box.
198 if (std::isinf(xmin) || std::isinf(xmax)) {
199 cX = 0.;
200 } else {
201 cX = 0.5 * (xmin + xmax);
202 }
203 if (std::isinf(ymin) || std::isinf(ymax)) {
204 cY = 0.;
205 } else {
206 cY = 0.5 * (ymin + ymax);
207 }
208 if (std::isinf(zmin) || std::isinf(zmax)) {
209 cZ = 0.;
210 } else {
211 cZ = 0.5 * (zmin + zmax);
212 }
213 if (debug) {
214 std::cout << className << "::NewTrack:\n";
215 std::cout << " Center of bounding box:\n";
216 std::cout << " x: " << cX << " cm\n";
217 std::cout << " y: " << cY << " cm\n";
218 std::cout << " z: " << cZ << " cm\n";
219 }
220
222
223 // Make sure the initial position is inside an ionisable medium.
224 Medium* medium;
225 if (!sensor->GetMedium(x0, y0, z0, medium)) {
226 std::cerr << className << "::NewTrack:\n";
227 std::cerr << " No medium at initial position.\n";
228 return false;
229 } else if (!medium->IsIonisable()) {
230 std::cerr << "TrackHeed:NewTrack:\n";
231 std::cerr << " Medium at initial position is not ionisable.\n";
232 return false;
233 }
234
235 // Check if the medium has changed since the last call.
236 if (medium->GetName() != mediumName ||
237 fabs(medium->GetMassDensity() - mediumDensity) > 1.e-9) {
238 isChanged = true;
239 }
240
241 // If medium, particle or bounding box have changed,
242 // update the cross-sections.
243 if (isChanged) {
244 if (!Setup(medium)) return false;
245 isChanged = false;
246 mediumName = medium->GetName();
247 mediumDensity = medium->GetMassDensity();
248 }
249
250 Heed::particle_bank.clear();
251 deltaElectrons.clear();
252 Heed::cluster_bank.allocate_block(100);
253 chamber->conduction_electron_bank.allocate_block(1000);
254
255 // Check the direction vector.
256 double dx = dx0, dy = dy0, dz = dz0;
257 const double d = sqrt(dx * dx + dy * dy + dz * dz);
258 if (d < Small) {
259 if (debug) {
260 std::cout << className << "::NewTrack:\n";
261 std::cout << " Direction vector has zero norm.\n";
262 std::cout << " Initial direction is randomized.\n";
263 }
264 // Null vector. Sample the direction isotropically.
265 const double ctheta = 1. - 2. * RndmUniform();
266 const double stheta = sqrt(1. - ctheta * ctheta);
267 const double phi = TwoPi * RndmUniform();
268 dx = cos(phi) * stheta;
269 dy = sin(phi) * stheta;
270 dz = ctheta;
271 } else {
272 // Normalise the direction vector.
273 dx /= d;
274 dy /= d;
275 dz /= d;
276 }
277 vec velocity(dx, dy, dz);
278 velocity = velocity * Heed::c_light * GetBeta();
279
280 if (debug) {
281 std::cout << className << "::NewTrack:\n";
282 std::cout << " Track starts at (" << x0 << ", " << y0 << ", " << z0
283 << ") at time " << t0 << "\n";
284 std::cout << " Initial direction: (" << dx << ", " << dy << ", " << dz
285 << ")\n";
286 }
287
288 // Initial position (shift with respect to bounding box center and
289 // convert from cm to mm).
290 point p0((x0 - cX) * 10., (y0 - cY) * 10., (z0 - cZ) * 10.);
291 // Setup the particle.
293 if (particle != 0) {
294 delete particle;
295 particle = 0;
296 }
297
299 if (particleName == "e-") {
300 particleType = &Heed::electron_def;
301 } else if (particleName == "e+") {
302 particleType = &Heed::positron_def;
303 } else if (particleName == "mu-") {
304 particleType = &Heed::muon_minus_def;
305 } else if (particleName == "mu+") {
306 particleType = &Heed::muon_plus_def;
307 } else if (particleName == "pi-") {
308 particleType = &Heed::pi_minus_meson_def;
309 } else if (particleName == "pi+") {
310 particleType = &Heed::pi_plus_meson_def;
311 } else if (particleName == "K-") {
312 particleType = &Heed::K_minus_meson_def;
313 } else if (particleName == "K+") {
314 particleType = &Heed::K_plus_meson_def;
315 } else if (particleName == "p") {
316 particleType = &Heed::proton_def;
317 } else if (particleName == "pbar") {
318 particleType = &Heed::anti_proton_def;
319 } else if (particleName == "d") {
320 particleType = &Heed::deuteron_def;
321 } else if (particleName == "alpha") {
322 particleType = &Heed::alpha_particle_def;
323 } else if (particleName == "exotic") {
324 // User defined particle
327 particleType = &Heed::user_particle_def;
328 } else {
329 // Not a predefined particle, use muon definition.
330 if (q > 0.) {
331 particleType = &Heed::muon_minus_def;
332 } else {
333 particleType = &Heed::muon_plus_def;
334 }
335 }
336
337 particle = new Heed::HeedParticle(chamber, p0, velocity, t0, particleType);
338 // Transport the particle.
339 particle->fly();
340 hasActiveTrack = true;
341 ready = true;
342
343 // Plot the new track.
344 if (usePlotting) PlotNewTrack(x0, y0, z0);
345
346 return true;
347}
348
350
351 if (!ready) {
352 std::cerr << className << "::GetClusterDensity:\n";
353 std::cerr << " Track has not been initialized.\n";
354 return 0.;
355 }
356
357 if (transferCs == 0) {
358 std::cerr << className << "::GetClusterDensity:\n";
359 std::cerr << " Ionisation cross-section is not available.\n";
360 return 0.;
361 }
362
363 return transferCs->quanC;
364}
365
367
368 if (!ready) {
369 std::cerr << className << "::GetStoppingPower:\n";
370 std::cerr << " Track has not been initialized.\n";
371 return 0.;
372 }
373
374 if (transferCs == 0) {
375 std::cerr << className << "::GetStoppingPower:\n";
376 std::cerr << " Ionisation cross-section is not available.\n";
377 return 0.;
378 }
379
380 return transferCs->meanC1 * 1.e6;
381}
382
383bool TrackHeed::GetCluster(double& xcls, double& ycls, double& zcls,
384 double& tcls, int& n, double& e, double& extra) {
385
386 // Initial settings.
387 xcls = ycls = zcls = tcls = 0.;
388 extra = 0.;
389 n = 0;
390 e = 0.;
391
392 // Make sure NewTrack has successfully been called.
393 if (!ready) {
394 std::cerr << className << "::GetCluster:\n";
395 std::cerr << " Track has not been initialized.\n";
396 std::cerr << " Call NewTrack first.\n";
397 return false;
398 }
399
400 if (!hasActiveTrack) {
401 std::cerr << className << "::GetCluster:\n";
402 std::cerr << " There are no more clusters.\n";
403 return false;
404 }
405
406 bool ok = false;
407 Medium* medium = 0;
409 Heed::HeedPhoton* virtualPhoton = 0;
410 while (!ok) {
411 // Get the first element from the particle bank.
412 node = Heed::particle_bank.get_first_node();
413
414 // Make sure the particle bank is not empty.
415 if (node == 0) {
416 hasActiveTrack = false;
417 return false;
418 }
419
420 // Convert the particle to a (virtual) photon.
421 virtualPhoton = dynamic_cast<Heed::HeedPhoton*>(node->el.get());
422 if (virtualPhoton == 0) {
423 std::cerr << className << "::GetCluster:\n";
424 std::cerr << " Particle is not a virtual photon.\n";
425 std::cerr << " Program bug!\n";
426 // Delete the node.
427 Heed::particle_bank.erase(node);
428 // Try the next node.
429 continue;
430 }
431
432 if (virtualPhoton->parent_particle_number != 0) {
433 std::cerr << className << "::GetCluster:\n";
434 std::cerr << " Virtual photon has an unexpected parent.\n";
435 // Delete this virtual photon.
436 Heed::particle_bank.erase(node);
437 continue;
438 }
439 // Get the location of the interaction (convert from mm to cm
440 // and shift with respect to bounding box center).
441 xcls = virtualPhoton->currpos.pt.v.x * 0.1 + cX;
442 ycls = virtualPhoton->currpos.pt.v.y * 0.1 + cY;
443 zcls = virtualPhoton->currpos.pt.v.z * 0.1 + cZ;
444 tcls = virtualPhoton->currpos.time;
445 // Make sure the cluster is inside the drift area.
446 if (!sensor->IsInArea(xcls, ycls, zcls)) {
447 // Delete this virtual photon and proceed with the next one.
448 Heed::particle_bank.erase(node);
449 continue;
450 }
451 // Make sure the cluster is inside a medium.
452 if (!sensor->GetMedium(xcls, ycls, zcls, medium)) {
453 // Delete this virtual photon and proceed with the next one.
454 Heed::particle_bank.erase(node);
455 continue;
456 }
457 // Make sure the medium has not changed.
458 if (medium->GetName() != mediumName ||
459 fabs(medium->GetMassDensity() - mediumDensity) > 1.e-9 ||
460 !medium->IsIonisable()) {
461 // Delete this virtual photon and proceed with the next one.
462 Heed::particle_bank.erase(node);
463 continue;
464 }
465 // Seems to be ok.
466 ok = true;
467 }
468
469 // Plot the cluster, if requested.
470 if (usePlotting) PlotCluster(xcls, ycls, zcls);
471
472 // Transport the virtual photon.
473 virtualPhoton->fly();
474 // Get the transferred energy (convert from MeV to eV).
475 e = virtualPhoton->energy * 1.e6;
476
477 // Make a list of parent particle id numbers.
478 std::vector<int> ids;
479 ids.clear();
480 // At the beginning, there is only the virtual photon.
481 ids.push_back(virtualPhoton->particle_number);
482 int nIds = 1;
483
484 // Look for daughter particles.
485 deltaElectrons.clear();
486 nDeltas = 0;
487 chamber->conduction_electron_bank.allocate_block(1000);
488 bool deleteNode = false;
489 Heed::HeedDeltaElectron* delta = 0;
490 Heed::HeedPhoton* photon = 0;
492 AbsListNode<ActivePtr<gparticle> >* tempNode = 0;
493 // Loop over the particle bank.
494 while (nextNode != 0) {
495 deleteNode = false;
496 // Check if it is a delta electron.
497 delta = dynamic_cast<Heed::HeedDeltaElectron*>(nextNode->el.get());
498 if (delta != 0) {
499 // Check if the delta electron was produced by one of the photons
500 // belonging to this cluster.
501 for (int i = nIds; i--;) {
502 if (delta->parent_particle_number == ids[i]) {
503 if (useDelta) {
504 // Transport the delta electron.
505 delta->fly();
506 } else {
507 // Add the delta electron to the list, for later use.
508 deltaElectron newDeltaElectron;
509 newDeltaElectron.x = delta->currpos.pt.v.x * 0.1 + cX;
510 newDeltaElectron.y = delta->currpos.pt.v.y * 0.1 + cY;
511 newDeltaElectron.z = delta->currpos.pt.v.z * 0.1 + cZ;
512 newDeltaElectron.t = delta->currpos.time;
513 newDeltaElectron.e = delta->curr_kin_energy * 1.e6;
514 newDeltaElectron.dx = delta->currpos.dir.x;
515 newDeltaElectron.dy = delta->currpos.dir.y;
516 newDeltaElectron.dz = delta->currpos.dir.z;
517 deltaElectrons.push_back(newDeltaElectron);
518 ++nDeltas;
519 }
520 deleteNode = true;
521 break;
522 }
523 }
524 } else {
525 // Check if it is a real photon.
526 photon = dynamic_cast<Heed::HeedPhoton*>(nextNode->el.get());
527 if (photon == 0) {
528 std::cerr << className << "::GetCluster:\n";
529 std::cerr << " Particle is neither an electron nor a photon.\n";
530 return false;
531 }
532 for (int i = nIds; i--;) {
533 if (photon->parent_particle_number == ids[i]) {
534 // Transport the photon and add its number to the list of ids.
535 if (usePhotonReabsorption) photon->fly();
536 deleteNode = true;
537 ids.push_back(photon->particle_number);
538 ++nIds;
539 break;
540 }
541 }
542 }
543 // Proceed with the next node in the particle bank.
544 if (deleteNode) {
545 tempNode = nextNode->get_next_node();
546 Heed::particle_bank.erase(nextNode);
547 nextNode = tempNode;
548 } else {
549 nextNode = nextNode->get_next_node();
550 }
551 }
552
553 // Get the total number of electrons produced in this step.
554 if (useDelta) {
555 n = chamber->conduction_electron_bank.get_qel();
556 } else {
557 n = nDeltas;
558 }
559
560 // Remove the virtual photon from the particle bank.
561 Heed::particle_bank.erase(node);
562
563 return true;
564}
565
566bool TrackHeed::GetElectron(const int i, double& x, double& y, double& z,
567 double& t, double& e, double& dx, double& dy,
568 double& dz) {
569
570 // Make sure NewTrack has successfully been called.
571 if (!ready) {
572 std::cerr << className << "::GetElectron:\n";
573 std::cerr << " Track has not been initialized.\n";
574 std::cerr << " Call NewTrack first.\n";
575 return false;
576 }
577
578 if (useDelta) {
579 // Make sure an electron with this number exists.
580 const int n = chamber->conduction_electron_bank.get_qel();
581 if (i < 0 || i >= n) {
582 std::cerr << className << "::GetElectron:\n";
583 std::cerr << " Electron number out of range.\n";
584 return false;
585 }
586
587 x = chamber->conduction_electron_bank[i].ptloc.v.x * 0.1 + cX;
588 y = chamber->conduction_electron_bank[i].ptloc.v.y * 0.1 + cY;
589 z = chamber->conduction_electron_bank[i].ptloc.v.z * 0.1 + cZ;
590 t = chamber->conduction_electron_bank[i].time;
591 e = 0.;
592 dx = dy = dz = 0.;
593
594 } else {
595 // Make sure a delta electron with this number exists.
596 if (i < 0 || i >= nDeltas) {
597 std::cerr << className << "::GetElectron:\n";
598 std::cerr << " Delta electron number out of range.\n";
599 return false;
600 }
601
602 x = deltaElectrons[i].x;
603 y = deltaElectrons[i].y;
604 z = deltaElectrons[i].z;
605 t = deltaElectrons[i].t;
606 e = deltaElectrons[i].e;
607 dx = deltaElectrons[i].dx;
608 dy = deltaElectrons[i].dy;
609 dz = deltaElectrons[i].dz;
610 }
611
612 return true;
613}
614
615void TrackHeed::TransportDeltaElectron(const double x0, const double y0,
616 const double z0, const double t0,
617 const double e0, const double dx0,
618 const double dy0, const double dz0,
619 int& nel) {
620
621 nel = 0;
622
623 // Check if delta electron transport was disabled.
624 if (!useDelta) {
625 std::cerr << className << "::TransportDeltaElectron:\n";
626 std::cerr << " Delta electron transport has been switched off.\n";
627 return;
628 }
629
630 // Make sure the kinetic energy is positive.
631 if (e0 <= 0.) {
632 std::cerr << className << "::TransportDeltaElectron:\n";
633 std::cerr << " Kinetic energy must be positive.\n";
634 return;
635 }
636
637 // Make sure the sensor has been set.
638 if (sensor == 0) {
639 std::cerr << className << "::TransportDeltaElectron:\n";
640 std::cerr << " Sensor is not defined.\n";
641 ready = false;
642 return;
643 }
644
645 // Get the bounding box.
646 double xmin, ymin, zmin;
647 double xmax, ymax, zmax;
648 if (!sensor->GetArea(xmin, ymin, zmin, xmax, ymax, zmax)) {
649 std::cerr << className << "::TransportDeltaElectron:\n";
650 std::cerr << " Drift area is not set.\n";
651 ready = false;
652 return;
653 }
654 // Check if the bounding box has changed.
655 bool update = false;
656 const double lx = fabs(xmax - xmin);
657 const double ly = fabs(ymax - ymin);
658 const double lz = fabs(zmax - zmin);
659 if (fabs(lx - lX) > Small || fabs(ly - lY) > Small || fabs(lz - lZ) > Small) {
660 lX = lx;
661 lY = ly;
662 lZ = lz;
663 isChanged = true;
664 update = true;
665 hasActiveTrack = false;
666 }
667 // Update the center of the bounding box.
668 cX = 0.5 * (xmin + xmax);
669 cY = 0.5 * (ymin + ymax);
670 cZ = 0.5 * (zmin + zmax);
671
673
674 // Make sure the initial position is inside an ionisable medium.
675 Medium* medium;
676 if (!sensor->GetMedium(x0, y0, z0, medium)) {
677 std::cerr << className << "::TransportDeltaElectron:\n";
678 std::cerr << " No medium at initial position.\n";
679 return;
680 } else if (!medium->IsIonisable()) {
681 std::cerr << "TrackHeed:TransportDeltaElectron:\n";
682 std::cerr << " Medium at initial position is not ionisable.\n";
683 ready = false;
684 return;
685 }
686
687 // Check if the medium has changed since the last call.
688 if (medium->GetName() != mediumName ||
689 fabs(medium->GetMassDensity() - mediumDensity) > 1.e-9) {
690 isChanged = true;
691 update = true;
692 ready = false;
693 hasActiveTrack = false;
694 }
695
696 // If medium or bounding box have changed, update the "chamber".
697 if (update) {
698 if (!Setup(medium)) return;
699 ready = true;
700 mediumName = medium->GetName();
701 mediumDensity = medium->GetMassDensity();
702 }
703
704 deltaElectrons.clear();
705 chamber->conduction_electron_bank.allocate_block(1000);
706
707 // Check the direction vector.
708 double dx = dx0, dy = dy0, dz = dz0;
709 const double d = sqrt(dx * dx + dy * dy + dz * dz);
710 if (d <= 0.) {
711 // Null vector. Sample the direction isotropically.
712 const double phi = TwoPi * RndmUniform();
713 const double ctheta = 1. - 2. * RndmUniform();
714 const double stheta = sqrt(1. - ctheta * ctheta);
715 dx = cos(phi) * stheta;
716 dy = sin(phi) * stheta;
717 dz = ctheta;
718 } else {
719 // Normalise the direction vector.
720 dx /= d;
721 dy /= d;
722 dz /= d;
723 }
724 vec velocity(dx, dy, dz);
725
726 // Calculate the speed for the given kinetic energy.
727 const double gamma = 1. + e0 / ElectronMass;
728 const double beta = sqrt(1. - 1. / (gamma * gamma));
729 double speed = Heed::c_light * beta;
730 velocity = velocity * speed;
731
732 // Initial position (shift with respect to bounding box center and
733 // convert from cm to mm).
734 point p0((x0 - cX) * 10., (y0 - cY) * 10., (z0 - cZ) * 10.);
735
736 // Transport the electron.
737 Heed::HeedDeltaElectron delta(chamber, p0, velocity, t0, 0);
738 delta.fly();
739
740 nel = chamber->conduction_electron_bank.get_qel();
741}
742
743void TrackHeed::TransportPhoton(const double x0, const double y0,
744 const double z0, const double t0,
745 const double e0, const double dx0,
746 const double dy0, const double dz0, int& nel) {
747
748 nel = 0;
749
750 // Make sure the energy is positive.
751 if (e0 <= 0.) {
752 std::cerr << className << "::TransportPhoton:\n";
753 std::cerr << " Photon energy must be positive.\n";
754 return;
755 }
756
757 // Make sure the sensor has been set.
758 if (sensor == 0) {
759 std::cerr << className << "::TransportPhoton:\n";
760 std::cerr << " Sensor is not defined.\n";
761 ready = false;
762 return;
763 }
764
765 // Get the bounding box.
766 double xmin, ymin, zmin;
767 double xmax, ymax, zmax;
768 if (!sensor->GetArea(xmin, ymin, zmin, xmax, ymax, zmax)) {
769 std::cerr << className << "::TransportPhoton:\n";
770 std::cerr << " Drift area is not set.\n";
771 ready = false;
772 return;
773 }
774 // Check if the bounding box has changed.
775 bool update = false;
776 const double lx = fabs(xmax - xmin);
777 const double ly = fabs(ymax - ymin);
778 const double lz = fabs(zmax - zmin);
779 if (fabs(lx - lX) > Small || fabs(ly - lY) > Small || fabs(lz - lZ) > Small) {
780 lX = lx;
781 lY = ly;
782 lZ = lz;
783 isChanged = true;
784 update = true;
785 hasActiveTrack = false;
786 }
787 // Update the center of the bounding box.
788 cX = 0.5 * (xmin + xmax);
789 cY = 0.5 * (ymin + ymax);
790 cZ = 0.5 * (zmin + zmax);
791
793
794 // Make sure the initial position is inside an ionisable medium.
795 Medium* medium;
796 if (!sensor->GetMedium(x0, y0, z0, medium)) {
797 std::cerr << className << "::TransportPhoton:\n";
798 std::cerr << " No medium at initial position.\n";
799 return;
800 } else if (!medium->IsIonisable()) {
801 std::cerr << "TrackHeed:TransportPhoton:\n";
802 std::cerr << " Medium at initial position is not ionisable.\n";
803 ready = false;
804 return;
805 }
806
807 // Check if the medium has changed since the last call.
808 if (medium->GetName() != mediumName ||
809 fabs(medium->GetMassDensity() - mediumDensity) > 1.e-9) {
810 isChanged = true;
811 update = true;
812 ready = false;
813 }
814
815 // If medium or bounding box have changed, update the "chamber".
816 if (update) {
817 if (!Setup(medium)) return;
818 ready = true;
819 mediumName = medium->GetName();
820 mediumDensity = medium->GetMassDensity();
821 }
822
823 // Delete the particle bank.
824 // Clusters from the current track will be lost.
825 hasActiveTrack = false;
827 Heed::particle_bank.clear();
828 deltaElectrons.clear();
829 nDeltas = 0;
830 chamber->conduction_electron_bank.allocate_block(1000);
831
832 // Check the direction vector.
833 double dx = dx0, dy = dy0, dz = dz0;
834 const double d = sqrt(dx * dx + dy * dy + dz * dz);
835 if (d <= 0.) {
836 // Null vector. Sample the direction isotropically.
837 const double phi = TwoPi * RndmUniform();
838 const double ctheta = 1. - 2. * RndmUniform();
839 const double stheta = sqrt(1. - ctheta * ctheta);
840 dx = cos(phi) * stheta;
841 dy = sin(phi) * stheta;
842 dz = ctheta;
843 } else {
844 // Normalise the direction vector.
845 dx /= d;
846 dy /= d;
847 dz /= d;
848 }
849 vec velocity(dx, dy, dz);
850 velocity = velocity * Heed::c_light;
851
852 // Initial position (shift with respect to bounding box center and
853 // convert from cm to mm).
854 point p0((x0 - cX) * 10., (y0 - cY) * 10., (z0 - cZ) * 10.);
855
856 // Create and transport the photon.
857 Heed::HeedPhoton photon(chamber, p0, velocity, t0, 0, e0 * 1.e-6, 0);
858 photon.fly();
859
860 // Make a list of parent particle id numbers.
861 std::vector<int> ids;
862 ids.clear();
863 // At the beginning, there is only the original photon.
864 ids.push_back(photon.particle_number);
865 int nIds = 1;
866
867 // Look for daughter particles.
868 Heed::HeedDeltaElectron* delta = 0;
869 Heed::HeedPhoton* fluorescencePhoton = 0;
870
871 // Get the first element from the particle bank.
873 Heed::particle_bank.get_first_node();
874 AbsListNode<ActivePtr<gparticle> >* tempNode = 0;
875 // Loop over the particle bank.
876 while (nextNode != 0) {
877 // Check if it is a delta electron.
878 delta = dynamic_cast<Heed::HeedDeltaElectron*>(nextNode->el.get());
879 if (delta != 0) {
880 // Check if the delta electron was produced by one of the photons
881 // belonging to this cluster.
882 bool gotParent = false;
883 for (int i = nIds; i--;) {
884 if (delta->parent_particle_number == ids[i]) {
885 gotParent = true;
886 if (useDelta) {
887 // Transport the delta electron.
888 delta->fly();
889 } else {
890 // Add the delta electron to the list, for later use.
891 deltaElectron newDeltaElectron;
892 newDeltaElectron.x = delta->currpos.pt.v.x * 0.1 + cX;
893 newDeltaElectron.y = delta->currpos.pt.v.y * 0.1 + cY;
894 newDeltaElectron.z = delta->currpos.pt.v.z * 0.1 + cZ;
895 newDeltaElectron.t = delta->currpos.time;
896 newDeltaElectron.e = delta->curr_kin_energy * 1.e6;
897 newDeltaElectron.dx = delta->currpos.dir.x;
898 newDeltaElectron.dy = delta->currpos.dir.y;
899 newDeltaElectron.dz = delta->currpos.dir.z;
900 deltaElectrons.push_back(newDeltaElectron);
901 ++nDeltas;
902 }
903 break;
904 }
905 }
906 if (!gotParent) {
907 std::cerr << className << "::TransportPhoton:\n";
908 std::cerr << " Delta electron with unknown parent.\n";
909 }
910 } else {
911 // Check if it is a fluorescence photon.
912 fluorescencePhoton = dynamic_cast<Heed::HeedPhoton*>(nextNode->el.get());
913 if (fluorescencePhoton == 0) {
914 std::cerr << className << "::TransportPhoton:\n";
915 std::cerr << " Unknown secondary particle.\n";
916 return;
917 }
918 for (int i = nIds; i--;) {
919 if (fluorescencePhoton->parent_particle_number == ids[i]) {
920 // Transport the photon and add its number to the list of ids.
921 fluorescencePhoton->fly();
922 ids.push_back(fluorescencePhoton->particle_number);
923 ++nIds;
924 break;
925 }
926 }
927 }
928 // Proceed with the next node in the particle bank.
929 tempNode = nextNode->get_next_node();
930 Heed::particle_bank.erase(nextNode);
931 nextNode = tempNode;
932 }
933
934 // Get the total number of electrons produced in this step.
935 if (useDelta) {
936 nel = chamber->conduction_electron_bank.get_qel();
937 } else {
938 nel = nDeltas;
939 }
940}
941
943
945
947
949
950void TrackHeed::SetEnergyMesh(const double e0, const double e1,
951 const int nsteps) {
952
953 if (fabs(e1 - e0) < Small) {
954 std::cerr << className << "::SetEnergyMesh:\n";
955 std::cerr << " Invalid energy range:\n";
956 std::cerr << " " << e0 << " < E [eV] < " << e1 << "\n";
957 return;
958 }
959
960 if (nsteps <= 0) {
961 std::cerr << className << "::SetEnergyMesh:\n";
962 std::cerr << " Number of intervals must be > 0.\n";
963 return;
964 }
965
966 emin = std::min(e0, e1);
967 emax = std::max(e0, e1);
968 emin *= 1.e-6;
969 emax *= 1.e-6;
970 nEnergyIntervals = nsteps;
971}
972
973void TrackHeed::SetParticleUser(const double m, const double z) {
974
975 if (fabs(z) < Small) {
976 std::cerr << className << "::SetParticleUser:\n";
977 std::cerr << " Particle cannot have zero charge.\n";
978 return;
979 }
980 if (m < Small) {
981 std::cerr << className << "::SetParticleUser:\n";
982 std::cerr << " Particle mass must be greater than zero.\n";
983 }
984 q = z;
985 mass = m;
986 isElectron = false;
987 spin = 0;
988 particleName = "exotic";
989}
990
991bool TrackHeed::Setup(Medium* medium) {
992
993 // Make sure the path to the Heed database is known.
994 char* dbPath = getenv("HEED_DATABASE");
995 if (dbPath == 0) {
996 std::cerr << className << "::Setup:\n";
997 std::cerr << " Database path is not defined.\n";
998 std::cerr << " Environment variable HEED_DATABASE is not set.\n";
999 std::cerr << " Cannot proceed with initialization.\n";
1000 return false;
1001 }
1002
1003 std::string databasePath = dbPath;
1004 if (databasePath[databasePath.size() - 1] != '/') {
1005 databasePath.append("/");
1006 }
1007
1008 // Check once more that the medium exists.
1009 if (medium == 0) {
1010 std::cerr << className << "::Setup:\n";
1011 std::cerr << " Medium pointer is null.\n";
1012 return false;
1013 }
1014
1015 // Setup the energy mesh.
1016 if (energyMesh != 0) {
1017 delete energyMesh;
1018 energyMesh = 0;
1019 }
1020 energyMesh = new Heed::EnergyMesh(emin, emax, nEnergyIntervals);
1021
1022 if (medium->IsGas()) {
1023 if (!SetupGas(medium)) return false;
1024 } else {
1025 if (!SetupMaterial(medium)) return false;
1026 }
1027
1028 // Energy transfer cross-section
1029 // Set a flag indicating whether the primary particle is an electron.
1030 int sel = 0;
1031 if (isElectron) sel = 1;
1032 const double gamma = GetGamma();
1033
1034 if (transferCs != 0) {
1035 delete transferCs;
1036 transferCs = 0;
1037 }
1038 transferCs =
1039 new Heed::EnTransfCS(mass / 1.e6, gamma - 1, sel, matter, long(q));
1040
1041 if (!SetupDelta(databasePath)) return false;
1042
1043 if (debug) {
1044 const double nc = transferCs->quanC;
1045 const double dedx = transferCs->meanC * 1.e3;
1046 const double dedxLeft = transferCs->meanCleft * 1.e3;
1047 const double dedx1 = transferCs->meanC1 * 1.e3;
1048 const double w = matter->W * 1.e6;
1049 const double f = matter->F;
1050 const double minI = matter->min_ioniz_pot * 1.e6;
1051 std::cout << className << "::Setup:\n";
1052 std::cout << " Cluster density: " << nc << " cm-1\n";
1053 std::cout << " Stopping power (restricted): " << dedxLeft << " - "
1054 << dedx << " keV/cm\n";
1055 std::cout << " Stopping power (incl. tail): " << dedx1 << " keV/cm\n";
1056 std::cout << " W value: " << w << " eV\n";
1057 std::cout << " Fano factor: " << f << "\n";
1058 std::cout << " Min. ionization potential: " << minI << " eV\n";
1059 }
1060
1061 fixsyscoor primSys(point(0., 0., 0.), basis("primary"), "primary");
1062 if (chamber != 0) {
1063 delete chamber;
1064 chamber = 0;
1065 }
1066 chamber = new HeedChamber(primSys, lX, lY, lZ, transferCs, deltaCs);
1067
1068 return true;
1069}
1070
1071bool TrackHeed::SetupGas(Medium* medium) {
1072
1073 // Get temperature and pressure.
1074 double pressure = medium->GetPressure();
1075 pressure = (pressure / AtmosphericPressure) * Heed::atmosphere;
1076 double temperature = medium->GetTemperature();
1077
1078 const int nComponents = medium->GetNumberOfComponents();
1079 if (nComponents < 1) {
1080 std::cerr << className << "::SetupGas:\n";
1081 std::cerr << " Gas " << medium->GetName() << " has zero constituents.\n";
1082 return false;
1083 }
1084
1085 if (m_molPacs != 0) {
1086 delete m_molPacs;
1087 m_molPacs = 0;
1088 }
1089 m_molPacs = new Heed::MolecPhotoAbsCS* [nComponents];
1090 DynLinArr<std::string> notations;
1091 notations.clear();
1092 DynLinArr<double> fractions;
1093 fractions.clear();
1094
1095 for (int i = 0; i < nComponents; ++i) {
1096 std::string gasname;
1097 double frac;
1098 medium->GetComponent(i, gasname, frac);
1099 // If necessary, change the Magboltz name to the Heed internal name.
1100 if (gasname == "He-3") gasname = "He";
1101 if (gasname == "CD4") gasname = "CH4";
1102 if (gasname == "iC4H10" || gasname == "nC4H10") gasname = "C4H10";
1103 if (gasname == "neoC5H12" || gasname == "nC5H12") gasname = "C5H12";
1104 if (gasname == "H2O") gasname = "Water";
1105 if (gasname == "D2") gasname = "H2";
1106 if (gasname == "cC3H6") gasname = "C3H6";
1107 // Find the corresponding photoabsorption cross-section.
1108 if (gasname == "CF4")
1109 m_molPacs[i] = &Heed::CF4_MPACS;
1110 else if (gasname == "Ar")
1111 m_molPacs[i] = &Heed::Ar_MPACS;
1112 else if (gasname == "He")
1113 m_molPacs[i] = &Heed::He_MPACS;
1114 else if (gasname == "Ne")
1115 m_molPacs[i] = &Heed::Ne_MPACS;
1116 else if (gasname == "Kr")
1117 m_molPacs[i] = &Heed::Kr_MPACS;
1118 else if (gasname == "Xe")
1119 m_molPacs[i] = &Heed::Xe_MPACS;
1120 else if (gasname == "CH4")
1121 m_molPacs[i] = &Heed::CH4_MPACS;
1122 else if (gasname == "C2H6")
1123 m_molPacs[i] = &Heed::C2H6_MPACS;
1124 else if (gasname == "C3H8")
1125 m_molPacs[i] = &Heed::C3H8_MPACS;
1126 else if (gasname == "C4H10")
1127 m_molPacs[i] = &Heed::C4H10_MPACS;
1128 else if (gasname == "CO2")
1129 m_molPacs[i] = &Heed::CO2_MPACS;
1130 else if (gasname == "C5H12")
1131 m_molPacs[i] = &Heed::C5H12_MPACS;
1132 else if (gasname == "Water")
1133 m_molPacs[i] = &Heed::H2O_MPACS;
1134 else if (gasname == "O2")
1135 m_molPacs[i] = &Heed::O2_MPACS;
1136 else if (gasname == "N2" || gasname == "N2 (Phelps)")
1137 m_molPacs[i] = &Heed::N2_MPACS;
1138 else if (gasname == "NO")
1139 m_molPacs[i] = &Heed::NO_MPACS;
1140 else if (gasname == "N2O")
1141 m_molPacs[i] = &Heed::N2O_MPACS;
1142 else if (gasname == "C2H4")
1143 m_molPacs[i] = &Heed::C2H4_MPACS;
1144 else if (gasname == "C2H2")
1145 m_molPacs[i] = &Heed::C2H2_MPACS;
1146 else if (gasname == "H2")
1147 m_molPacs[i] = &Heed::H2_MPACS;
1148 else if (gasname == "CO")
1149 m_molPacs[i] = &Heed::CO_MPACS;
1150 else if (gasname == "Methylal")
1151 m_molPacs[i] = &Heed::Methylal_MPACS;
1152 else if (gasname == "DME")
1153 m_molPacs[i] = &Heed::DME_MPACS;
1154 else if (gasname == "C2F6")
1155 m_molPacs[i] = &Heed::C2F6_MPACS;
1156 else if (gasname == "SF6")
1157 m_molPacs[i] = &Heed::SF6_MPACS;
1158 else if (gasname == "NH3")
1159 m_molPacs[i] = &Heed::NH3_MPACS;
1160 else if (gasname == "C3H6")
1161 m_molPacs[i] = &Heed::C3H6_MPACS;
1162 else if (gasname == "CH3OH")
1163 m_molPacs[i] = &Heed::CH3OH_MPACS;
1164 else if (gasname == "C2H5OH")
1165 m_molPacs[i] = &Heed::C2H5OH_MPACS;
1166 else if (gasname == "C3H7OH")
1167 m_molPacs[i] = &Heed::C3H7OH_MPACS;
1168 else if (gasname == "Cs")
1169 m_molPacs[i] = &Heed::Cs_MPACS;
1170 else if (gasname == "F2")
1171 m_molPacs[i] = &Heed::F2_MPACS;
1172 else if (gasname == "CS2")
1173 m_molPacs[i] = &Heed::CS2_MPACS;
1174 else if (gasname == "COS")
1175 m_molPacs[i] = &Heed::COS_MPACS;
1176 else if (gasname == "CD4")
1177 m_molPacs[i] = &Heed::CH4_MPACS;
1178 else if (gasname == "BF3")
1179 m_molPacs[i] = &Heed::BF3_MPACS;
1180 else if (gasname == "C2HF5")
1181 m_molPacs[i] = &Heed::C2HF5_MPACS;
1182 else if (gasname == "C2H2F4")
1183 m_molPacs[i] = &Heed::C2H2F4_MPACS;
1184 else if (gasname == "CHF3")
1185 m_molPacs[i] = &Heed::CHF3_MPACS;
1186 else if (gasname == "CF3Br")
1187 m_molPacs[i] = &Heed::CF3Br_MPACS;
1188 else if (gasname == "C3F8")
1189 m_molPacs[i] = &Heed::C3F8_MPACS;
1190 else if (gasname == "O3")
1191 m_molPacs[i] = &Heed::O3_MPACS;
1192 else if (gasname == "Hg")
1193 m_molPacs[i] = &Heed::Hg_MPACS;
1194 else if (gasname == "H2S")
1195 m_molPacs[i] = &Heed::H2S_MPACS;
1196 else if (gasname == "GeH4")
1197 m_molPacs[i] = &Heed::GeH4_MPACS;
1198 else if (gasname == "SiH4")
1199 m_molPacs[i] = &Heed::SiH4_MPACS;
1200 else {
1201 std::cerr << className << "::SetupGas:\n";
1202 std::cerr << " Photoabsorption cross-section data for " << gasname
1203 << " are not available.\n";
1204 return false;
1205 }
1206 notations.increment(gasname);
1207 fractions.increment(frac);
1208 }
1209 if (usePacsOutput) {
1210 std::ofstream pacsfile;
1211 pacsfile.open("heed_pacs.txt", std::ios::out);
1212 const int nValues = energyMesh->get_q();
1213 if (nValues > 0) {
1214 for (int i = 0; i < nValues; ++i) {
1215 double e = energyMesh->get_e(i);
1216 pacsfile << 1.e6 * e << " ";
1217 for (int j = 0; j < nComponents; ++j) {
1218 pacsfile << m_molPacs[j]->get_ACS(e) << " "
1219 << m_molPacs[j]->get_ICS(e) << " ";
1220 }
1221 pacsfile << "\n";
1222 }
1223 }
1224 pacsfile.close();
1225 }
1226
1227 std::string gasname = medium->GetName();
1228 if (gas != 0) {
1229 delete gas;
1230 gas = 0;
1231 }
1232
1233 gas = new Heed::GasDef(gasname, gasname, nComponents, notations, fractions,
1234 pressure, temperature, -1.);
1235
1236 double w = medium->GetW() * 1.e-6;
1237 if (w < 0.) w = 0.;
1238 double f = medium->GetFanoFactor();
1239 if (f <= 0.) f = Heed::standard_factor_Fano;
1240
1241 if (matter != 0) {
1242 delete matter;
1243 matter = 0;
1244 }
1245 matter = new Heed::HeedMatterDef(energyMesh, gas, m_molPacs, w, f);
1246
1247 return true;
1248}
1249
1250bool TrackHeed::SetupMaterial(Medium* medium) {
1251
1252 // Get temperature and density.
1253 double temperature = medium->GetTemperature();
1254 double density = medium->GetMassDensity() * Heed::g / Heed::cm3;
1255
1256 const int nComponents = medium->GetNumberOfComponents();
1257 if (m_atPacs != 0) {
1258 delete m_atPacs;
1259 m_atPacs = 0;
1260 }
1261 m_atPacs = new Heed::AtomPhotoAbsCS* [nComponents];
1262
1263 DynLinArr<std::string> notations;
1264 notations.clear();
1265 DynLinArr<double> fractions;
1266 fractions.clear();
1267 for (int i = 0; i < nComponents; ++i) {
1268 std::string materialName;
1269 double frac;
1270 medium->GetComponent(i, materialName, frac);
1271 if (materialName == "C")
1272 m_atPacs[i] = &Heed::Carbon_PACS;
1273 else if (materialName == "Si")
1274 m_atPacs[i] = &Heed::Silicon_crystal_PACS;
1275 // else if (materialName == "Si") m_atPacs[i] = &Heed::Silicon_G4_PACS;
1276 else if (materialName == "Ga")
1277 m_atPacs[i] = &Heed::Gallium_PACS;
1278 else if (materialName == "Ge")
1279 m_atPacs[i] = &Heed::Germanium_PACS;
1280 else if (materialName == "As")
1281 m_atPacs[i] = &Heed::Arsenic_PACS;
1282 else if (materialName == "Cd")
1283 m_atPacs[i] = &Heed::Cadmium_PACS;
1284 else if (materialName == "Te")
1285 m_atPacs[i] = &Heed::Tellurium_PACS;
1286 else {
1287 std::cerr << className << "::SetupMaterial:\n";
1288 std::cerr << " Photoabsorption cross-section data for " << materialName
1289 << " are not implemented.\n";
1290 return false;
1291 }
1292 notations.increment(materialName);
1293 fractions.increment(frac);
1294 }
1295 if (usePacsOutput) {
1296 std::ofstream pacsfile;
1297 pacsfile.open("heed_pacs.txt", std::ios::out);
1298 const int nValues = energyMesh->get_q();
1299 if (nValues > 0) {
1300 for (int i = 0; i < nValues; ++i) {
1301 double e = energyMesh->get_e(i);
1302 pacsfile << 1.e6 * e << " ";
1303 for (int j = 0; j < nComponents; ++j) {
1304 pacsfile << m_atPacs[j]->get_ACS(e) << " " << m_atPacs[j]->get_ICS(e)
1305 << " ";
1306 }
1307 pacsfile << "\n";
1308 }
1309 }
1310 pacsfile.close();
1311 }
1312 if (material != 0) {
1313 delete material;
1314 material = 0;
1315 }
1316 std::string materialName = medium->GetName();
1317 material = new Heed::MatterDef(materialName, materialName, nComponents,
1318 notations, fractions, density, temperature);
1319
1320 double w = medium->GetW() * 1.e-6;
1321 if (w < 0.) w = 0.;
1322 double f = medium->GetFanoFactor();
1323 if (f <= 0.) f = Heed::standard_factor_Fano;
1324
1325 if (matter != 0) {
1326 delete matter;
1327 matter = 0;
1328 }
1329 matter = new Heed::HeedMatterDef(energyMesh, material, m_atPacs, w, f);
1330
1331 return true;
1332}
1333
1334bool TrackHeed::SetupDelta(const std::string databasePath) {
1335
1336 // Load elastic scattering data.
1337 std::string filename = databasePath + "cbdel.dat";
1338 if (elScat != 0) {
1339 delete elScat;
1340 elScat = 0;
1341 }
1342 elScat = new Heed::ElElasticScat(filename);
1343
1344 filename = databasePath + "elastic_disp.dat";
1345 if (lowSigma != 0) {
1346 delete lowSigma;
1347 lowSigma = 0;
1348 }
1349 lowSigma = new Heed::ElElasticScatLowSigma(elScat, filename);
1350
1351 // Load data for calculation of ionization.
1352 // Get W value and Fano factor.
1353 const double w = matter->W * 1.e6;
1354 const double f = matter->F;
1355 filename = databasePath + "delta_path.dat";
1356 if (pairProd != 0) {
1357 delete pairProd;
1358 pairProd = 0;
1359 }
1360 pairProd = new Heed::PairProd(filename, w, f);
1361
1362 if (deltaCs != 0) {
1363 delete deltaCs;
1364 deltaCs = 0;
1365 }
1366 deltaCs = new Heed::HeedDeltaElectronCS(matter, elScat, lowSigma, pairProd);
1367 return true;
1368}
1369
1370double TrackHeed::GetW() const { return matter->W * 1.e6; }
1371double TrackHeed::GetFanoFactor() const { return matter->F; }
1372
1373}
DoubleAc cos(const DoubleAc &f)
Definition: DoubleAc.cpp:431
DoubleAc sqrt(const DoubleAc &f)
Definition: DoubleAc.cpp:313
DoubleAc sin(const DoubleAc &f)
Definition: DoubleAc.cpp:383
DoubleAc fabs(const DoubleAc &f)
Definition: DoubleAc.h:616
void check_point(gparticle *)
Definition: TrackHeed.cc:84
trajestep_limit gtrajlim
AbsListNode< T > * get_next_node(void) const
Definition: AbsList.h:98
Definition: BlkArr.h:80
void clear(void)
Definition: AbsArr.h:450
void increment(const T *val=NULL)
Definition: AbsArr.h:440
virtual double GetMassDensity() const
Definition: Medium.cc:150
double GetFanoFactor()
Definition: Medium.hh:67
double GetW()
Definition: Medium.hh:65
double GetPressure() const
Definition: Medium.hh:31
virtual void GetComponent(const unsigned int &i, std::string &label, double &f)
Definition: Medium.cc:155
unsigned int GetNumberOfComponents() const
Definition: Medium.hh:37
virtual bool IsGas() const
Definition: Medium.hh:23
bool IsIonisable() const
Definition: Medium.hh:59
double GetTemperature() const
Definition: Medium.hh:28
std::string GetName() const
Definition: Medium.hh:22
void MagneticField(const double x, const double y, const double z, double &bx, double &by, double &bz, int &status)
Definition: Sensor.cc:95
void ElectricField(const double x, const double y, const double z, double &ex, double &ey, double &ez, double &v, Medium *&medium, int &status)
Definition: Sensor.cc:44
bool IsInArea(const double x, const double y, const double z)
Definition: Sensor.cc:254
bool GetMedium(const double x, const double y, const double z, Medium *&medium)
Definition: Sensor.cc:141
bool GetArea(double &xmin, double &ymin, double &zmin, double &xmax, double &ymax, double &zmax)
Definition: Sensor.cc:227
void EnableMagneticField()
Definition: TrackHeed.cc:946
void SetEnergyMesh(const double e0, const double e1, const int nsteps)
Definition: TrackHeed.cc:950
bool GetCluster(double &xcls, double &ycls, double &zcls, double &tcls, int &n, double &e, double &extra)
Definition: TrackHeed.cc:383
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 &nel)
Definition: TrackHeed.cc:615
void EnableElectricField()
Definition: TrackHeed.cc:942
void DisableMagneticField()
Definition: TrackHeed.cc:948
bool GetElectron(const int i, double &x, double &y, double &z, double &t, double &e, double &dx, double &dy, double &dz)
Definition: TrackHeed.cc:566
double GetFanoFactor() const
Definition: TrackHeed.cc:1371
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 &nel)
Definition: TrackHeed.cc:743
double GetClusterDensity()
Definition: TrackHeed.cc:349
bool NewTrack(const double x0, const double y0, const double z0, const double t0, const double dx0, const double dy0, const double dz0)
Definition: TrackHeed.cc:158
double GetW() const
Definition: TrackHeed.cc:1370
void SetParticleUser(const double m, const double z)
Definition: TrackHeed.cc:973
void DisableElectricField()
Definition: TrackHeed.cc:944
double GetStoppingPower()
Definition: TrackHeed.cc:366
double GetBeta() const
Definition: Track.hh:33
double GetGamma() const
Definition: Track.hh:34
bool isChanged
Definition: Track.hh:73
bool usePlotting
Definition: Track.hh:75
std::string className
Definition: Track.hh:61
double mass
Definition: Track.hh:65
std::string particleName
Definition: Track.hh:69
double q
Definition: Track.hh:63
void PlotCluster(const double x0, const double y0, const double z0)
Definition: Track.cc:221
bool isElectron
Definition: Track.hh:68
bool debug
Definition: Track.hh:78
Sensor * sensor
Definition: Track.hh:71
void PlotNewTrack(const double x0, const double y0, const double z0)
Definition: Track.cc:214
virtual double get_ACS(double energy) const =0
virtual double get_ICS(double energy) const =0
double quanC
Integrated (ionization) cross-section.
Definition: EnTransfCS.h:79
double meanCleft
Definition: EnTransfCS.h:95
long get_q() const
Definition: EnergyMesh.h:51
double get_e(long n) const
Definition: EnergyMesh.h:54
long particle_number
Definition: HeedPhoton.h:19
long parent_particle_number
Definition: HeedPhoton.h:20
virtual double get_ACS(double energy) const
virtual double get_ICS(double energy) const
BlkArr< HeedCondElectron > conduction_electron_bank
double curr_kin_energy
Definition: mparticle.h:31
void set_mass(const double m)
void set_charge(const double z)
Definition: vec.h:397
stvpoint currpos
Definition: gparticle.h:188
virtual void fly(void)
Definition: gparticle.h:249
Definition: vec.h:477
vec v
Definition: vec.h:479
point pt
Definition: gparticle.h:33
vfloat time
Definition: gparticle.h:55
vec dir
Definition: gparticle.h:35
Definition: vec.h:248
vfloat y
Definition: vec.h:250
vfloat x
Definition: vec.h:250
vfloat z
Definition: vec.h:250
double RndmUniform()
Definition: Random.hh:16
Definition: BGMesh.cpp:3
MolecPhotoAbsCS Cs_MPACS(Caesium_PACS, 1)
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:137
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:135
ExAtomPhotoAbsCS Tellurium_PACS(49, shelllist_dir_name+"shelllist.dat", pacs_table_dir_name+"Te.dat")
Definition: PhotoAbsCSLib.h:61
MolecPhotoAbsCS CF3Br_MPACS(Carbon_for_CF4_PACS, 1, Fluorine_PACS, 3, Bromine_PACS, 1)
MolecPhotoAbsCS N2_MPACS(Nitrogen_PACS, 2, 34.8e-6)
Definition: PhotoAbsCSLib.h:69
ExAtomPhotoAbsCS Silicon_crystal_PACS(14, shelllist_dir_name+"shelllist_solid.dat", pacs_table_dir_name+"Si.dat", "Si_crystal")
Definition: PhotoAbsCSLib.h:48
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:124
BlkArr< HeedCluster > cluster_bank
Definition: TrackHeed.cc:41
MolecPhotoAbsCS Ne_MPACS(Neon_PACS, 1, 35.4e-6)
Definition: PhotoAbsCSLib.h:71
MolecPhotoAbsCS C5H12_MPACS(Carbon_for_C4H10_PACS, 5, Hydrogen_for_H2_PACS, 12, 23.2e-6)
Definition: PhotoAbsCSLib.h:99
MolecPhotoAbsCS CO_MPACS(Carbon_for_CO2_PACS, 1, Oxygen_PACS, 1)
long last_particle_number
Definition: HeedParticle.h:26
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:143
particle_def anti_proton_def("", "p-", proton_def)
Definition: particle_def.h:127
MolecPhotoAbsCS Hg_MPACS(Mercury_PACS, 1)
MolecPhotoAbsCS SiH4_MPACS(Silicon_PACS, 1, Hydrogen_for_H2_PACS, 4)
MolecPhotoAbsCS CS2_MPACS(Carbon_for_CO2_PACS, 1, Sulfur_PACS, 2)
MolecPhotoAbsCS COS_MPACS(Carbon_for_CO2_PACS, 1, Oxygen_PACS, 1, Sulfur_PACS, 1)
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:142
MolecPhotoAbsCS DME_MPACS(Carbon_for_Methylal_PACS, 2, Hydrogen_for_H2_PACS, 6, Oxygen_PACS, 1)
MolecPhotoAbsCS Xe_MPACS(Xenon_PACS, 1, 22.1e-6)
Definition: PhotoAbsCSLib.h:74
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:126
MolecPhotoAbsCS H2S_MPACS(Hydrogen_for_H2_PACS, 2, Sulfur_PACS, 1)
ExAtomPhotoAbsCS Cadmium_PACS(48, shelllist_dir_name+"shelllist.dat", pacs_table_dir_name+"Cd.dat")
Definition: PhotoAbsCSLib.h:60
MolecPhotoAbsCS F2_MPACS(Fluorine_PACS, 2)
MolecPhotoAbsCS C3H8_MPACS(Carbon_for_CH4_PACS, 3, Hydrogen_for_H2_PACS, 8, 24.0e-6)
Definition: PhotoAbsCSLib.h:89
ExAtomPhotoAbsCS Arsenic_PACS(33, shelllist_dir_name+"shelllist.dat", pacs_table_dir_name+"As.dat")
Definition: PhotoAbsCSLib.h:57
particle_def K_minus_meson_def("K_minus_meson_def", "K-", K_plus_meson_def)
Definition: particle_def.h:140
const double standard_factor_Fano
Definition: PhotoAbsCS.h:542
MolecPhotoAbsCS C2H5OH_MPACS(Carbon_for_C2H6_PACS, 2, Hydrogen_for_H2_PACS, 6, Oxygen_PACS, 1, 24.8e-6)
MolecPhotoAbsCS O2_MPACS(Oxygen_PACS, 2, 30.8e-6)
Definition: PhotoAbsCSLib.h:70
MolecPhotoAbsCS C2H2_MPACS(Carbon_for_CH4_PACS, 2, Hydrogen_for_H2_PACS, 2, 25.8e-6)
Definition: PhotoAbsCSLib.h:86
MolecPhotoAbsCS C2H4_MPACS(Carbon_for_C2H4_PACS, 2, Hydrogen_for_H2_PACS, 4, 25.8e-6)
Definition: PhotoAbsCSLib.h:87
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:139
MolecPhotoAbsCS Ar_MPACS(Argon_PACS, 1, 26.4e-6)
Definition: PhotoAbsCSLib.h:72
MolecPhotoAbsCS CHF3_MPACS(Carbon_for_CF4_PACS, 1, Hydrogen_for_H2_PACS, 1, Fluorine_PACS, 3)
MolecPhotoAbsCS NH3_MPACS(Nitrogen_PACS, 1, Hydrogen_for_NH4_PACS, 3, 26.6e-6)
Definition: PhotoAbsCSLib.h:75
AbsList< ActivePtr< gparticle > > particle_bank
Definition: TrackHeed.cc:42
MolecPhotoAbsCS CH3OH_MPACS(Carbon_for_C2H6_PACS, 1, Hydrogen_for_H2_PACS, 4, Oxygen_PACS, 1, 24.7e-6)
MolecPhotoAbsCS C2HF5_MPACS(Carbon_for_C2H6_PACS, 2, Hydrogen_for_H2_PACS, 1, Fluorine_PACS, 5)
MolecPhotoAbsCS C4H10_MPACS(Carbon_for_C4H10_PACS, 4, Hydrogen_for_H2_PACS, 10, 23.4e-6)
Definition: PhotoAbsCSLib.h:90
MolecPhotoAbsCS CH4_MPACS(Carbon_for_CH4_PACS, 1, Hydrogen_for_CH4_PACS, 4, 27.3e-6)
Definition: PhotoAbsCSLib.h:78
MolecPhotoAbsCS SF6_MPACS(Sulfur_PACS, 1, Fluorine_PACS, 6)
Definition: PhotoAbsCSLib.h:84
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:146
MolecPhotoAbsCS C2H2F4_MPACS(Carbon_for_C2H6_PACS, 2, Fluorine_PACS, 4, Hydrogen_for_H2_PACS, 2)
MolecPhotoAbsCS BF3_MPACS(Boron_PACS, 1, Fluorine_PACS, 3)
ExAtomPhotoAbsCS Germanium_PACS(32, shelllist_dir_name+"shelllist.dat", pacs_table_dir_name+"Ge.dat")
Definition: PhotoAbsCSLib.h:55
MolecPhotoAbsCS Kr_MPACS(Krypton_PACS, 1, 24.4e-6)
Definition: PhotoAbsCSLib.h:73
MolecPhotoAbsCS C2F6_MPACS(Carbon_for_C2H6_PACS, 2, Fluorine_PACS, 6)
MolecPhotoAbsCS C3H7OH_MPACS(Carbon_for_C2H6_PACS, 3, Hydrogen_for_H2_PACS, 8, Oxygen_PACS, 1)
MolecPhotoAbsCS CO2_MPACS(Carbon_for_CO2_PACS, 1, Oxygen_for_CO2_PACS, 2, 33.0e-6)
Definition: PhotoAbsCSLib.h:77
MolecPhotoAbsCS C2H6_MPACS(Carbon_for_C2H6_PACS, 2, Hydrogen_for_H2_PACS, 6, 25.0e-6)
Definition: PhotoAbsCSLib.h:88
MolecPhotoAbsCS He_MPACS(Helium_PACS, 1, 41.3e-6)
Definition: PhotoAbsCSLib.h:68
particle_def muon_plus_def("muon_plus", "mu+", muon_minus_def)
Definition: particle_def.h:125
particle_def positron_def("positron", "e+", electron_def)
Definition: particle_def.h:123
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:122
MolecPhotoAbsCS H2_MPACS(Hydrogen_for_H2_PACS, 2)
Definition: PhotoAbsCSLib.h:67
ExAtomPhotoAbsCS Gallium_PACS(31, shelllist_dir_name+"shelllist.dat", pacs_table_dir_name+"Ga.dat")
Definition: PhotoAbsCSLib.h:54
ExAtomPhotoAbsCS Carbon_PACS(6, shelllist_dir_name+"shelllist.dat", pacs_table_dir_name+"C.dat")
Definition: PhotoAbsCSLib.h:31
MolecPhotoAbsCS NO_MPACS(Nitrogen_PACS, 1, Oxygen_PACS, 1)
MolecPhotoAbsCS O3_MPACS(Oxygen_PACS, 3)
MolecPhotoAbsCS GeH4_MPACS(Germanium_PACS, 1, Hydrogen_for_H2_PACS, 4)
MolecPhotoAbsCS C3F8_MPACS(Carbon_for_CF4_PACS, 3, Fluorine_PACS, 8)
MolecPhotoAbsCS Methylal_MPACS(Oxygen_PACS, 2, Carbon_for_Methylal_PACS, 3, Hydrogen_for_H2_PACS, 8, 10.0e-6 *23.4/10.55)
Definition: PhotoAbsCSLib.h:95
MolecPhotoAbsCS H2O_MPACS(Hydrogen_for_H2_PACS, 2, Oxygen_PACS, 1, 29.6e-6)
MolecPhotoAbsCS CF4_MPACS(Carbon_for_CF4_PACS, 1, Fluorine_PACS, 4)
Definition: PhotoAbsCSLib.h:79
MolecPhotoAbsCS N2O_MPACS(Nitrogen_PACS, 2, Oxygen_PACS, 1, 34.8e-6)
Definition: PhotoAbsCSLib.h:76
void field_map(const point &pt, vec &Efield, vec &Hfield, vfloat &mrange)
Definition: TrackHeed.cc:44
MolecPhotoAbsCS C3H6_MPACS(Carbon_for_C2H6_PACS, 3, Hydrogen_for_H2_PACS, 6)
double vfloat
Definition: vfloat.h:15