Garfield++ v2r0
A toolkit for the detailed simulation of particle detectors based on ionisation measurement in gases and semiconductors
Loading...
Searching...
No Matches
GarfieldPhysics.cc
Go to the documentation of this file.
1//
2// ********************************************************************
3// * License and Disclaimer *
4// * *
5// * The Geant4 software is copyright of the Copyright Holders of *
6// * the Geant4 Collaboration. It is provided under the terms and *
7// * conditions of the Geant4 Software License, included in the file *
8// * LICENSE and available at http://cern.ch/geant4/license . These *
9// * include a list of copyright holders. *
10// * *
11// * Neither the authors of this software system, nor their employing *
12// * institutes,nor the agencies providing financial support for this *
13// * work make any representation or warranty, express or implied, *
14// * regarding this software system or assume any liability for its *
15// * use. Please see the license in the file LICENSE and URL above *
16// * for the full disclaimer and the limitation of liability. *
17// * *
18// * This code implementation is the result of the scientific and *
19// * technical work of the GEANT4 collaboration. *
20// * By using, copying, modifying or distributing the software (or *
21// * any work based on the software) you agree to acknowledge its *
22// * use in resulting scientific publications, and indicate your *
23// * acceptance of all terms of the Geant4 Software license. *
24// ********************************************************************
25//
26// $Id: GarfieldPhysics.cc 999996 2015-12-11 14:47:43Z dpfeiffe $
27//
28/// \file GarfieldPhysics.cc
29/// \brief Implementation of the GarfieldPhysics class
30#include "GarfieldPhysics.hh"
31
32#include "TGeoManager.h"
33#include "TGeoBBox.h"
34
35#include "GarfieldAnalysis.hh"
36
37GarfieldPhysics* GarfieldPhysics::fGarfieldPhysics = 0;
38//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
39
41 if (!fGarfieldPhysics) {
42 fGarfieldPhysics = new GarfieldPhysics();
43 }
44 return fGarfieldPhysics;
45}
46
48 delete fGarfieldPhysics;
49 fGarfieldPhysics = 0;
50}
51
52GarfieldPhysics::GarfieldPhysics() {
53 fMapParticlesEnergyGeant4 = new MapParticlesEnergy();
54 fMapParticlesEnergyGarfield = new MapParticlesEnergy();
55 fSecondaryParticles = new std::vector<GarfieldParticle*>();
56 fMediumMagboltz = 0;
57 fSensor = 0;
58 fAvalanche = 0;
59 fDrift = 0;
60 fComponentAnalyticField = 0;
61 fTrackHeed = 0;
62 fGeoManager = 0;
63 fGeometryRoot = 0;
64 fGeometrySimple = 0;
65 fTube = 0;
66 createSecondariesInGeant4 = false;
67 fIonizationModel = "PAIPhot";
68}
69
70GarfieldPhysics::~GarfieldPhysics() {
71 delete fMapParticlesEnergyGeant4;
72 delete fMapParticlesEnergyGarfield;
74 delete fSecondaryParticles;
75 delete fMediumMagboltz;
76 delete fSensor;
77 delete fAvalanche;
78 delete fDrift;
79 delete fComponentAnalyticField;
80 delete fTrackHeed;
81 delete fGeometryRoot;
82 delete fGeometrySimple;
83
84 std::cout << "Deconstructor GarfieldPhysics" << std::endl;
85}
86
88 return fIonizationModel;
89}
90
91void GarfieldPhysics::SetIonizationModel(std::string model, bool useDefaults) {
92 if (model != "PAIPhot" && model != "PAI" && model != "Heed") {
93
94 std::cout << "Unknown ionization model " << model << std::endl;
95 std::cout << "Using PAIPhot as default model!" << std::endl;
96 model = "PAIPhot";
97 }
98 fIonizationModel = model;
99
100 if (fIonizationModel == "PAIPhot" || fIonizationModel == "PAI") {
101 if (useDefaults == true) {
102 //Particle types and energies for which the G4FastSimulationModel with Garfield++ is valid
103 this->AddParticleName("e-", 1e-6, 1e-3, "garfield");
104 this->AddParticleName("gamma", 1e-6, 1e+8, "garfield");
105
106 //Particle types and energies for which the PAI or PAIPhot model is valid
107 this->AddParticleName("e-", 0, 1e+8, "geant4");
108 this->AddParticleName("e+", 0, 1e+8, "geant4");
109 this->AddParticleName("mu-", 0, 1e+8, "geant4");
110 this->AddParticleName("mu+", 0, 1e+8, "geant4");
111 this->AddParticleName("proton", 0, 1e+8, "geant4");
112 this->AddParticleName("pi+", 0, 1e+8, "geant4");
113 this->AddParticleName("pi-", 0, 1e+8, "geant4");
114 this->AddParticleName("alpha", 0, 1e+8, "geant4");
115 this->AddParticleName("He3", 0, 1e+8, "geant4");
116 this->AddParticleName("GenericIon", 0, 1e+8, "geant4");
117 }
118
119 } else if (fIonizationModel == "Heed") {
120 if (useDefaults == true) {
121 //Particle types and energies for which the G4FastSimulationModel with Garfield++ is valid
122 this->AddParticleName("gamma", 1e-6, 1e+8, "garfield");
123 this->AddParticleName("e-", 6e-2, 1e+7, "garfield");
124 this->AddParticleName("e+", 6e-2, 1e+7, "garfield");
125 this->AddParticleName("mu-", 1e+1, 1e+8, "garfield");
126 this->AddParticleName("mu+", 1e+1, 1e+8, "garfield");
127 this->AddParticleName("pi-", 2e+1, 1e+8, "garfield");
128 this->AddParticleName("pi+", 2e+1, 1e+8, "garfield");
129 this->AddParticleName("kaon-", 1e+1, 1e+8, "garfield");
130 this->AddParticleName("kaon+", 1e+1, 1e+8, "garfield");
131 this->AddParticleName("proton", 9.e+1, 1e+8, "garfield");
132 this->AddParticleName("anti_proton", 9.e+1, 1e+8, "garfield");
133 this->AddParticleName("deuteron", 2.e+2, 1e+8, "garfield");
134 this->AddParticleName("alpha", 4.e+2, 1e+8, "garfield");
135 }
136
137 }
138}
139
140void GarfieldPhysics::AddParticleName(const std::string particleName,
141 double ekin_min_MeV, double ekin_max_MeV, std::string program) {
142 if (ekin_min_MeV >= ekin_max_MeV) {
143 std::cout << "Ekin_min=" << ekin_min_MeV
144 << " keV is larger than Ekin_max=" << ekin_max_MeV << " keV"
145 << std::endl;
146 return;
147 }
148
149 if (program == "garfield") {
150 std::cout << "Garfield model (Heed) is applicable for G4Particle "
151 << particleName << " between " << ekin_min_MeV << " MeV and "
152 << ekin_max_MeV << " MeV" << std::endl;
153
154 fMapParticlesEnergyGarfield->insert(
155 std::make_pair(particleName,
156 std::make_pair(ekin_min_MeV, ekin_max_MeV)));
157 } else {
158 std::cout << fIonizationModel << " is applicable for G4Particle "
159 << particleName << " between " << ekin_min_MeV << " MeV and "
160 << ekin_max_MeV << " MeV" << std::endl;
161 fMapParticlesEnergyGeant4->insert(
162 std::make_pair(particleName,
163 std::make_pair(ekin_min_MeV, ekin_max_MeV)));
164 }
165
166}
167
168bool GarfieldPhysics::FindParticleName(std::string name, std::string program) {
169 MapParticlesEnergy::iterator it;
170 if (program == "garfield") {
171 it = fMapParticlesEnergyGarfield->find(name);
172 if (it != fMapParticlesEnergyGarfield->end()) {
173 return true;
174 }
175 return false;
176 } else {
177 it = fMapParticlesEnergyGeant4->find(name);
178 if (it != fMapParticlesEnergyGeant4->end()) {
179 return true;
180 }
181 return false;
182 }
183}
184
185bool GarfieldPhysics::FindParticleNameEnergy(std::string name, double ekin_MeV,
186 std::string program) {
187 MapParticlesEnergy::iterator it;
188 if (program == "garfield") {
189 it = fMapParticlesEnergyGarfield->find(name);
190 if (it != fMapParticlesEnergyGarfield->end()) {
191 EnergyRange_MeV range = it->second;
192 if (range.first <= ekin_MeV && range.second >= ekin_MeV) {
193 return true;
194 }
195 }
196 return false;
197 } else {
198 it = fMapParticlesEnergyGeant4->find(name);
199 if (it != fMapParticlesEnergyGeant4->end()) {
200 EnergyRange_MeV range = it->second;
201 if (range.first <= ekin_MeV && range.second >= ekin_MeV) {
202 return true;
203 }
204 }
205 return false;
206 }
207}
208
210 std::string program) {
211 MapParticlesEnergy::iterator it;
212 if (program == "garfield") {
213 it = fMapParticlesEnergyGarfield->find(name);
214 if (it != fMapParticlesEnergyGarfield->end()) {
215 EnergyRange_MeV range = it->second;
216 return range.first;
217 }
218 return false;
219 } else {
220 it = fMapParticlesEnergyGeant4->find(name);
221 if (it != fMapParticlesEnergyGeant4->end()) {
222 EnergyRange_MeV range = it->second;
223 return range.first;
224 }
225 }
226 return -1;
227}
228
230 std::string program) {
231 MapParticlesEnergy::iterator it;
232 if (program == "garfield") {
233 it = fMapParticlesEnergyGarfield->find(name);
234 if (it != fMapParticlesEnergyGarfield->end()) {
235 EnergyRange_MeV range = it->second;
236 return range.second;
237
238 }
239 } else {
240 it = fMapParticlesEnergyGeant4->find(name);
241 if (it != fMapParticlesEnergyGeant4->end()) {
242 EnergyRange_MeV range = it->second;
243 return range.second;
244 }
245 }
246 return -1;
247}
248
250
251 fMediumMagboltz = new Garfield::MediumMagboltz();
252
253 fMediumMagboltz->SetComposition("ar", 70., "co2", 30.);
254 fMediumMagboltz->SetTemperature(293.15);
255 fMediumMagboltz->SetPressure(760.);
256 fMediumMagboltz->EnableDebugging();
257 fMediumMagboltz->Initialise(true);
258 fMediumMagboltz->DisableDebugging();
259// Set the Penning transfer efficiency.
260 const double rPenning = 0.57;
261 const double lambdaPenning = 0.;
262 fMediumMagboltz->EnablePenningTransfer(rPenning, lambdaPenning, "ar");
263 fMediumMagboltz->LoadGasFile("ar_70_co2_30_1000mbar.gas");
264
265 fSensor = new Garfield::Sensor();
266 fDrift = new Garfield::AvalancheMC();
267 fAvalanche = new Garfield::AvalancheMicroscopic();
268 fComponentAnalyticField = new Garfield::ComponentAnalyticField();
269
271
272 fDrift->SetSensor(fSensor);
273 fAvalanche->SetSensor(fSensor);
274
275 fTrackHeed = new Garfield::TrackHeed();
276 fTrackHeed->EnableDebugging();
277 fTrackHeed->SetSensor(fSensor);
278
279 fTrackHeed->EnableDeltaElectronTransport();
280}
281
283// Wire radius [cm]
284 const double rWire = 25.e-4;
285// Outer radius of the tube [cm]
286 const double rTube = 1.451;
287// Half-length of the tube [cm]
288 const double lTube = 10.;
289
290 fGeometrySimple = new Garfield::GeometrySimple();
291// Make a tube (centered at the origin, inner radius: 0, outer radius: rTube).
292 fTube = new Garfield::SolidTube(0., 0., 0, rWire, rTube, lTube);
293// Add the solid to the geometry, together with the medium inside.
294 fGeometrySimple->AddSolid(fTube, fMediumMagboltz);
295 fComponentAnalyticField->SetGeometry(fGeometrySimple);
296
297// Voltages
298 const double vWire = 1000.;
299 const double vTube = 0.;
300// Add the wire in the center.
301 fComponentAnalyticField->AddWire(0., 0., 2 * rWire, vWire, "w");
302// Add the tube.
303 fComponentAnalyticField->AddTube(rTube, vTube, 0, "t");
304
305 fSensor->AddComponent(fComponentAnalyticField);
306
307}
308
309void GarfieldPhysics::DoIt(std::string particleName, double ekin_MeV,
310 double time, double x_cm, double y_cm, double z_cm, double dx,
311 double dy, double dz) {
312
313 G4AnalysisManager* analysisManager = G4AnalysisManager::Instance();
314 fEnergyDeposit = 0;
316
317// Wire radius [cm]
318 const double rWire = 25.e-4;
319// Outer radius of the tube [cm]
320 const double rTube = 1.45;
321// Half-length of the tube [cm]
322 const double lTube = 10.;
323
324 double eKin_eV = ekin_MeV * 1e+6;
325
326 double xc = 0., yc = 0., zc = 0., tc = 0.;
327// Number of electrons produced in a collision
328 int nc = 0;
329// Energy loss in a collision
330 double ec = 0.;
331// Dummy variable (not used at present)
332 double extra = 0.;
333 fEnergyDeposit = 0;
334 if (fIonizationModel != "Heed" || particleName == "gamma") {
335 if (particleName == "gamma") {
336 fTrackHeed->TransportPhoton(x_cm, y_cm, z_cm, time, eKin_eV, dx, dy,
337 dz, nc);
338 } else {
339 fTrackHeed->TransportDeltaElectron(x_cm, y_cm, z_cm, time, eKin_eV,
340 dx, dy, dz, nc);
341 fEnergyDeposit = eKin_eV;
342 }
343
344 for (int cl = 0; cl < nc; cl++) {
345 double xe, ye, ze, te;
346 double ee, dxe, dye, dze;
347 fTrackHeed->GetElectron(cl, xe, ye, ze, te, ee, dxe, dye, dze);
348 if (ze < lTube && ze > -lTube && sqrt(xe * xe + ye * ye) < rTube) {
349 nsum++;
350 if (particleName == "gamma") {
351 fEnergyDeposit += fTrackHeed->GetW();
352 }
353 analysisManager->FillH3(1, ze * 10, xe * 10, ye * 10);
354 if (createSecondariesInGeant4) {
355 double newTime = te;
356 if (newTime < time) {
357 newTime += time;
358 }
359 fSecondaryParticles->push_back(
360 new GarfieldParticle("e-",ee, newTime, xe, ye, ze, dxe,
361 dye, dze));
362 }
363
364 fDrift->DriftElectron(xe, ye, ze, te);
365
366 double xe1, ye1, ze1, te1;
367 double xe2, ye2, ze2, te2;
368
369 int status;
370 fDrift->GetElectronEndpoint(0, xe1, ye1, ze1, te1, xe2, ye2,
371 ze2, te2, status);
372
373 if (0 < xe2 && xe2 < rWire) {
374 xe2 += 2 * rWire;
375 }
376 if (0 > xe2 && xe2 > -rWire) {
377 xe2 += -2 * rWire;
378 }
379 if (0 < ye2 && ye2 < rWire) {
380 ye2 += 2 * rWire;
381 }
382 if (0 > ye2 && ye2 > -rWire) {
383 ye2 += -2 * rWire;
384 }
385
386 double e2 = 0.1;
387 fAvalanche->AvalancheElectron(xe2, ye2, ze2, te2, e2, 0, 0, 0);
388
389 int ne = 0, ni = 0;
390 fAvalanche->GetAvalancheSize(ne, ni);
391 fAvalancheSize += ne;
392
393 }
394 }
395 } else {
396 fTrackHeed->SetParticle(particleName);
397 fTrackHeed->SetKineticEnergy(eKin_eV);
398 fTrackHeed->NewTrack(x_cm, y_cm, z_cm, time, dx, dy, dz);
399
400 while (fTrackHeed->GetCluster(xc, yc, zc, tc, nc, ec, extra)) {
401 if (zc < lTube && zc > -lTube && sqrt(xc * xc + yc * yc) < rTube) {
402 nsum += nc;
403 fEnergyDeposit += ec;
404 for (int cl = 0; cl < nc; cl++) {
405 double xe, ye, ze, te;
406 double ee, dxe, dye, dze;
407 fTrackHeed->GetElectron(cl, xe, ye, ze, te, ee, dxe, dye,
408 dze);
409 if (ze < lTube && ze > -lTube
410 && sqrt(xe * xe + ye * ye) < rTube) {
411 analysisManager->FillH3(1, ze * 10, xe * 10, ye * 10);
412 if (createSecondariesInGeant4) {
413 double newTime = te;
414 if (newTime < time) {
415 newTime += time;
416 }
417 fSecondaryParticles->push_back(
418 new GarfieldParticle("e-", ee, newTime, xe, ye,
419 ze, dxe, dye, dze));
420 }
421
422 fDrift->DriftElectron(xe, ye, ze, te);
423
424 double xe1, ye1, ze1, te1;
425 double xe2, ye2, ze2, te2;
426
427 int status;
428 fDrift->GetElectronEndpoint(0, xe1, ye1, ze1, te1, xe2,
429 ye2, ze2, te2, status);
430
431 if (0 < xe2 && xe2 < rWire) {
432 xe2 += 2 * rWire;
433 }
434 if (0 > xe2 && xe2 > -rWire) {
435 xe2 += -2 * rWire;
436 }
437 if (0 < ye2 && ye2 < rWire) {
438 ye2 += 2 * rWire;
439 }
440 if (0 > ye2 && ye2 > -rWire) {
441 ye2 += -2 * rWire;
442 }
443
444 double e2 = 0.1;
445 fAvalanche->AvalancheElectron(xe2, ye2, ze2, te2, e2, 0,
446 0, 0);
447
448 int ne = 0, ni = 0;
449 fAvalanche->GetAvalancheSize(ne, ni);
450 fAvalancheSize += ne;
451
452 }
453 }
454
455 }
456 }
457 }
458 fGain = fAvalancheSize / nsum;
459
460}
461
462std::vector<GarfieldParticle*>* GarfieldPhysics::GetSecondaryParticles() {
463 return fSecondaryParticles;
464}
465
467 if (!fSecondaryParticles->empty()) {
468 fSecondaryParticles->erase(fSecondaryParticles->begin(),
469 fSecondaryParticles->end());
470 }
471}
472
473
Selection of the analysis technology.
Definition of the GarfieldPhysics class.
std::map< const std::string, EnergyRange_MeV > MapParticlesEnergy
std::pair< double, double > EnergyRange_MeV
static void Dispose()
double GetMaxEnergyMeVParticle(std::string name, std::string program="garfield")
void DeleteSecondaryParticles()
static GarfieldPhysics * GetInstance()
std::vector< GarfieldParticle * > * GetSecondaryParticles()
void SetIonizationModel(std::string model, bool useDefaults=true)
double GetMinEnergyMeVParticle(std::string name, std::string program="garfield")
void AddParticleName(const std::string particleName, double ekin_min_MeV, double ekin_max_MeV, std::string program)
std::string GetIonizationModel()
void DoIt(std::string particleName, double ekin_MeV, double time, double x_cm, double y_cm, double z_cm, double dx, double dy, double dz)
bool FindParticleNameEnergy(std::string name, double ekin_MeV, std::string program="garfield")
bool FindParticleName(const std::string name, std::string program="garfield")
bool DriftElectron(const double x0, const double y0, const double z0, const double t0)
Simulate the drift line of an electron with a given starting point.
Definition: AvalancheMC.cc:210
void GetElectronEndpoint(const unsigned int i, double &x0, double &y0, double &z0, double &t0, double &x1, double &y1, double &z1, double &t1, int &status) const
Definition: AvalancheMC.cc:188
void SetSensor(Sensor *s)
Set the sensor.
Definition: AvalancheMC.cc:49
Calculate electron drift lines and avalanches using microscopic tracking.
void GetAvalancheSize(int &ne, int &ni) const
Return the number of electrons and ions in the avalanche.
void SetSensor(Sensor *sensor)
Set the sensor.
bool AvalancheElectron(const double x0, const double y0, const double z0, const double t0, const double e0, const double dx0=0., const double dy0=0., const double dz0=0.)
Calculate an avalanche initiated by a given electron.
void AddTube(const double radius, const double voltage, const int nEdges, const std::string &label)
Add a tube.
void AddWire(const double x, const double y, const double diameter, const double voltage, const std::string &label, const double length=100., const double tension=50., const double rho=19.3, const int ntrap=5)
Add a wire at (x, y) .
virtual void SetGeometry(GeometryBase *geo)
Define the geometry.
"Native" geometry, using simple shapes.
void AddSolid(Solid *s, Medium *m)
bool SetComposition(const std::string &gas1, const double f1=1., const std::string &gas2="", const double f2=0., const std::string &gas3="", const double f3=0., const std::string &gas4="", const double f4=0., const std::string &gas5="", const double f5=0., const std::string &gas6="", const double f6=0.)
Definition: MediumGas.cc:59
bool LoadGasFile(const std::string &filename)
Definition: MediumGas.cc:251
void EnablePenningTransfer(const double r, const double lambda)
bool Initialise(const bool verbose=false)
void SetTemperature(const double t)
Definition: Medium.cc:104
void DisableDebugging()
Definition: Medium.hh:291
void SetPressure(const double p)
Definition: Medium.cc:115
void EnableDebugging()
Definition: Medium.hh:290
void AddComponent(ComponentBase *comp)
Add a component.
Definition: Sensor.cc:314
Cylindrical tube.
Definition: SolidTube.hh:10
Generate tracks using Heed++.
Definition: TrackHeed.hh:37
virtual bool GetCluster(double &xcls, double &ycls, double &zcls, double &tcls, int &n, double &e, double &extra)
Definition: TrackHeed.cc:327
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, int &ni)
Definition: TrackHeed.cc:676
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, int &ni)
Definition: TrackHeed.cc:535
void EnableDeltaElectronTransport()
Definition: TrackHeed.hh:99
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:465
virtual 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:111
double GetW() const
Definition: TrackHeed.cc:1270
void SetSensor(Sensor *s)
Definition: Track.cc:185
void SetKineticEnergy(const double ekin)
Set the kinetic energy of the particle.
Definition: Track.cc:171
virtual void SetParticle(const std::string &part)
Set the type of particle.
Definition: Track.cc:29
void EnableDebugging()
Definition: Track.hh:76