Belle II Software  release-08-01-10
G4mplIonisationWithDeltaModel.cc
1 /**************************************************************************
2  * basf2 (Belle II Analysis Software Framework) *
3  * Author: The Belle II Collaboration *
4  * *
5  * See git log for contributors and copyright holders. *
6  * This file is licensed under LGPL-3.0, see LICENSE.md. *
7  **************************************************************************/
8 
9 // References
10 // [1] Steven P. Ahlen: Energy loss of relativistic heavy ionizing particles,
11 // S.P. Ahlen, Rev. Mod. Phys 52(1980), p121
12 // [2] K.A. Milton arXiv:hep-ex/0602040
13 // [3] S.P. Ahlen and K. Kinoshita, Phys. Rev. D26 (1982) 2347
14 // [4] Y. Kazama et al., Phys. Rev. D15 (1977) 2287-2299
15 // [5] S.P. Ahlen, Phys. Rev. D17 (1978) 229-233
16 
17 // modified from GEANT4 exoticphysics/monopole/*
18 
19 #include <simulation/monopoles/G4mplIonisationWithDeltaModel.h>
20 
21 #include <Randomize.hh>
22 #include <CLHEP/Units/PhysicalConstants.h>
23 #include <CLHEP/Units/SystemOfUnits.h>
24 #include <G4ParticleChangeForLoss.hh>
25 #include <G4Electron.hh>
26 #include <G4DynamicParticle.hh>
27 #include <G4ProductionCutsTable.hh>
28 #include <G4MaterialCutsCouple.hh>
29 #include <G4Log.hh>
30 #include <G4Pow.hh>
31 
32 #include <framework/logging/Logger.h>
33 
34 using namespace std;
35 using namespace Belle2;
36 using namespace Belle2::Monopoles;
37 using namespace CLHEP;
38 
39 std::vector<G4double>* G4mplIonisationWithDeltaModel::dedx0 = nullptr;
40 
41 G4mplIonisationWithDeltaModel::G4mplIonisationWithDeltaModel(G4double mCharge,
42  const G4String& nam)
43  : G4VEmModel(nam), G4VEmFluctuationModel(nam),
44  magCharge(mCharge),
45  twoln10(log(100.0)),
46  betalow(0.01),
47  betalim(0.1),
48  beta2lim(betalim * betalim),
49  bg2lim(beta2lim * (1.0 + beta2lim)),
50  pi_hbarc2_over_mc2(pi * hbarc * hbarc / electron_mass_c2)
51 {
52  nmpl = magCharge * 2 * fine_structure_const;
53  chargeSquare = magCharge * magCharge * 4 * fine_structure_const *
54  fine_structure_const;
55  //NOTE Formulas below assume Dirac charge units for magnetic charge, g_D = 68.5e
56  dedxlim = 45. * chargeSquare * GeV * cm2 / g;
57  fParticleChange = nullptr;
58  theElectron = G4Electron::Electron();
59  B2INFO("Monopole ionisation model with d-electron production, Gmag= " << magCharge / eplus);
60  if (nmpl >= 6)
61  B2WARNING("Monopole charge Gmag= " << magCharge / eplus << "e not reasonable. Please choose a value smaller than 411e.");
62  monopole = nullptr;
63  mass = 0.0;
64 }
65 
67 {
68  if (IsMaster()) { delete dedx0; }
69 }
70 
71 void G4mplIonisationWithDeltaModel::SetParticle(const G4ParticleDefinition* p)
72 {
73  monopole = p;
74  mass = monopole->GetPDGMass();
75  G4double emin =
76  std::min(LowEnergyLimit(), 0.1 * mass * (1. / sqrt(1. - betalow * betalow) - 1.));
77  G4double emax =
78  std::max(HighEnergyLimit(), 10 * mass * (1. / sqrt(1. - beta2lim) - 1.));
79  SetLowEnergyLimit(emin);
80  SetHighEnergyLimit(emax);
81 }
82 
83 void
84 G4mplIonisationWithDeltaModel::Initialise(const G4ParticleDefinition* p,
85  const G4DataVector&)
86 {
87  if (!monopole) { SetParticle(p); }
88  if (!fParticleChange) { fParticleChange = GetParticleChangeForLoss(); }
89  if (IsMaster()) {
90  if (!dedx0) { dedx0 = new std::vector<G4double>; }
91  G4ProductionCutsTable* theCoupleTable =
92  G4ProductionCutsTable::GetProductionCutsTable();
93  G4int numOfCouples = theCoupleTable->GetTableSize();
94  G4int n = dedx0->size();
95  if (n < numOfCouples) { dedx0->resize(numOfCouples); }
96  G4Pow* g4calc = G4Pow::GetInstance();
97 
98  // initialise vector
99  for (G4int i = 0; i < numOfCouples; ++i) {
100 
101  const G4Material* material =
102  theCoupleTable->GetMaterialCutsCouple(i)->GetMaterial();
103  G4double eDensity = material->GetElectronDensity();
104  G4double vF = electron_Compton_length * g4calc->A13(3.*pi * pi * eDensity);
105  (*dedx0)[i] = pi_hbarc2_over_mc2 * eDensity * chargeSquare *
106  (G4Log(2 * vF / fine_structure_const) - 0.5) / vF;
107  }
108  }
109 }
110 
111 G4double
113  const G4MaterialCutsCouple* couple)
114 {
115  return couple->GetMaterial()->GetIonisation()->GetMeanExcitationEnergy();
116 }
117 
118 G4double
120  const G4ParticleDefinition* p,
121  G4double kineticEnergy,
122  G4double maxEnergy)
123 {
124  if (!monopole) { SetParticle(p); }
125  G4double tmax = MaxSecondaryEnergy(p, kineticEnergy);
126  G4double cutEnergy = std::min(tmax, maxEnergy);
127  cutEnergy = std::max(LowEnergyLimit(), cutEnergy);
128  G4double tau = kineticEnergy / mass;
129  G4double gam = tau + 1.0;
130  G4double bg2 = tau * (tau + 2.0);
131  G4double beta2 = bg2 / (gam * gam);
132  G4double beta = sqrt(beta2);
133 
134  // low-energy asymptotic formula
135  //G4double dedx = dedxlim*beta*material->GetDensity();
136  G4double dedx = (*dedx0)[CurrentCouple()->GetIndex()] * beta;
137 
138  // above asymptotic
139  if (beta > betalow) {
140 
141  // high energy
142  if (beta >= betalim) {
143  dedx = ComputeDEDXAhlen(material, bg2, cutEnergy);
144 
145  } else {
146 
147  //G4double dedx1 = dedxlim*betalow*material->GetDensity();
148  G4double dedx1 = (*dedx0)[CurrentCouple()->GetIndex()] * betalow;
149  G4double dedx2 = ComputeDEDXAhlen(material, bg2lim, cutEnergy);
150 
151  // extrapolation between two formula
152  G4double kapa2 = beta - betalow;
153  G4double kapa1 = betalim - beta;
154  dedx = (kapa1 * dedx1 + kapa2 * dedx2) / (kapa1 + kapa2);
155  }
156  }
157  return dedx;
158 }
159 
160 G4double
162  G4double bg2,
163  G4double cutEnergy)
164 {
165  G4double eDensity = material->GetElectronDensity();
166  G4double eexc = material->GetIonisation()->GetMeanExcitationEnergy();
167 
168  // Ahlen's formula for nonconductors, [1]p157, f(5.7)
169  G4double dedx =
170  0.5 * (G4Log(2.0 * electron_mass_c2 * bg2 * cutEnergy / (eexc * eexc)) - 1.0);//"Conventional" ionisation
171 // G4double dedx =
172 // 1.0 * (G4Log(2.0 * electron_mass_c2 * bg2 * cutEnergy / (eexc * eexc)));//Fryberger magneticon double ionisation
173 
174 
175  G4double k = 0; // Cross-section correction
176  if (nmpl >= 0.5) { k = 0.406; }
177  if (nmpl >= 1) { k = 0.346; }
178  if (nmpl >= 1.5) { k = 0.3; }
179  const G4double B[7] = { 0.0, 0.248, 0.672, 1.022, 1.243, 1.464, 1.685}; // Bloch correction
180  if (nmpl < 6)
181  dedx += 0.5 * k - B[int(floor(nmpl + 0.5))];
182 
183 
184  // density effect correction
185  G4double x = G4Log(bg2) / twoln10;
186  dedx -= material->GetIonisation()->DensityCorrection(x);
187 
188  // now compute the total ionization loss
189  dedx *= pi_hbarc2_over_mc2 * eDensity * chargeSquare;
190 
191  dedx = std::max(dedx, 0.0);
192  return dedx;
193 }
194 
195 G4double
197  const G4ParticleDefinition* p,
198  G4double kineticEnergy,
199  G4double cut,
200  G4double maxKinEnergy)
201 {
202  if (!monopole) { SetParticle(p); }
203  G4double tmax = MaxSecondaryEnergy(p, kineticEnergy);
204  G4double maxEnergy = std::min(tmax, maxKinEnergy);
205  G4double cutEnergy = std::max(LowEnergyLimit(), cut);
206  G4double cross = (cutEnergy < maxEnergy)
207  ? (1.0 / cutEnergy - 1.0 / maxEnergy) * twopi_mc2_rcl2 * chargeSquare : 0.0; //cross section used in ATLAS
208 // G4double cross = (cutEnergy < maxEnergy)
209 // ? (0.5 / cutEnergy - 0.5 / maxEnergy) * pi_hbarc2_over_mc2 * chargeSquare : 0.0; //one coming with GEANT4; causes 4 orders higher values
210  return cross;
211 }
212 
213 G4double
215  const G4ParticleDefinition* p,
216  G4double kineticEnergy,
217  G4double Z, G4double,
218  G4double cutEnergy,
219  G4double maxEnergy)
220 {
221  G4double cross =
222  Z * ComputeCrossSectionPerElectron(p, kineticEnergy, cutEnergy, maxEnergy);
223  return cross;
224 }
225 
226 void
227 G4mplIonisationWithDeltaModel::SampleSecondaries(vector<G4DynamicParticle*>* vdp,
228  const G4MaterialCutsCouple*,
229  const G4DynamicParticle* dp,
230  G4double minKinEnergy,
231  G4double maxEnergy)
232 {
233  G4double kineticEnergy = dp->GetKineticEnergy();
234  G4double tmax = MaxSecondaryEnergy(dp->GetDefinition(), kineticEnergy);
235 
236  G4double maxKinEnergy = std::min(maxEnergy, tmax);
237  if (minKinEnergy >= maxKinEnergy) { return; }
238 
239  G4double totEnergy = kineticEnergy + mass;
240  G4double etot2 = totEnergy * totEnergy;
241  G4double beta2 = kineticEnergy * (kineticEnergy + 2.0 * mass) / etot2;
242 
243  // sampling without nuclear size effect
244  G4double q = G4UniformRand();
245  G4double deltaKinEnergy = minKinEnergy * maxKinEnergy
246  / (minKinEnergy * (1.0 - q) + maxKinEnergy * q);
247 
248  // delta-electron is produced
249  G4double totMomentum = totEnergy * sqrt(beta2);
250  G4double deltaMomentum =
251  sqrt(deltaKinEnergy * (deltaKinEnergy + 2.0 * electron_mass_c2));
252  G4double cost = deltaKinEnergy * (totEnergy + electron_mass_c2) /
253  (deltaMomentum * totMomentum);
254  cost = std::min(cost, 1.0);
255 
256  G4double sint = sqrt((1.0 - cost) * (1.0 + cost));
257 
258  G4double phi = twopi * G4UniformRand() ;
259 
260  G4ThreeVector deltaDirection(sint * cos(phi), sint * sin(phi), cost);
261  G4ThreeVector direction = dp->GetMomentumDirection();
262  deltaDirection.rotateUz(direction);
263 
264  // create G4DynamicParticle object for delta ray
265  G4DynamicParticle* delta =
266  new G4DynamicParticle(theElectron, deltaDirection, deltaKinEnergy);
267 
268  vdp->push_back(delta);
269 
270  // Change kinematics of primary particle
271  kineticEnergy -= deltaKinEnergy;
272  G4ThreeVector finalP = direction * totMomentum - deltaDirection * deltaMomentum;
273  finalP = finalP.unit();
274 
275  fParticleChange->SetProposedKineticEnergy(kineticEnergy);
276  fParticleChange->SetProposedMomentumDirection(finalP);
277 }
278 
280  const G4MaterialCutsCouple* couple,
281  const G4DynamicParticle* dp,
282  G4double tcut,
283  G4double tmax,
284  G4double length,
285  G4double meanLoss)
286 {
287  G4double siga = Dispersion(couple->GetMaterial(), dp, tcut, tmax, length);
288  G4double loss = meanLoss;
289  siga = sqrt(siga);
290  G4double twomeanLoss = meanLoss + meanLoss;
291 
292  if (twomeanLoss < siga) {
293  G4double x;
294  do {
295  loss = twomeanLoss * G4UniformRand();
296  x = (loss - meanLoss) / siga;
297  // Loop checking, 07-Aug-2015, Vladimir Ivanchenko
298  } while (1.0 - 0.5 * x * x < G4UniformRand());
299  } else {
300  do {
301  loss = G4RandGauss::shoot(meanLoss, siga);
302  // Loop checking, 07-Aug-2015, Vladimir Ivanchenko
303  } while (0.0 > loss || loss > twomeanLoss);
304  }
305  return loss;
306 }
307 
308 G4double
309 G4mplIonisationWithDeltaModel::Dispersion(const G4Material* material,
310  const G4DynamicParticle* dp,
311  G4double tcut,
312  G4double tmax,
313  G4double length)
314 {
315  G4double siga = 0.0;
316  G4double tau = dp->GetKineticEnergy() / mass;
317  if (tau > 0.0) {
318  G4double electronDensity = material->GetElectronDensity();
319  const G4double beta = dp->GetBeta();
320  siga = (tmax / (beta * beta) - 0.5 * tcut) * twopi_mc2_rcl2 * length
321  * electronDensity * chargeSquare;
322  }
323  return siga;
324 }
325 
326 G4double
328  G4double kinEnergy)
329 {
330  G4double tau = kinEnergy / mass;
331  return 2.0 * electron_mass_c2 * tau * (tau + 2.);
332 }
G4double pi_hbarc2_over_mc2
Convenient constants combination with mass.
G4double betalow
Beta threshold for low asymptotic.
virtual G4double MinEnergyCut(const G4ParticleDefinition *, const G4MaterialCutsCouple *couple) override
Threshold for zero value.
G4double chargeSquare
Square of magnetic charge in units of Dirac charge.
virtual G4double ComputeCrossSectionPerAtom(const G4ParticleDefinition *p, G4double kineticEnergy, G4double Z, G4double A, G4double cutEnergy, G4double maxEnergy) override
Compute cross section per atom for delta electrons emission.
G4ParticleChangeForLoss * fParticleChange
Pointer to ionising particle.
G4ParticleDefinition * theElectron
Electron definition.
const G4ParticleDefinition * monopole
Monopole definition.
G4double dedxlim
dedx limit in asymptotic formula, not used
virtual G4double ComputeDEDXPerVolume(const G4Material *material, const G4ParticleDefinition *p, G4double kineticEnergy, G4double maxEnergy) override
G4VEmModel::ComputeDEDXPerVolume implementation.
virtual G4double MaxSecondaryEnergy(const G4ParticleDefinition *p, G4double kinEnergy) override
Calculate maximum energy available for secondary particle emission.
G4double magCharge
Monopole magnetic charge in e+ units.
G4double ComputeDEDXAhlen(const G4Material *material, G4double bg2, G4double cut)
Calculate dedx based on extrapolated Ahlen formula.
virtual void Initialise(const G4ParticleDefinition *p, const G4DataVector &) override
G4VEmModel::Initialise implementation.
virtual void SampleSecondaries(std::vector< G4DynamicParticle * > *vdp, const G4MaterialCutsCouple *materialCutsCouple, const G4DynamicParticle *dp, G4double tmin, G4double maxEnergy) override
Create the sample of secondary delta electrons.
void SetParticle(const G4ParticleDefinition *p)
Read definition of the monopole.
virtual G4double SampleFluctuations(const G4MaterialCutsCouple *couple, const G4DynamicParticle *dp, G4double tcut, G4double tmax, G4double length, G4double meanLoss) override
Create fluctuations in the energies lost to a secondary delta electron.
virtual G4double ComputeCrossSectionPerElectron(const G4ParticleDefinition *p, G4double kineticEnergy, G4double cutEnergy, G4double maxEnergy)
Compute cross section per electron for delta electrons emission.
virtual G4double Dispersion(const G4Material *material, const G4DynamicParticle *, G4double tcut, G4double tmax, G4double length) override
Calculate dispersion.
static std::vector< G4double > * dedx0
Base dedx for each couple in current material.
G4double betalim
Beta threshold for high energy (only Ahlen formula)
double sqrt(double a)
sqrt for double
Definition: beamHelpers.h:28
Abstract base class for different kinds of events.