Garfield++ v1r0
A toolkit for the detailed simulation of particle detectors based on ionisation measurement in gases and semiconductors
Loading...
Searching...
No Matches
Garfield::TrackHeed Class Reference

#include <TrackHeed.hh>

+ Inheritance diagram for Garfield::TrackHeed:

Public Member Functions

 TrackHeed ()
 
 ~TrackHeed ()
 
bool NewTrack (const double x0, const double y0, const double z0, const double t0, const double dx0, const double dy0, const double dz0)
 
bool GetCluster (double &xcls, double &ycls, double &zcls, double &tcls, int &n, double &e, double &extra)
 
bool GetElectron (const int i, double &x, double &y, double &z, double &t, double &e, double &dx, double &dy, double &dz)
 
double GetClusterDensity ()
 
double GetStoppingPower ()
 
double GetW () const
 
double GetFanoFactor () const
 
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)
 
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)
 
void EnableElectricField ()
 
void DisableElectricField ()
 
void EnableMagneticField ()
 
void DisableMagneticField ()
 
void EnableDeltaElectronTransport ()
 
void DisableDeltaElectronTransport ()
 
void EnablePhotonReabsorption ()
 
void DisablePhotonReabsorption ()
 
void EnablePhotoAbsorptionCrossSectionOutput ()
 
void DisablePhotoAbsorptionCrossSectionOutput ()
 
void SetEnergyMesh (const double e0, const double e1, const int nsteps)
 
void SetParticleUser (const double m, const double z)
 
- Public Member Functions inherited from Garfield::Track
 Track ()
 
virtual ~Track ()
 
virtual void SetParticle (std::string part)
 
void SetEnergy (const double e)
 
void SetBetaGamma (const double bg)
 
void SetBeta (const double beta)
 
void SetGamma (const double gamma)
 
void SetMomentum (const double p)
 
void SetKineticEnergy (const double ekin)
 
double GetEnergy () const
 
double GetBetaGamma () const
 
double GetBeta () const
 
double GetGamma () const
 
double GetMomentum () const
 
double GetKineticEnergy () const
 
void SetSensor (Sensor *s)
 
virtual bool NewTrack (const double x0, const double y0, const double z0, const double t0, const double dx0, const double dy0, const double dz0)=0
 
virtual bool GetCluster (double &xcls, double &ycls, double &zcls, double &tcls, int &n, double &e, double &extra)=0
 
virtual double GetClusterDensity ()
 
virtual double GetStoppingPower ()
 
void EnablePlotting (ViewDrift *viewer)
 
void DisablePlotting ()
 
void EnableDebugging ()
 
void DisableDebugging ()
 

Additional Inherited Members

- Protected Member Functions inherited from Garfield::Track
void PlotNewTrack (const double x0, const double y0, const double z0)
 
void PlotCluster (const double x0, const double y0, const double z0)
 
- Protected Attributes inherited from Garfield::Track
std::string className
 
double q
 
int spin
 
double mass
 
double energy
 
double beta2
 
bool isElectron
 
std::string particleName
 
Sensorsensor
 
bool isChanged
 
bool usePlotting
 
ViewDriftviewer
 
bool debug
 
int plotId
 

Detailed Description

Definition at line 30 of file TrackHeed.hh.

Constructor & Destructor Documentation

◆ TrackHeed()

Garfield::TrackHeed::TrackHeed ( )

Definition at line 98 of file TrackHeed.cc.

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}
std::string className
Definition: Track.hh:61

◆ ~TrackHeed()

Garfield::TrackHeed::~TrackHeed ( )

Definition at line 139 of file TrackHeed.cc.

139 {
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}

Member Function Documentation

◆ DisableDeltaElectronTransport()

void Garfield::TrackHeed::DisableDeltaElectronTransport ( )
inline

Definition at line 68 of file TrackHeed.hh.

68{ useDelta = false; }

◆ DisableElectricField()

void Garfield::TrackHeed::DisableElectricField ( )

Definition at line 944 of file TrackHeed.cc.

944{ HeedInterface::useEfield = false; }

◆ DisableMagneticField()

void Garfield::TrackHeed::DisableMagneticField ( )

Definition at line 948 of file TrackHeed.cc.

948{ HeedInterface::useBfield = false; }

◆ DisablePhotoAbsorptionCrossSectionOutput()

void Garfield::TrackHeed::DisablePhotoAbsorptionCrossSectionOutput ( )
inline

Definition at line 74 of file TrackHeed.hh.

74{ usePacsOutput = false; }

◆ DisablePhotonReabsorption()

void Garfield::TrackHeed::DisablePhotonReabsorption ( )
inline

Definition at line 71 of file TrackHeed.hh.

71{ usePhotonReabsorption = false; }

◆ EnableDeltaElectronTransport()

void Garfield::TrackHeed::EnableDeltaElectronTransport ( )
inline

Definition at line 67 of file TrackHeed.hh.

67{ useDelta = true; }

Referenced by GarfieldPhysics::InitializePhysics().

◆ EnableElectricField()

void Garfield::TrackHeed::EnableElectricField ( )

Definition at line 942 of file TrackHeed.cc.

942{ HeedInterface::useEfield = true; }

◆ EnableMagneticField()

void Garfield::TrackHeed::EnableMagneticField ( )

Definition at line 946 of file TrackHeed.cc.

946{ HeedInterface::useBfield = true; }

◆ EnablePhotoAbsorptionCrossSectionOutput()

void Garfield::TrackHeed::EnablePhotoAbsorptionCrossSectionOutput ( )
inline

Definition at line 73 of file TrackHeed.hh.

73{ usePacsOutput = true; }

◆ EnablePhotonReabsorption()

void Garfield::TrackHeed::EnablePhotonReabsorption ( )
inline

Definition at line 70 of file TrackHeed.hh.

70{ usePhotonReabsorption = true; }

◆ GetCluster()

bool Garfield::TrackHeed::GetCluster ( double &  xcls,
double &  ycls,
double &  zcls,
double &  tcls,
int &  n,
double &  e,
double &  extra 
)
virtual

Implements Garfield::Track.

Definition at line 383 of file TrackHeed.cc.

384 {
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}
DoubleAc fabs(const DoubleAc &f)
Definition: DoubleAc.h:616
AbsListNode< T > * get_next_node(void) const
Definition: AbsList.h:98
virtual double GetMassDensity() const
Definition: Medium.cc:150
bool IsIonisable() const
Definition: Medium.hh:59
std::string GetName() const
Definition: Medium.hh:22
bool IsInArea(const double x, const double y, const double z)
Definition: Sensor.cc:254
bool GetMedium(const double x, const double y, const double z, Medium *&medium)
Definition: Sensor.cc:141
bool usePlotting
Definition: Track.hh:75
void PlotCluster(const double x0, const double y0, const double z0)
Definition: Track.cc:221
Sensor * sensor
Definition: Track.hh:71
long particle_number
Definition: HeedPhoton.h:19
long parent_particle_number
Definition: HeedPhoton.h:20
BlkArr< HeedCondElectron > conduction_electron_bank
double curr_kin_energy
Definition: mparticle.h:31
stvpoint currpos
Definition: gparticle.h:188
virtual void fly(void)
Definition: gparticle.h:249
vec v
Definition: vec.h:479
point pt
Definition: gparticle.h:33
vfloat time
Definition: gparticle.h:55
vec dir
Definition: gparticle.h:35
vfloat y
Definition: vec.h:250
vfloat x
Definition: vec.h:250
vfloat z
Definition: vec.h:250
AbsList< ActivePtr< gparticle > > particle_bank
Definition: TrackHeed.cc:42

Referenced by GarfieldPhysics::DoIt().

◆ GetClusterDensity()

double Garfield::TrackHeed::GetClusterDensity ( )
virtual

Reimplemented from Garfield::Track.

Definition at line 349 of file TrackHeed.cc.

349 {
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}
double quanC
Integrated (ionization) cross-section.
Definition: EnTransfCS.h:79

◆ GetElectron()

bool Garfield::TrackHeed::GetElectron ( const int  i,
double &  x,
double &  y,
double &  z,
double &  t,
double &  e,
double &  dx,
double &  dy,
double &  dz 
)

Definition at line 566 of file TrackHeed.cc.

568 {
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}

Referenced by GarfieldPhysics::DoIt().

◆ GetFanoFactor()

double Garfield::TrackHeed::GetFanoFactor ( ) const

Definition at line 1371 of file TrackHeed.cc.

1371{ return matter->F; }

◆ GetStoppingPower()

double Garfield::TrackHeed::GetStoppingPower ( )
virtual

Reimplemented from Garfield::Track.

Definition at line 366 of file TrackHeed.cc.

366 {
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}

◆ GetW()

double Garfield::TrackHeed::GetW ( ) const

Definition at line 1370 of file TrackHeed.cc.

1370{ return matter->W * 1.e6; }

Referenced by GarfieldPhysics::DoIt().

◆ NewTrack()

bool Garfield::TrackHeed::NewTrack ( const double  x0,
const double  y0,
const double  z0,
const double  t0,
const double  dx0,
const double  dy0,
const double  dz0 
)
virtual

Implements Garfield::Track.

Definition at line 158 of file TrackHeed.cc.

160 {
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}
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
bool GetArea(double &xmin, double &ymin, double &zmin, double &xmax, double &ymax, double &zmax)
Definition: Sensor.cc:227
double GetBeta() const
Definition: Track.hh:33
bool isChanged
Definition: Track.hh:73
double mass
Definition: Track.hh:65
std::string particleName
Definition: Track.hh:69
double q
Definition: Track.hh:63
bool debug
Definition: Track.hh:78
void PlotNewTrack(const double x0, const double y0, const double z0)
Definition: Track.cc:214
void set_mass(const double m)
void set_charge(const double z)
Definition: vec.h:477
Definition: vec.h:248
double RndmUniform()
Definition: Random.hh:16
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
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
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
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
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
particle_def K_minus_meson_def("K_minus_meson_def", "K-", K_plus_meson_def)
Definition: particle_def.h:140
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
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
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

Referenced by GarfieldPhysics::DoIt().

◆ SetEnergyMesh()

void Garfield::TrackHeed::SetEnergyMesh ( const double  e0,
const double  e1,
const int  nsteps 
)

Definition at line 950 of file TrackHeed.cc.

951 {
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}

◆ SetParticleUser()

void Garfield::TrackHeed::SetParticleUser ( const double  m,
const double  z 
)

Definition at line 973 of file TrackHeed.cc.

973 {
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}
bool isElectron
Definition: Track.hh:68

◆ TransportDeltaElectron()

void Garfield::TrackHeed::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 at line 615 of file TrackHeed.cc.

619 {
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}

Referenced by GarfieldPhysics::DoIt().

◆ TransportPhoton()

void Garfield::TrackHeed::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 at line 743 of file TrackHeed.cc.

746 {
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}

Referenced by GarfieldPhysics::DoIt().


The documentation for this class was generated from the following files: