Belle II Software development
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
34using namespace std;
35using namespace Belle2;
36using namespace Belle2::Monopoles;
37using namespace CLHEP;
38
39std::vector<G4double>* G4mplIonisationWithDeltaModel::dedx0 = nullptr;
40
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
71void 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
83void
84G4mplIonisationWithDeltaModel::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
111G4double
113 const G4MaterialCutsCouple* couple)
114{
115 return couple->GetMaterial()->GetIonisation()->GetMeanExcitationEnergy();
116}
117
118G4double
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
160G4double
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
195G4double
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
213G4double
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
226void
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
308G4double
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
326G4double
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.
G4mplIonisationWithDeltaModel(G4double mCharge, const G4String &nam="mplIonisationWithDelta")
Constructor.
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.
STL namespace.