Geant4 11.1.1
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
G4MuonToMuonPairProductionModel.cc
Go to the documentation of this file.
1//
2// ********************************************************************
3// * License and Disclaimer *
4// * *
5// * The Geant4 software is copyright of the Copyright Holders of *
6// * the Geant4 Collaboration. It is provided under the terms and *
7// * conditions of the Geant4 Software License, included in the file *
8// * LICENSE and available at http://cern.ch/geant4/license . These *
9// * include a list of copyright holders. *
10// * *
11// * Neither the authors of this software system, nor their employing *
12// * institutes,nor the agencies providing financial support for this *
13// * work make any representation or warranty, express or implied, *
14// * regarding this software system or assume any liability for its *
15// * use. Please see the license in the file LICENSE and URL above *
16// * for the full disclaimer and the limitation of liability. *
17// * *
18// * This code implementation is the result of the scientific and *
19// * technical work of the GEANT4 collaboration. *
20// * By using, copying, modifying or distributing the software (or *
21// * any work based on the software) you agree to acknowledge its *
22// * use in resulting scientific publications, and indicate your *
23// * acceptance of all terms of the Geant4 Software license. *
24// ********************************************************************
25//
26//
27// -------------------------------------------------------------------
28//
29// GEANT4 Class file
30//
31//
32// File name: G4MuonToMuonPairProductionModel
33//
34// Author: Siddharth Yajaman on the base of Vladimir Ivantchenko code
35//
36// Creation date: 12.07.2022
37//
38//
39// -------------------------------------------------------------------
40//
41//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
42//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
43
46#include "G4SystemOfUnits.hh"
47#include "G4EmParameters.hh"
48#include "G4MuonMinus.hh"
49#include "G4MuonPlus.hh"
50#include "Randomize.hh"
51#include "G4Material.hh"
52#include "G4Element.hh"
54#include "G4Log.hh"
55#include "G4Exp.hh"
56#include <iostream>
57#include <fstream>
58
59//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
60
61// static members
62//
63static const G4int nzdat = 5;
64static const G4int zdat[5] = {1, 4, 13, 29, 92};
65
66static const G4double xgi[] =
67{ 0.0198550717512320, 0.1016667612931865, 0.2372337950418355, 0.4082826787521750,
68 0.5917173212478250, 0.7627662049581645, 0.8983332387068135, 0.9801449282487680 };
69
70static const G4double wgi[] =
71{ 0.0506142681451880, 0.1111905172266870, 0.1568533229389435, 0.1813418916891810,
72 0.1813418916891810, 0.1568533229389435, 0.1111905172266870, 0.0506142681451880 };
73
74//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
75
76using namespace std;
77
79 const G4ParticleDefinition* p,
80 const G4String& nam)
82{
87 mueRatio = muonMass/CLHEP::electron_mass_c2;
88 factorForCross = 2./(3*CLHEP::pi)*
89 pow(CLHEP::fine_structure_const*CLHEP::classic_electr_radius/mueRatio, 2);
90}
91
92//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
93
95 G4double tkin,
96 G4double Z,
97 G4double pairEnergy)
98// Calculates the differential (D) microscopic cross section
99// using the cross section formula of Kelner, Kokoulin and Petrukhin (1999)
100// Code written by Siddharth Yajaman (12/07/2022)
101{
102 if (pairEnergy <= minPairEnergy)
103 return 0.0;
104
105 G4double totalEnergy = tkin + particleMass;
106 G4double residEnergy = totalEnergy - pairEnergy;
107
108 if (residEnergy <= muonMass) { return 0.0; }
109
110 G4double a0 = 1.0 / (totalEnergy * residEnergy);
111 G4double rhomax = 1.0 - 2*muonMass/pairEnergy;
112 G4double tmnexp = 1. - rhomax;
113
114 if(tmnexp >= 1.0) { return 0.0; }
115
116 G4double tmn = G4Log(tmnexp);
117
118 G4double z2 = Z*Z;
119 G4double beta = 0.5*pairEnergy*pairEnergy*a0;
120 G4double xi0 = 0.5*beta;
121
122 // Gaussian integration in ln(1-ro) ( with 8 points)
123 G4double rho[8];
124 G4double rho2[8];
125 G4double xi[8];
126 G4double xi1[8];
127 G4double xii[8];
128
129 for (G4int i = 0; i < 8; ++i)
130 {
131 rho[i] = G4Exp(tmn*xgi[i]) - 1.0; // rho = -asymmetry
132 rho2[i] = rho[i] * rho[i];
133 xi[i] = xi0*(1.0-rho2[i]);
134 xi1[i] = 1.0 + xi[i];
135 xii[i] = 1.0 / xi[i];
136 }
137
138 G4double ximax = xi0*(1. - rhomax*rhomax);
139
140 G4double Y = 10 * sqrt(particleMass/totalEnergy);
141 G4double U[8];
142
143 for (G4int i = 0; i < 8; ++i)
144 {
145 U[i] = U_func(Z, rho2[i], xi[i], Y, pairEnergy);
146 }
147
148 G4double UMax = U_func(Z, rhomax*rhomax, ximax, Y, pairEnergy);
149
150 G4double sum = 0.0;
151 for (G4int i = 0; i < 8; ++i)
152 {
153 G4double X = 1 + U[i] - UMax;
154 G4double lnX = G4Log(X);
155 G4double phi = ((2 + rho2[i])*(1 + beta) + xi[i]*(3 + rho2[i]))*
156 G4Log(1 + xii[i]) - 1 - 3*rho2[i] + beta*(1 - 2*rho2[i])
157 + ((1 + rho2[i])*(1 + 1.5*beta) - xii[i]*(1 + 2*beta)
158 *(1 - rho2[i]))*G4Log(xi1[i]);
159 sum += wgi[i]*(1.0 + rho[i])*phi*lnX;
160 }
161
162 return -tmn*sum*factorForCross*z2*residEnergy/(totalEnergy*pairEnergy);
163
164}
165
167 G4double xi, G4double Y,
168 G4double pairEnergy,
169 const G4double B)
170{
171 G4int Z = G4lrint(ZZ);
172 G4double A27 = nist->GetA27(Z);
173 G4double Z13 = nist->GetZ13(Z);
174 static const G4double sqe = std::sqrt(G4Exp(1.0));
175 G4double res = (0.65 * B / (A27*Z13) * mueRatio)/
176 (1 + (2*sqe*muonMass*muonMass*(B/Z13)*(1 + xi)*(1 + Y))
177 /(CLHEP::electron_mass_c2*pairEnergy*(1 - rho2)));
178 return res;
179}
180
181//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
182
184 std::vector<G4DynamicParticle*>* vdp,
185 const G4MaterialCutsCouple* couple,
186 const G4DynamicParticle* aDynamicParticle,
187 G4double tmin,
188 G4double tmax)
189{
190 G4double kinEnergy = aDynamicParticle->GetKineticEnergy();
191 //G4cout << "--- G4MuonToMuonPairProductionModel::SampleSecondaries E(MeV)= "
192 // << kinEnergy << " "
193 // << aDynamicParticle->GetDefinition()->GetParticleName() << G4endl;
194 G4double totalMomentum = std::sqrt(kinEnergy*(kinEnergy + 2.0*muonMass));
195
196 G4ThreeVector partDirection = aDynamicParticle->GetMomentumDirection();
197
198 // select randomly one element constituing the material
199 const G4Element* anElement = SelectRandomAtom(couple,particle,kinEnergy);
200
201 // define interval of energy transfer
202 G4double maxPairEnergy = MaxSecondaryEnergyForElement(kinEnergy,
203 anElement->GetZ());
204 G4double maxEnergy = std::min(tmax, maxPairEnergy);
205 G4double minEnergy = std::max(tmin, minPairEnergy);
206
207 if(minEnergy >= maxEnergy) { return; }
208 //G4cout << "emin= " << minEnergy << " emax= " << maxEnergy
209 // << " minPair= " << minPairEnergy << " maxpair= " << maxPairEnergy
210 // << " ymin= " << ymin << " dy= " << dy << G4endl;
211
212 G4double coeff = G4Log(minPairEnergy/kinEnergy)/ymin;
213
214 // compute limits
215 G4double yymin = G4Log(minEnergy/kinEnergy)/coeff;
216 G4double yymax = G4Log(maxEnergy/kinEnergy)/coeff;
217
218 //G4cout << "yymin= " << yymin << " yymax= " << yymax << G4endl;
219
220 // units should not be used, bacause table was built without
221 G4double logTkin = G4Log(kinEnergy/CLHEP::MeV);
222
223 // sample mu-mu+ pair energy first
224
225 // select sample table via Z
226 G4int iz1(0), iz2(0);
227 for(G4int iz=0; iz<nzdat; ++iz) {
228 if(currentZ == zdat[iz]) {
229 iz1 = iz2 = currentZ;
230 break;
231 } else if(currentZ < zdat[iz]) {
232 iz2 = zdat[iz];
233 if(iz > 0) { iz1 = zdat[iz-1]; }
234 else { iz1 = iz2; }
235 break;
236 }
237 }
238 if(0 == iz1) { iz1 = iz2 = zdat[nzdat-1]; }
239
240 G4double pairEnergy = 0.0;
241 G4int count = 0;
242 //G4cout << "start loop Z1= " << iz1 << " Z2= " << iz2 << G4endl;
243 do {
244 ++count;
245 // sampling using only one random number
246 G4double rand = G4UniformRand();
247
248 G4double x = FindScaledEnergy(iz1, rand, logTkin, yymin, yymax);
249 if(iz1 != iz2) {
250 G4double x2 = FindScaledEnergy(iz2, rand, logTkin, yymin, yymax);
251 G4double lz1= nist->GetLOGZ(iz1);
252 G4double lz2= nist->GetLOGZ(iz2);
253 //G4cout << count << ". x= " << x << " x2= " << x2
254 // << " Z1= " << iz1 << " Z2= " << iz2 << G4endl;
255 x += (x2 - x)*(lnZ - lz1)/(lz2 - lz1);
256 }
257 //G4cout << "x= " << x << " coeff= " << coeff << G4endl;
258 pairEnergy = kinEnergy*G4Exp(x*coeff);
259
260 // Loop checking, 03-Aug-2015, Vladimir Ivanchenko
261 } while((pairEnergy < minEnergy || pairEnergy > maxEnergy) && 10 > count);
262
263 //G4cout << "## pairEnergy(GeV)= " << pairEnergy/GeV
264 // << " Etot(GeV)= " << totalEnergy/GeV << G4endl;
265
266 // sample r=(mu+mu-)/pairEnergy ( uniformly .....)
267 G4double rmax = 1 - 2*muonMass/(pairEnergy);
268 G4double r = rmax * (-1.+2.*G4UniformRand()) ;
269
270 // compute energies from pairEnergy,r
271 G4double muMinusEnergy = (1.-r)*pairEnergy*0.5;
272 G4double muPlusEnergy = pairEnergy - muMinusEnergy;
273
274 // Sample angles
275 G4ThreeVector muMinusDirection, muPlusDirection;
276 //
277 GetAngularDistribution()->SamplePairDirections(aDynamicParticle,
278 muMinusEnergy, muPlusEnergy,
279 muMinusDirection, muPlusDirection);
280 // create G4DynamicParticle object for mu+mu-
281 muMinusEnergy = std::max(muMinusEnergy - muonMass, 0.0);
282 muPlusEnergy = std::max(muPlusEnergy - muonMass, 0.0);
283 G4DynamicParticle* aParticle1 =
284 new G4DynamicParticle(theMuonMinus,muMinusDirection,muMinusEnergy);
285 G4DynamicParticle* aParticle2 =
286 new G4DynamicParticle(theMuonPlus,muPlusDirection,muPlusEnergy);
287 // Fill output vector
288 vdp->push_back(aParticle1);
289 vdp->push_back(aParticle2);
290
291 // primary change
292 kinEnergy -= pairEnergy;
293 partDirection *= totalMomentum;
294 partDirection -= (aParticle1->GetMomentum() + aParticle2->GetMomentum());
295 partDirection = partDirection.unit();
296
297 // if energy transfer is higher than threshold (very high by default)
298 // then stop tracking the primary particle and create a new secondary
299 if (pairEnergy > SecondaryThreshold()) {
302 G4DynamicParticle* newdp =
303 new G4DynamicParticle(particle, partDirection, kinEnergy);
304 vdp->push_back(newdp);
305 } else { // continue tracking the primary e-/e+ otherwise
308 }
309 //G4cout << "--- G4MuonToMuonPairProductionModel::SampleSecondaries done" << G4endl;
310}
311
312//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
313
315{
317 ed << "G4ElementData is not properly initialized Z= " << Z
318 << " Ekin(MeV)= " << G4Exp(logTkin)
319 << " IsMasterThread= " << IsMaster()
320 << " Model " << GetName();
321 G4Exception("G4MuonToMuonPairProductionModel","em0033",FatalException,ed,"");
322}
323
324//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4double B(G4double temperature)
G4double Y(G4double density)
@ FatalException
void G4Exception(const char *originOfException, const char *exceptionCode, G4ExceptionSeverity severity, const char *description)
Definition: G4Exception.cc:59
std::ostringstream G4ExceptionDescription
Definition: G4Exception.hh:40
G4double G4Exp(G4double initial_x)
Exponential Function double precision.
Definition: G4Exp.hh:180
const G4double a0
G4double G4Log(G4double x)
Definition: G4Log.hh:227
@ fStopAndKill
double G4double
Definition: G4Types.hh:83
int G4int
Definition: G4Types.hh:85
const G4int Z[17]
#define G4UniformRand()
Definition: Randomize.hh:52
Hep3Vector unit() const
const G4ThreeVector & GetMomentumDirection() const
G4double GetKineticEnergy() const
G4ThreeVector GetMomentum() const
G4double GetZ() const
Definition: G4Element.hh:131
G4double FindScaledEnergy(G4int Z, G4double rand, G4double logTkin, G4double yymin, G4double yymax)
const G4ParticleDefinition * particle
G4ParticleChangeForLoss * fParticleChange
G4double MaxSecondaryEnergyForElement(G4double kineticEnergy, G4double Z)
static G4MuonMinus * MuonMinus()
Definition: G4MuonMinus.cc:99
static G4MuonPlus * MuonPlus()
Definition: G4MuonPlus.cc:98
G4double ComputeDMicroscopicCrossSection(G4double tkin, G4double Z, G4double pairEnergy) override
void SampleSecondaries(std::vector< G4DynamicParticle * > *, const G4MaterialCutsCouple *, const G4DynamicParticle *, G4double tmin, G4double maxEnergy) override
G4MuonToMuonPairProductionModel(const G4ParticleDefinition *p=nullptr, const G4String &nam="muToMuonPairProd")
G4double U_func(G4double Z, G4double rho2, G4double xi, G4double Y, G4double pairEnergy, const G4double B=183)
void DataCorrupted(G4int Z, G4double logTkin) const override
G4double GetA27(G4int Z) const
G4double GetZ13(G4double Z) const
G4double GetLOGZ(G4int Z) const
void SetProposedKineticEnergy(G4double proposedKinEnergy)
void SetProposedMomentumDirection(const G4ThreeVector &dir)
virtual void SamplePairDirections(const G4DynamicParticle *dp, G4double elecKinEnergy, G4double posiKinEnergy, G4ThreeVector &dirElectron, G4ThreeVector &dirPositron, G4int Z=0, const G4Material *mat=nullptr)
G4VEmAngularDistribution * GetAngularDistribution()
Definition: G4VEmModel.hh:600
G4bool IsMaster() const
Definition: G4VEmModel.hh:725
const G4Element * SelectRandomAtom(const G4MaterialCutsCouple *, const G4ParticleDefinition *, G4double kineticEnergy, G4double cutEnergy=0.0, G4double maxEnergy=DBL_MAX)
Definition: G4VEmModel.hh:561
const G4String & GetName() const
Definition: G4VEmModel.hh:816
G4double SecondaryThreshold() const
Definition: G4VEmModel.hh:669
void ProposeTrackStatus(G4TrackStatus status)
int G4lrint(double ad)
Definition: templates.hh:134