BmnRoot
Loading...
Searching...
No Matches
BmnSsdPhysics.cxx
Go to the documentation of this file.
1
7#include <fstream>
8#include <iomanip>
9#include "BmnSsdPhysics.h"
10#include "TDatabasePDG.h"
11#include "TMath.h"
12#include "TRandom.h"
13#include "TSystem.h"
14#include "FairLogger.h"
15
16
17using std::ifstream;
18using std::right;
19using std::setw;
20using std::map;
21
22// ----- Initialisation of static variables ----------------------------
23BmnSsdPhysics* BmnSsdPhysics::fgInstance = NULL;
24const Double_t BmnSsdPhysics::fgkSiCharge = 14.;
25const Double_t BmnSsdPhysics::fgkSiDensity = 2.336; // g/cm^3
26const Double_t BmnSsdPhysics::fgkProtonMass = 0.938272081; // GeV
27// -------------------------------------------------------------------------
28
29
30
31// ----- Constructor ---------------------------------------------------
32BmnSsdPhysics::BmnSsdPhysics()
33 : fUrbanI(0.),
34 fUrbanE1(0.),
35 fUrbanE2(0.),
36 fUrbanF1(0.),
37 fUrbanF2(0.),
38 fUrbanEmax(0.),
39 fUrbanR(0.),
40 fStoppingElectron(),
41 fStoppingProton(),
42 fLandauWidth()
43
44{
45 // --- Read the energy loss data tables
46 LOG(info) << "Instantiating SSD Physics... ";
47 ReadDataTablesStoppingPower();
48 ReadDataTablesLandauWidth();
49
50 // --- Initialise the constants for the Urban model
51 SetUrbanParameters(fgkSiCharge);
52}
53// -------------------------------------------------------------------------
54
55
56
57// ----- Destructor ----------------------------------------------------
60// -------------------------------------------------------------------------
61
62
63
64// ----- Diffusion width -----------------------------------------------
65Double_t BmnSsdPhysics::DiffusionWidth(Double_t z, Double_t d,
66 Double_t vBias, Double_t vFd,
67 Double_t temperature,
68 Int_t chargeType) {
69
70
71 // --- Check parameters
72 if ( z < 0. || z > d ) {
73 LOG(error) << "SsdPhysics: z coordinate " << z
74 << " not inside sensor (d = " << d << ")"
75 ;
76 return -1.;
77 }
78 if ( temperature < 0. ) {
79 LOG(error) << "SsdPhysics: illegal temperature value "
80 << temperature;
81 return -1.;
82 }
83
84 // --- Diffusion constant over mobility [J/C]
85 // --- The numerical factor is k_B/e in units of J/(KC).
86 Double_t diffConst = 8.61733e-5 * temperature;
87
88 // --- Drift time times mobility [cm**2 * C / J]
89 // For the formula, see the SSD digitiser note.
90 Double_t tau = 0.;
91 if ( chargeType == 0 ) { // electrons, drift to n (front) side
92 tau = 0.5 * d * d / vFd
93 * log( ( vBias + ( 1. - 2. * z / d ) * vFd ) / ( vBias - vFd ) );
94 }
95 else if ( chargeType == 1 ) { // holes, drift to the p (back) side
96 tau = -0.5 * d * d / vFd
97 * log( 1. - 2. * vFd * z / d / ( vBias + vFd ) );
98 }
99 else {
100 LOG(error) << "SsdPhysics: Illegal charge type " << chargeType
101 ;
102 return -1.;
103 }
104
105 return sqrt(2. * diffConst * tau);
106}
107// -------------------------------------------------------------------------
108
109
110
111// ----- Electric field ------------------------------------------------
112Double_t BmnSsdPhysics::ElectricField(Double_t vBias, Double_t vFd,
113 Double_t dZ, Double_t z) {
114 return ( vBias + vFd * (2. * z / dZ - 1.) ) / dZ;
115}
116// -------------------------------------------------------------------------
117
118
119
120// ----- Energy loss from fluctuation model ----------------------------
121Double_t BmnSsdPhysics::EnergyLoss(Double_t dz, Double_t mass, Double_t eKin,
122 Double_t dedx) const {
123
124 // Gamma and beta
125 Double_t gamma = (eKin + mass) / mass;
126 Double_t beta2 = 1. - 1. / ( gamma * gamma );
127
128 // Auxiliary
129 Double_t xAux = 2. * mass * beta2 * gamma * gamma;
130
131 // Mean energy losses (PHYS333 2.4 eqs. (2) and (3))
132 Double_t sigma1 = dedx * fUrbanF1 / fUrbanE1
133 * ( TMath::Log(xAux / fUrbanE1) - beta2 )
134 / ( TMath::Log(xAux / fUrbanI) - beta2 )
135 * (1. - fUrbanR);
136 Double_t sigma2 = dedx * fUrbanF2 / fUrbanE2
137 * ( TMath::Log(xAux / fUrbanE2) - beta2 )
138 / ( TMath::Log(xAux / fUrbanI) - beta2 )
139 * (1. - fUrbanR);
140 Double_t sigma3 = dedx * fUrbanEmax * fUrbanR
141 / ( fUrbanI * ( fUrbanEmax + fUrbanI ) )
142 / TMath::Log( (fUrbanEmax + fUrbanI) / fUrbanI );
143
144 // Sample number of processes Poissonian energy loss distribution
145 // (PHYS333 2.4 eq. (6))
146 Int_t n1 = gRandom->Poisson( sigma1 * dz );
147 Int_t n2 = gRandom->Poisson( sigma2 * dz );
148 Int_t n3 = gRandom->Poisson( sigma3 * dz );
149
150 // Ion energy loss (PHYS333 2.4 eq. (12))
151 Double_t eLossIon = 0.;
152 for (Int_t j = 1; j <= n3; j++) {
153 Double_t uni = gRandom->Uniform(1.);
154 eLossIon += fUrbanI
155 / ( 1. - uni * fUrbanEmax / ( fUrbanEmax + fUrbanI ) );
156 }
157
158 // Total energy loss
159 return (n1 * fUrbanE1 + n2 * fUrbanE2 + eLossIon);
160
161}
162// -------------------------------------------------------------------------
163
164
165
166// ----- Get static instance ---------------------------------------------
168 if ( ! fgInstance ) fgInstance = new BmnSsdPhysics();
169 return fgInstance;
170}
171// -------------------------------------------------------------------------
172
173
174
175// ----- Interpolate a value from a data table --------
176Double_t BmnSsdPhysics::InterpolateDataTable(Double_t eEquiv,
177 map<Double_t, Double_t>& table) {
178
179 std::map<Double_t, Double_t>::iterator it = table.lower_bound(eEquiv);
180
181 // Input value smaller than or equal to first table entry:
182 // return first value
183 if ( it == table.begin() ) return it->second;
184
185 // Input value larger than last table entry: return last value
186 if ( it == table.end() ) return (--it)->second;
187
188 // Else: interpolate from table values
189 Double_t e2 = it->first;
190 Double_t v2 = it->second;
191 it--;
192 Double_t e1 = it->first;
193 Double_t v1 = it->second;
194 return ( v1 + ( eEquiv - e1 ) * ( v2 - v1 ) / ( e2 - e1 ) );
195
196}
197// -------------------------------------------------------------------------
198
199
200
201// ----- Landau Width ------------------------------------------------
202Double_t BmnSsdPhysics::LandauWidth(Double_t mostProbableCharge) {
203
204 // --- Get interpolated value from the data table
205 return InterpolateDataTable(mostProbableCharge, fLandauWidth);
206}
207// -------------------------------------------------------------------------
208
209
210
211// ----- Particle charge for PDG PID ------------------------------------
212Double_t BmnSsdPhysics::ParticleCharge(Int_t pid) {
213
214 Double_t charge = 0.;
215
216 // --- For particles in the TDatabasePDG. Note that TParticlePDG
217 // --- gives the charge in units of |e|/3, God knows why.
218 TParticlePDG* particle = TDatabasePDG::Instance()->GetParticle(pid);
219 if ( particle ) charge = particle->Charge() / 3.;
220
221 // --- For ions
222 else if ( pid > 1000000000 && pid < 1010000000 ) {
223 Int_t myPid = pid / 10000;
224 charge = Double_t( myPid - ( myPid / 1000 ) * 1000 );
225 }
226
227 return charge;
228}
229// -------------------------------------------------------------------------
230
231
232
233// ----- Particle mass for PDG PID ------------------------------------
234Double_t BmnSsdPhysics::ParticleMass(Int_t pid) {
235
236 Double_t mass = -1.;
237
238 // --- For particles in the TDatabasePDG
239 TParticlePDG* particle = TDatabasePDG::Instance()->GetParticle(pid);
240 if ( particle ) mass = particle->Mass();
241
242 // --- For ions
243 else if ( pid > 1000000000 && pid < 1010000000 ) {
244 Int_t myPid = pid - 1e9;
245 myPid -= (myPid / 10000 ) * 10000;
246 mass = Double_t( myPid / 10 );
247 }
248
249 return mass;
250}
251// -------------------------------------------------------------------------
252
253
254
255// ----- Read data tables for stopping power ---------------------------
256void BmnSsdPhysics::ReadDataTablesLandauWidth() {
257
258 // The table with errors for Landau distribution:
259 // MP charge (e) --> half width of charge distribution (e)
260
261 TString dir = gSystem->Getenv("VMCWORKDIR");
262 TString errFileName = dir + "/parameters/ssd/LandauWidthTable.txt";
263
264 ifstream inFile;
265 Double_t q, err;
266
267 // --- Read electron stopping power
268 inFile.open(errFileName);
269 if ( inFile.is_open() ) {
270 while (true) {
271 inFile >> q;
272 inFile >> err;
273 if ( inFile.eof() ) break;
274 fLandauWidth[q] = err;
275 }
276 inFile.close();
277 LOG(info) << "SsdPhysics: " << setw(5) << right
278 << fLandauWidth.size() << " values read from "
279 << errFileName;
280 }
281 else
282 LOG(fatal) << "SsdPhysics: Could not read from " << errFileName
283 ;
284
285}
286// -------------------------------------------------------------------------
287
288
289
290// ----- Read data tables for stopping power ---------------------------
291void BmnSsdPhysics::ReadDataTablesStoppingPower() {
292
293 // The data tables are obtained from the NIST ESTAR and PSTAR databases:
294 // http://www.nist.gov/pml/data/star/index.cfm
295 // The first column in the tables is the kinetic energy in MeV, the second
296 // one is the specific stopping power in MeV*cm^2/g for Silicon.
297 // Internally, the values are stored in GeV and GeV*cm^2/g, respectively.
298 // Conversion MeV->GeV is done when reading from file.
299
300 TString dir = gSystem->Getenv("VMCWORKDIR");
301 TString eFileName = dir + "/parameters/ssd/dEdx_Si_e.txt";
302 TString pFileName = dir + "/parameters/ssd/dEdx_Si_p.txt";
303
304 ifstream inFile;
305 Double_t e, dedx;
306
307 // --- Read electron stopping power
308 inFile.open(eFileName);
309 if ( inFile.is_open() ) {
310 while (true) {
311 inFile >> e;
312 inFile >> dedx;
313 if ( inFile.eof() ) break;
314 e *= 1.e-3; // MeV -> GeV
315 dedx *= 1.e-3; // MeV -> GeV
316 fStoppingElectron[e] = dedx;
317 }
318 inFile.close();
319 LOG(info) << "SsdPhysics: " << setw(5) << right
320 << fStoppingElectron.size() << " values read from "
321 << eFileName;
322 }
323 else
324 LOG(fatal) << "SsdPhysics: Could not read from " << eFileName
325 ;
326
327 // --- Read proton stopping power
328 inFile.open(pFileName);
329 if ( inFile.is_open() ) {
330 while (true) {
331 inFile >> e;
332 inFile >> dedx;
333 if ( inFile.eof() ) break;
334 e *= 1.e-3; // MeV -> GeV
335 dedx *= 1.e-3; // MeV -> GeV
336 fStoppingProton[e] = dedx;
337 }
338 inFile.close();
339 LOG(info) << "SsdPhysics: " << setw(5) << right
340 << fStoppingProton.size() << " values read from "
341 << pFileName;
342 }
343 else
344 LOG(fatal) << "SsdPhysics: Could not read from " << pFileName
345 ;
346
347}
348// -------------------------------------------------------------------------
349
350
351
352// ----- Set the parameters for the Urban model ------------------------
353void BmnSsdPhysics::SetUrbanParameters(Double_t z) {
354
355 // --- Mean ionisation potential according to PHYS333 2.1
356 fUrbanI = 1.6e-8 * TMath::Power(z, 0.9); // in GeV
357
358 // --- Maximal energy loss (delta electron threshold) [GeV]
359 // TODO: 1 MeV is the default setting in our transport simulation.
360 // It would be desirable to obtain the actually used value automatically.
361 fUrbanEmax = 1.e-3;
362
363 // --- The following parameters were defined according the GEANT3 choice
364 // --- described in PHYS332 2.4 (p.264)
365
366 // --- Oscillator strengths of energy levels
367 fUrbanF1 = 1. - 2. / z;
368 fUrbanF2 = 2. / z;
369
370 // --- Energy levels [GeV]
371 fUrbanE2= 1.e-8 * z * z;
372 fUrbanE1
373 = TMath::Power(fUrbanI / TMath::Power(fUrbanE2, fUrbanF2), 1./fUrbanF1);
374
375 // --- Relative weight excitation / ionisation
376 fUrbanR = 0.4;
377
378 // --- Screen output
379 LOG(info) << "SsdPhysics: Urban parameters for z = " << z << " :"
380 ;
381 LOG(info) << "I = " << fUrbanI*1.e9 << " eV, Emax = " << fUrbanEmax*1.e9
382 << " eV, E1 = " << fUrbanE1*1.e9 << " eV, E2 = "
383 << fUrbanE2*1.e9 << " eV, f1 = " << fUrbanF1 << ", f2 = "
384 << fUrbanF2 << ", r = " << fUrbanR;
385
386}
387// -------------------------------------------------------------------------
388
389
390
391// ----- Stopping power ------------------------------------------------
392Double_t BmnSsdPhysics::StoppingPower(Double_t eKin, Int_t pid) {
393
394 Double_t mass = ParticleMass(pid);
395 if ( mass < 0. ) return 0.;
396 Double_t charge = ParticleCharge(pid);
397 Bool_t isElectron = ( pid == 11 || pid == -11 );
398
399 return StoppingPower(eKin, mass, charge, isElectron);
400}
401// -------------------------------------------------------------------------
402
403
404
405// ----- Stopping power ------------------------------------------------
406Double_t BmnSsdPhysics::StoppingPower(Double_t energy,
407 Double_t mass,
408 Double_t charge,
409 Bool_t isElectron) {
410
411 // --- Get interpolated value from data table
412 Double_t stopPower = -1.;
413 if ( isElectron )
414 stopPower = InterpolateDataTable(energy, fStoppingElectron);
415 else {
416 Double_t eEquiv = energy * fgkProtonMass / mass; // equiv. proton energy
417 stopPower = InterpolateDataTable(eEquiv, fStoppingProton);
418 }
419
420 // --- Calculate stopping power (from specific SP and density of silicon)
421 stopPower *= fgkSiDensity; // density of silicon
422
423 // --- For non-electrons: scale with squared charge
424 if ( ! isElectron ) stopPower *= ( charge * charge );
425
426 return stopPower;
427}
428// -------------------------------------------------------------------------
const Float_t d
Z-ccordinate of the first GEM-station.
Definition BmnMwpcHit.cxx:7
friend F32vec4 sqrt(const F32vec4 &a)
Definition P4_F32vec4.h:34
friend F32vec4 log(const F32vec4 &a)
Definition P4_F32vec4.h:123
Auxiliary class for simulating physics processes in Silicon.
static Double_t ParticleMass(Int_t pid)
static Double_t ParticleCharge(Int_t pid)
Double_t StoppingPower(Double_t eKin, Int_t pid)
virtual ~BmnSsdPhysics()
static Double_t DiffusionWidth(Double_t z, Double_t d, Double_t vBias, Double_t vFd, Double_t temperature, Int_t chargeType)
static Double_t ElectricField(Double_t vBias, Double_t vFd, Double_t dZ, Double_t z)
Double_t EnergyLoss(Double_t dz, Double_t mass, Double_t eKin, Double_t dedx) const
Double_t LandauWidth(Double_t mostProbableCharge)
static BmnSsdPhysics * Instance()