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