Geant4 11.2.2
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
62 const G4ParticleDefinition* p,
63 const G4String& nam)
65{
70 mueRatio = muonMass/CLHEP::electron_mass_c2;
71 factorForCross = 2./(3*CLHEP::pi)*
72 std::pow(CLHEP::fine_structure_const*CLHEP::classic_electr_radius/mueRatio, 2);
73}
74
75//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
76
78 G4double tkin,
79 G4double Z,
80 G4double pairEnergy)
81// Calculates the differential (D) microscopic cross section
82// using the cross section formula of Kelner, Kokoulin and Petrukhin (1999)
83// Code written by Siddharth Yajaman (12/07/2022)
84{
85 if (pairEnergy <= minPairEnergy)
86 return 0.0;
87
88 G4double totalEnergy = tkin + particleMass;
89 G4double residEnergy = totalEnergy - pairEnergy;
90
91 if (residEnergy <= muonMass) { return 0.0; }
92
93 G4double a0 = 1.0 / (totalEnergy * residEnergy);
94 G4double rhomax = 1.0 - 2*muonMass/pairEnergy;
95 G4double tmnexp = 1. - rhomax;
96
97 if(tmnexp >= 1.0) { return 0.0; }
98
99 G4double tmn = G4Log(tmnexp);
100
101 G4double z2 = Z*Z;
102 G4double beta = 0.5*pairEnergy*pairEnergy*a0;
103 G4double xi0 = 0.5*beta;
104
105 // Gaussian integration in ln(1-ro) ( with NINTPAIR points)
106 G4double rho[NINTPAIR];
107 G4double rho2[NINTPAIR];
108 G4double xi[NINTPAIR];
109 G4double xi1[NINTPAIR];
110 G4double xii[NINTPAIR];
111
112 for (G4int i = 0; i < NINTPAIR; ++i)
113 {
114 rho[i] = G4Exp(tmn*xgi[i]) - 1.0; // rho = -asymmetry
115 rho2[i] = rho[i] * rho[i];
116 xi[i] = xi0*(1.0-rho2[i]);
117 xi1[i] = 1.0 + xi[i];
118 xii[i] = 1.0 / xi[i];
119 }
120
121 G4double ximax = xi0*(1. - rhomax*rhomax);
122
123 G4double Y = 10 * std::sqrt(particleMass/totalEnergy);
124 G4double U[8];
125
126 for (G4int i = 0; i < NINTPAIR; ++i)
127 {
128 U[i] = U_func(Z, rho2[i], xi[i], Y, pairEnergy);
129 }
130
131 G4double UMax = U_func(Z, rhomax*rhomax, ximax, Y, pairEnergy);
132
133 G4double sum = 0.0;
134 for (G4int i = 0; i < NINTPAIR; ++i)
135 {
136 G4double X = 1 + U[i] - UMax;
137 G4double lnX = G4Log(X);
138 G4double phi = ((2 + rho2[i])*(1 + beta) + xi[i]*(3 + rho2[i]))*
139 G4Log(1 + xii[i]) - 1 - 3*rho2[i] + beta*(1 - 2*rho2[i])
140 + ((1 + rho2[i])*(1 + 1.5*beta) - xii[i]*(1 + 2*beta)
141 *(1 - rho2[i]))*G4Log(xi1[i]);
142 sum += wgi[i]*(1.0 + rho[i])*phi*lnX;
143 }
144
145 return -tmn*sum*factorForCross*z2*residEnergy/(totalEnergy*pairEnergy);
146
147}
148
150 G4double xi, G4double Y,
151 G4double pairEnergy,
152 const G4double B)
153{
154 G4int Z = G4lrint(ZZ);
155 G4double A27 = nist->GetA27(Z);
156 G4double Z13 = nist->GetZ13(Z);
157 static const G4double sqe = std::sqrt(G4Exp(1.0));
158 G4double res = (0.65 * B / (A27*Z13) * mueRatio)/
159 (1 + (2*sqe*muonMass*muonMass*(B/Z13)*(1 + xi)*(1 + Y))
160 /(CLHEP::electron_mass_c2*pairEnergy*(1 - rho2)));
161 return res;
162}
163
164//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
165
167 std::vector<G4DynamicParticle*>* vdp,
168 const G4MaterialCutsCouple* couple,
169 const G4DynamicParticle* aDynamicParticle,
170 G4double tmin,
171 G4double tmax)
172{
173 G4double kinEnergy = aDynamicParticle->GetKineticEnergy();
174 //G4cout << "--- G4MuonToMuonPairProductionModel::SampleSecondaries E(MeV)= "
175 // << kinEnergy << " "
176 // << aDynamicParticle->GetDefinition()->GetParticleName() << G4endl;
177 G4double totalMomentum = std::sqrt(kinEnergy*(kinEnergy + 2.0*muonMass));
178
179 G4ThreeVector partDirection = aDynamicParticle->GetMomentumDirection();
180
181 // select randomly one element constituing the material
182 const G4Element* anElement = SelectRandomAtom(couple,particle,kinEnergy);
183
184 // define interval of energy transfer
185 G4double maxPairEnergy = MaxSecondaryEnergyForElement(kinEnergy,
186 anElement->GetZ());
187 G4double maxEnergy = std::min(tmax, maxPairEnergy);
188 G4double minEnergy = std::max(tmin, minPairEnergy);
189
190 if(minEnergy >= maxEnergy) { return; }
191 //G4cout << "emin= " << minEnergy << " emax= " << maxEnergy
192 // << " minPair= " << minPairEnergy << " maxpair= " << maxPairEnergy
193 // << " ymin= " << ymin << " dy= " << dy << G4endl;
194
195 G4double coeff = G4Log(minPairEnergy/kinEnergy)/ymin;
196
197 // compute limits
198 G4double yymin = G4Log(minEnergy/kinEnergy)/coeff;
199 G4double yymax = G4Log(maxEnergy/kinEnergy)/coeff;
200
201 //G4cout << "yymin= " << yymin << " yymax= " << yymax << G4endl;
202
203 // units should not be used, bacause table was built without
204 G4double logTkin = G4Log(kinEnergy/CLHEP::MeV);
205
206 // sample mu-mu+ pair energy first
207
208 // select sample table via Z
209 G4int iz1(0), iz2(0);
210 for(G4int iz=0; iz<NZDATPAIR; ++iz) {
211 if(currentZ == ZDATPAIR[iz]) {
212 iz1 = iz2 = iz;
213 break;
214 } else if(currentZ < ZDATPAIR[iz]) {
215 iz2 = iz;
216 if(iz > 0) { iz1 = iz-1; }
217 else { iz1 = iz2; }
218 break;
219 }
220 }
221 if(0 == iz1) { iz1 = iz2 = NZDATPAIR-1; }
222
223 G4double pairEnergy = 0.0;
224 G4int count = 0;
225 //G4cout << "start loop Z1= " << iz1 << " Z2= " << iz2 << G4endl;
226 do {
227 ++count;
228 // sampling using only one random number
229 G4double rand = G4UniformRand();
230
231 G4double x = FindScaledEnergy(iz1, rand, logTkin, yymin, yymax);
232 if(iz1 != iz2) {
233 G4double x2 = FindScaledEnergy(iz2, rand, logTkin, yymin, yymax);
234 G4double lz1= nist->GetLOGZ(ZDATPAIR[iz1]);
235 G4double lz2= nist->GetLOGZ(ZDATPAIR[iz2]);
236 //G4cout << count << ". x= " << x << " x2= " << x2
237 // << " Z1= " << iz1 << " Z2= " << iz2 << G4endl;
238 x += (x2 - x)*(lnZ - lz1)/(lz2 - lz1);
239 }
240 //G4cout << "x= " << x << " coeff= " << coeff << G4endl;
241 pairEnergy = kinEnergy*G4Exp(x*coeff);
242
243 // Loop checking, 03-Aug-2015, Vladimir Ivanchenko
244 } while((pairEnergy < minEnergy || pairEnergy > maxEnergy) && 10 > count);
245
246 //G4cout << "## pairEnergy(GeV)= " << pairEnergy/GeV
247 // << " Etot(GeV)= " << totalEnergy/GeV << G4endl;
248
249 // sample r=(mu+mu-)/pairEnergy ( uniformly .....)
250 G4double rmax = 1 - 2*muonMass/(pairEnergy);
251 G4double r = rmax * (-1.+2.*G4UniformRand()) ;
252
253 // compute energies from pairEnergy,r
254 G4double muMinusEnergy = (1.-r)*pairEnergy*0.5;
255 G4double muPlusEnergy = pairEnergy - muMinusEnergy;
256
257 // Sample angles
258 G4ThreeVector muMinusDirection, muPlusDirection;
259 //
260 GetAngularDistribution()->SamplePairDirections(aDynamicParticle,
261 muMinusEnergy, muPlusEnergy,
262 muMinusDirection, muPlusDirection);
263 // create G4DynamicParticle object for mu+mu-
264 muMinusEnergy = std::max(muMinusEnergy - muonMass, 0.0);
265 muPlusEnergy = std::max(muPlusEnergy - muonMass, 0.0);
266 G4DynamicParticle* aParticle1 =
267 new G4DynamicParticle(theMuonMinus,muMinusDirection,muMinusEnergy);
268 G4DynamicParticle* aParticle2 =
269 new G4DynamicParticle(theMuonPlus,muPlusDirection,muPlusEnergy);
270 // Fill output vector
271 vdp->push_back(aParticle1);
272 vdp->push_back(aParticle2);
273
274 // primary change
275 kinEnergy -= pairEnergy;
276 partDirection *= totalMomentum;
277 partDirection -= (aParticle1->GetMomentum() + aParticle2->GetMomentum());
278 partDirection = partDirection.unit();
279
280 // if energy transfer is higher than threshold (very high by default)
281 // then stop tracking the primary particle and create a new secondary
282 if (pairEnergy > SecondaryThreshold()) {
285 G4DynamicParticle* newdp =
286 new G4DynamicParticle(particle, partDirection, kinEnergy);
287 vdp->push_back(newdp);
288 } else { // continue tracking the primary e-/e+ otherwise
291 }
292 //G4cout << "--- G4MuonToMuonPairProductionModel::SampleSecondaries done" << G4endl;
293}
294
295//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
296
298{
300 ed << "G4ElementData is not properly initialized Z= " << Z
301 << " Ekin(MeV)= " << G4Exp(logTkin)
302 << " IsMasterThread= " << IsMaster()
303 << " Model " << GetName();
304 G4Exception("G4MuonToMuonPairProductionModel","em0033",FatalException,ed,"");
305}
306
307//....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)
std::ostringstream G4ExceptionDescription
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
#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:119
G4double FindScaledEnergy(G4int Z, G4double rand, G4double logTkin, G4double yymin, G4double yymax)
const G4ParticleDefinition * particle
G4ParticleChangeForLoss * fParticleChange
static const G4int ZDATPAIR[NZDATPAIR]
G4double MaxSecondaryEnergyForElement(G4double kineticEnergy, G4double Z)
static const G4double xgi[NINTPAIR]
static const G4double wgi[NINTPAIR]
static G4MuonMinus * MuonMinus()
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()
G4bool IsMaster() const
const G4Element * SelectRandomAtom(const G4MaterialCutsCouple *, const G4ParticleDefinition *, G4double kineticEnergy, G4double cutEnergy=0.0, G4double maxEnergy=DBL_MAX)
const G4String & GetName() const
G4double SecondaryThreshold() const
void ProposeTrackStatus(G4TrackStatus status)
int G4lrint(double ad)
Definition templates.hh:134