CMS 3D CMS Logo

SiG4UniversalFluctuation.cc
Go to the documentation of this file.
1 
2 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
3 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
4 
5 #include <CLHEP/Random/RandFlat.h>
6 #include <CLHEP/Random/RandGaussQ.h>
7 #include <CLHEP/Random/RandPoissonQ.h>
8 #include <CLHEP/Units/GlobalPhysicalConstants.h>
9 #include <CLHEP/Units/SystemOfUnits.h>
11 #include "vdt/log.h"
12 #include <cmath>
13 
14 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
15 
16 using namespace std;
17 
19  : minNumberInteractionsBohr(10.0),
20  theBohrBeta2(50.0 * CLHEP::keV / proton_mass_c2),
21  minLoss(10. * CLHEP::eV),
22  problim(5.e-3),
23  alim(10.),
24  nmaxCont1(4.),
25  nmaxCont2(16.) {
26  sumalim = -log(problim);
27 
28  // Add these definitions d.k.
29  chargeSquare = 1.; // Assume all particles have charge 1
30  // Taken from Geant4 printout, HARDWIRED for Silicon.
31  ipotFluct = 0.0001736; // material->GetIonisation()->GetMeanExcitationEnergy();
32  electronDensity = 6.797E+20; // material->GetElectronDensity();
33  f1Fluct = 0.8571; // material->GetIonisation()->GetF1fluct();
34  f2Fluct = 0.1429; // material->GetIonisation()->GetF2fluct();
35  e1Fluct = 0.000116; // material->GetIonisation()->GetEnergy1fluct();
36  e2Fluct = 0.00196; // material->GetIonisation()->GetEnergy2fluct();
37  e1LogFluct = -9.063; // material->GetIonisation()->GetLogEnergy1fluct();
38  e2LogFluct = -6.235; // material->GetIonisation()->GetLogEnergy2fluct();
39  rateFluct = 0.4; // material->GetIonisation()->GetRateionexcfluct();
40  ipotLogFluct = -8.659; // material->GetIonisation()->GetLogMeanExcEnergy();
41  e0 = 1.E-5; // material->GetIonisation()->GetEnergy0fluct();
42 
43  // cout << " init new fluct +++++++++++++++++++++++++++++++++++++++++"<<endl;
44 }
45 
46 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
47 // The main dedx fluctuation routine.
48 // Arguments: momentum in MeV/c, mass in MeV, delta ray cut (tmax) in
49 // MeV, silicon thickness in mm, mean eloss in MeV.
50 
52 
53 double SiG4UniversalFluctuation::SampleFluctuations(const double momentum,
54  const double mass,
55  double &tmax,
56  const double length,
57  const double meanLoss,
58  CLHEP::HepRandomEngine *engine) {
59  // Calculate actual loss from the mean loss.
60  // The model used to get the fluctuations is essentially the same
61  // as in Glandz in Geant3 (Cern program library W5013, phys332).
62  // L. Urban et al. NIM A362, p.416 (1995) and Geant4 Physics Reference Manual
63 
64  // shortcut for very very small loss (out of validity of the model)
65  //
66  if (meanLoss < minLoss)
67  return meanLoss;
68 
70  double gam2 = (momentum * momentum) / (particleMass * particleMass) + 1.0;
71  double beta2 = 1.0 - 1.0 / gam2;
72  double gam = sqrt(gam2);
73 
74  double loss(0.), siga(0.);
75 
76  // Gaussian regime
77  // for heavy particles only and conditions
78  // for Gauusian fluct. has been changed
79  //
80  if ((particleMass > electron_mass_c2) && (meanLoss >= minNumberInteractionsBohr * tmax)) {
81  double massrate = electron_mass_c2 / particleMass;
82  double tmaxkine = 2. * electron_mass_c2 * beta2 * gam2 / (1. + massrate * (2. * gam + massrate));
83  if (tmaxkine <= 2. * tmax) {
84  siga = (1.0 / beta2 - 0.5) * twopi_mc2_rcl2 * tmax * length * electronDensity * chargeSquare;
85  siga = sqrt(siga);
86  double twomeanLoss = meanLoss + meanLoss;
87  if (twomeanLoss < siga) {
88  double x;
89  do {
90  loss = twomeanLoss * CLHEP::RandFlat::shoot(engine);
91  x = (loss - meanLoss) / siga;
92  } while (1.0 - 0.5 * x * x < CLHEP::RandFlat::shoot(engine));
93  } else {
94  do {
95  loss = CLHEP::RandGaussQ::shoot(engine, meanLoss, siga);
96  } while (loss < 0. || loss > twomeanLoss);
97  }
98  return loss;
99  }
100  }
101 
102  double a1 = 0., a2 = 0., a3 = 0.;
103  double p3;
104  double rate = rateFluct;
105 
106  double w1 = tmax / ipotFluct;
107  double w2 = vdt::fast_log(2. * electron_mass_c2 * beta2 * gam2) - beta2;
108 
109  if (w2 > ipotLogFluct) {
110  double C = meanLoss * (1. - rateFluct) / (w2 - ipotLogFluct);
111  a1 = C * f1Fluct * (w2 - e1LogFluct) / e1Fluct;
112  a2 = C * f2Fluct * (w2 - e2LogFluct) / e2Fluct;
113  if (a2 < 0.) {
114  a1 = 0.;
115  a2 = 0.;
116  rate = 1.;
117  }
118  } else {
119  rate = 1.;
120  }
121 
122  // added
123  if (tmax > ipotFluct) {
124  a3 = rate * meanLoss * (tmax - ipotFluct) / (ipotFluct * tmax * vdt::fast_log(w1));
125  }
126  double suma = a1 + a2 + a3;
127 
128  // Glandz regime
129  //
130  if (suma > sumalim) {
131  if ((a1 + a2) > 0.) {
132  double p1, p2;
133  // excitation type 1
134  if (a1 > alim) {
135  siga = sqrt(a1);
136  p1 = max(0., CLHEP::RandGaussQ::shoot(engine, a1, siga) + 0.5);
137  } else {
138  p1 = double(CLHEP::RandPoissonQ::shoot(engine, a1));
139  }
140 
141  // excitation type 2
142  if (a2 > alim) {
143  siga = sqrt(a2);
144  p2 = max(0., CLHEP::RandGaussQ::shoot(engine, a2, siga) + 0.5);
145  } else {
146  p2 = double(CLHEP::RandPoissonQ::shoot(engine, a2));
147  }
148 
149  loss = p1 * e1Fluct + p2 * e2Fluct;
150 
151  // smearing to avoid unphysical peaks
152  if (p2 > 0.)
153  loss += (1. - 2. * CLHEP::RandFlat::shoot(engine)) * e2Fluct;
154  else if (loss > 0.)
155  loss += (1. - 2. * CLHEP::RandFlat::shoot(engine)) * e1Fluct;
156  if (loss < 0.)
157  loss = 0.0;
158  }
159 
160  // ionisation
161  if (a3 > 0.) {
162  if (a3 > alim) {
163  siga = sqrt(a3);
164  p3 = max(0., CLHEP::RandGaussQ::shoot(engine, a3, siga) + 0.5);
165  } else {
166  p3 = double(CLHEP::RandPoissonQ::shoot(engine, a3));
167  }
168  double lossc = 0.;
169  if (p3 > 0) {
170  double na = 0.;
171  double alfa = 1.;
172  if (p3 > nmaxCont2) {
173  double rfac = p3 / (nmaxCont2 + p3);
174  double namean = p3 * rfac;
175  double sa = nmaxCont1 * rfac;
176  na = CLHEP::RandGaussQ::shoot(engine, namean, sa);
177  if (na > 0.) {
178  alfa = w1 * (nmaxCont2 + p3) / (w1 * nmaxCont2 + p3);
179  double alfa1 = alfa * vdt::fast_log(alfa) / (alfa - 1.);
180  double ea = na * ipotFluct * alfa1;
181  double sea = ipotFluct * sqrt(na * (alfa - alfa1 * alfa1));
182  lossc += CLHEP::RandGaussQ::shoot(engine, ea, sea);
183  }
184  }
185 
186  if (p3 > na) {
187  w2 = alfa * ipotFluct;
188  double w = (tmax - w2) / tmax;
189  int nb = int(p3 - na);
190  for (int k = 0; k < nb; k++)
191  lossc += w2 / (1. - w * CLHEP::RandFlat::shoot(engine));
192  }
193  }
194  loss += lossc;
195  }
196  return loss;
197  }
198 
199  // suma < sumalim; very small energy loss;
200  a3 = meanLoss * (tmax - e0) / (tmax * e0 * vdt::fast_log(tmax / e0));
201  if (a3 > alim) {
202  siga = sqrt(a3);
203  p3 = max(0., CLHEP::RandGaussQ::shoot(engine, a3, siga) + 0.5);
204  } else {
205  p3 = double(CLHEP::RandPoissonQ::shoot(engine, a3));
206  }
207  if (p3 > 0.) {
208  double w = (tmax - e0) / tmax;
209  double corrfac = 1.;
210  if (p3 > nmaxCont2) {
211  corrfac = p3 / nmaxCont2;
212  p3 = nmaxCont2;
213  }
214  int ip3 = (int)p3;
215  for (int i = 0; i < ip3; i++)
216  loss += 1. / (1. - w * CLHEP::RandFlat::shoot(engine));
217  loss *= e0 * corrfac;
218  // smearing for losses near to e0
219  if (p3 <= 2.)
220  loss += e0 * (1. - 2. * CLHEP::RandFlat::shoot(engine));
221  }
222 
223  return loss;
224 }
common ppss p3p6s2 common epss epspn46 common const1 w2
Definition: inclppp.h:1
T w() const
T sqrt(T t)
Definition: SSEVec.h:23
static const double tmax[3]
double SampleFluctuations(const double momentum, const double mass, double &tmax, const double length, const double meanLoss, CLHEP::HepRandomEngine *)
double rate(double x)
Definition: Constants.cc:3