Geant4 11.1.1
Toolkit for the simulation of the passage of particles through matter
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
G4BetheHeitlerModel.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: G4BetheHeitlerModel
33//
34// Author: Vladimir Ivanchenko on base of Michel Maire code
35//
36// Creation date: 15.03.2005
37//
38// Modifications by Vladimir Ivanchenko, Michel Maire, Mihaly Novak
39//
40// Class Description:
41//
42// -------------------------------------------------------------------
43//
44
47#include "G4SystemOfUnits.hh"
48#include "G4Electron.hh"
49#include "G4Positron.hh"
50#include "G4Gamma.hh"
51#include "Randomize.hh"
53#include "G4Pow.hh"
54#include "G4Exp.hh"
55#include "G4ModifiedTsai.hh"
56
58std::vector<G4BetheHeitlerModel::ElementData*> G4BetheHeitlerModel::gElementData;
59
61 const G4String& nam)
62: G4VEmModel(nam),
63 fG4Calc(G4Pow::GetInstance()), fTheGamma(G4Gamma::Gamma()),
64 fTheElectron(G4Electron::Electron()), fThePositron(G4Positron::Positron()),
65 fParticleChange(nullptr)
66{
68}
69
71{
72 if (IsMaster()) {
73 // clear ElementData container
74 for (std::size_t iz = 0; iz < gElementData.size(); ++iz) {
75 if (gElementData[iz]) delete gElementData[iz];
76 }
77 gElementData.clear();
78 }
79}
80
82 const G4DataVector& cuts)
83{
84 if (IsMaster()) {
86 }
88 if (IsMaster()) {
90 }
91}
92
94 G4VEmModel* masterModel)
95{
97}
98
99// Calculates the microscopic cross section in GEANT4 internal units.
100// A parametrized formula from L. Urban is used to estimate
101// the total cross section.
102// It gives a good description of the data from 1.5 MeV to 100 GeV.
103// below 1.5 MeV: sigma=sigma(1.5MeV)*(GammaEnergy-2electronmass)
104// *(GammaEnergy-2electronmass)
107 G4double gammaEnergy, G4double Z,
109{
110 G4double xSection = 0.0 ;
111 // short versions
112 static const G4double kMC2 = CLHEP::electron_mass_c2;
113 // zero cross section below the kinematical limit: Eg<2mc^2
114 if (Z < 0.9 || gammaEnergy <= 2.0*kMC2) { return xSection; }
115 //
116 static const G4double gammaEnergyLimit = 1.5*CLHEP::MeV;
117 // set coefficients a, b c
118 static const G4double a0 = 8.7842e+2*CLHEP::microbarn;
119 static const G4double a1 = -1.9625e+3*CLHEP::microbarn;
120 static const G4double a2 = 1.2949e+3*CLHEP::microbarn;
121 static const G4double a3 = -2.0028e+2*CLHEP::microbarn;
122 static const G4double a4 = 1.2575e+1*CLHEP::microbarn;
123 static const G4double a5 = -2.8333e-1*CLHEP::microbarn;
124
125 static const G4double b0 = -1.0342e+1*CLHEP::microbarn;
126 static const G4double b1 = 1.7692e+1*CLHEP::microbarn;
127 static const G4double b2 = -8.2381 *CLHEP::microbarn;
128 static const G4double b3 = 1.3063 *CLHEP::microbarn;
129 static const G4double b4 = -9.0815e-2*CLHEP::microbarn;
130 static const G4double b5 = 2.3586e-3*CLHEP::microbarn;
131
132 static const G4double c0 = -4.5263e+2*CLHEP::microbarn;
133 static const G4double c1 = 1.1161e+3*CLHEP::microbarn;
134 static const G4double c2 = -8.6749e+2*CLHEP::microbarn;
135 static const G4double c3 = 2.1773e+2*CLHEP::microbarn;
136 static const G4double c4 = -2.0467e+1*CLHEP::microbarn;
137 static const G4double c5 = 6.5372e-1*CLHEP::microbarn;
138 // check low energy limit of the approximation (1.5 MeV)
139 G4double gammaEnergyOrg = gammaEnergy;
140 if (gammaEnergy < gammaEnergyLimit) { gammaEnergy = gammaEnergyLimit; }
141 // compute gamma energy variables
142 const G4double x = G4Log(gammaEnergy/kMC2);
143 const G4double x2 = x *x;
144 const G4double x3 = x2*x;
145 const G4double x4 = x3*x;
146 const G4double x5 = x4*x;
147 //
148 const G4double F1 = a0 + a1*x + a2*x2 + a3*x3 + a4*x4 + a5*x5;
149 const G4double F2 = b0 + b1*x + b2*x2 + b3*x3 + b4*x4 + b5*x5;
150 const G4double F3 = c0 + c1*x + c2*x2 + c3*x3 + c4*x4 + c5*x5;
151 // compute the approximated cross section
152 xSection = (Z + 1.)*(F1*Z + F2*Z*Z + F3);
153 // check if we are below the limit of the approximation and apply correction
154 if (gammaEnergyOrg < gammaEnergyLimit) {
155 const G4double dum = (gammaEnergyOrg-2.*kMC2)/(gammaEnergyLimit-2.*kMC2);
156 xSection *= dum*dum;
157 }
158 // make sure that the cross section is never negative
159 xSection = std::max(xSection, 0.);
160 return xSection;
161}
162
163// The secondaries e+e- energies are sampled using the Bethe - Heitler
164// cross sections with Coulomb correction.
165// A modified version of the random number techniques of Butcher & Messel
166// is used (Nuc Phys 20(1960),15).
167//
168// GEANT4 internal units.
169//
170// Note 1 : Effects due to the breakdown of the Born approximation at
171// low energy are ignored.
172// Note 2 : The differential cross section implicitly takes account of
173// pair creation in both nuclear and atomic electron fields.
174// However triplet prodution is not generated.
175void G4BetheHeitlerModel::SampleSecondaries(std::vector<G4DynamicParticle*>* fvect,
176 const G4MaterialCutsCouple* couple,
177 const G4DynamicParticle* aDynamicGamma,
179{
180 // set some constant values
181 const G4double gammaEnergy = aDynamicGamma->GetKineticEnergy();
182 const G4double eps0 = CLHEP::electron_mass_c2/gammaEnergy;
183 //
184 // check kinematical limit: gamma energy(Eg) must be at least 2 e- rest mass
185 if (eps0 > 0.5) { return; }
186 //
187 // select target element of the material (probs. are based on partial x-secs)
188 const G4Element* anElement = SelectTargetAtom(couple, fTheGamma, gammaEnergy,
189 aDynamicGamma->GetLogKineticEnergy());
190
191 //
192 // get the random engine
193 CLHEP::HepRandomEngine* rndmEngine = G4Random::getTheEngine();
194 //
195 // 'eps' is the total energy transferred to one of the e-/e+ pair in initial
196 // gamma energy units Eg. Since the corresponding DCS is symmetric on eps=0.5,
197 // the kinematical limits for eps0=mc^2/Eg <= eps <= 0.5
198 // 1. 'eps' is sampled uniformly on the [eps0, 0.5] inteval if Eg<Egsmall
199 // 2. otherwise, on the [eps_min, 0.5] interval according to the DCS (case 2.)
200 G4double eps;
201 // case 1.
202 static const G4double Egsmall = 2.*CLHEP::MeV;
203 if (gammaEnergy < Egsmall) {
204 eps = eps0 + (0.5-eps0)*rndmEngine->flat();
205 } else {
206 // case 2.
207 // get the Coulomb factor for the target element (Z) and gamma energy (Eg)
208 // F(Z) = 8*ln(Z)/3 if Eg <= 50 [MeV] => no Coulomb correction
209 // F(Z) = 8*ln(Z)/3 + 8*fc(Z) if Eg > 50 [MeV] => fc(Z) is the Coulomb cor.
210 //
211 // The screening variable 'delta(eps)' = 136*Z^{-1/3}*eps0/[eps(1-eps)]
212 // Due to the Coulomb correction, the DCS can go below zero even at
213 // kinematicaly allowed eps > eps0 values. In order to exclude this eps
214 // range with negative DCS, the minimum eps value will be set to eps_min =
215 // max[eps0, epsp] with epsp is the solution of SF(delta(epsp)) - F(Z)/2 = 0
216 // with SF being the screening function (SF1=SF2 at high value of delta).
217 // The solution is epsp = 0.5 - 0.5*sqrt[ 1 - 4*136*Z^{-1/3}eps0/deltap]
218 // with deltap = Exp[(42.038-F(Z))/8.29]-0.958. So the limits are:
219 // - when eps=eps_max = 0.5 => delta_min = 136*Z^{-1/3}*eps0/4
220 // - epsp = 0.5 - 0.5*sqrt[ 1 - delta_min/deltap]
221 // - and eps_min = max[eps0, epsp]
222 static const G4double midEnergy = 50.*CLHEP::MeV;
223 const G4int iZet = std::min(gMaxZet, anElement->GetZasInt());
224 const G4double deltaFactor = 136.*eps0/anElement->GetIonisation()->GetZ3();
225 G4double deltaMax = gElementData[iZet]->fDeltaMaxLow;
226 G4double FZ = 8.*anElement->GetIonisation()->GetlogZ3();
227 if (gammaEnergy > midEnergy) {
228 FZ += 8.*(anElement->GetfCoulomb());
229 deltaMax = gElementData[iZet]->fDeltaMaxHigh;
230 }
231 const G4double deltaMin = 4.*deltaFactor;
232 //
233 // compute the limits of eps
234 const G4double epsp = 0.5 - 0.5*std::sqrt(1. - deltaMin/deltaMax) ;
235 const G4double epsMin = std::max(eps0,epsp);
236 const G4double epsRange = 0.5 - epsMin;
237 //
238 // sample the energy rate (eps) of the created electron (or positron)
240 ScreenFunction12(deltaMin, F10, F20);
241 F10 -= FZ;
242 F20 -= FZ;
243 const G4double NormF1 = std::max(F10 * epsRange * epsRange, 0.);
244 const G4double NormF2 = std::max(1.5 * F20 , 0.);
245 const G4double NormCond = NormF1/(NormF1 + NormF2);
246 // we will need 3 uniform random number for each trial of sampling
247 G4double rndmv[3];
248 G4double greject = 0.;
249 do {
250 rndmEngine->flatArray(3, rndmv);
251 if (NormCond > rndmv[0]) {
252 eps = 0.5 - epsRange * fG4Calc->A13(rndmv[1]);
253 const G4double delta = deltaFactor/(eps*(1.-eps));
254 greject = (ScreenFunction1(delta)-FZ)/F10;
255 } else {
256 eps = epsMin + epsRange*rndmv[1];
257 const G4double delta = deltaFactor/(eps*(1.-eps));
258 greject = (ScreenFunction2(delta)-FZ)/F20;
259 }
260 // Loop checking, 03-Aug-2015, Vladimir Ivanchenko
261 } while (greject < rndmv[2]);
262 } // end of eps sampling
263 //
264 // select charges randomly
265 G4double eTotEnergy, pTotEnergy;
266 if (rndmEngine->flat() > 0.5) {
267 eTotEnergy = (1.-eps)*gammaEnergy;
268 pTotEnergy = eps*gammaEnergy;
269 } else {
270 pTotEnergy = (1.-eps)*gammaEnergy;
271 eTotEnergy = eps*gammaEnergy;
272 }
273 //
274 // sample pair kinematics
275 const G4double eKinEnergy = std::max(0.,eTotEnergy - CLHEP::electron_mass_c2);
276 const G4double pKinEnergy = std::max(0.,pTotEnergy - CLHEP::electron_mass_c2);
277 //
278 G4ThreeVector eDirection, pDirection;
279 //
281 eKinEnergy, pKinEnergy,
282 eDirection, pDirection);
283 // create G4DynamicParticle object for the particle1
284 auto aParticle1= new G4DynamicParticle(fTheElectron,eDirection,eKinEnergy);
285 // create G4DynamicParticle object for the particle2
286 auto aParticle2= new G4DynamicParticle(fThePositron,pDirection,pKinEnergy);
287 // Fill output vector
288 fvect->push_back(aParticle1);
289 fvect->push_back(aParticle2);
290 // kill incident photon
293}
294
295// should be called only by the master and at initialisation
297{
298 G4int size = (G4int)gElementData.size();
299 if (size < gMaxZet+1) {
300 gElementData.resize(gMaxZet+1, nullptr);
301 }
302 // create for all elements that are in the detector
303 const G4ElementTable* elemTable = G4Element::GetElementTable();
304 std::size_t numElems = (*elemTable).size();
305 for (std::size_t ie = 0; ie < numElems; ++ie) {
306 const G4Element* elem = (*elemTable)[ie];
307 const G4int iz = std::min(gMaxZet, elem->GetZasInt());
308 if (!gElementData[iz]) { // create it if doesn't exist yet
309 G4double FZLow = 8.*elem->GetIonisation()->GetlogZ3();
310 G4double FZHigh = FZLow + 8.*elem->GetfCoulomb();
311 auto elD = new ElementData();
312 elD->fDeltaMaxLow = G4Exp((42.038 - FZLow )/8.29) - 0.958;
313 elD->fDeltaMaxHigh = G4Exp((42.038 - FZHigh)/8.29) - 0.958;
314 gElementData[iz] = elD;
315 }
316 }
317}
318
std::vector< G4Element * > G4ElementTable
#define F10
#define F20
G4double G4Exp(G4double initial_x)
Exponential Function double precision.
Definition: G4Exp.hh:180
const G4double a0
G4double G4Log(G4double x)
Definition: G4Log.hh:227
#define elem(i, j)
@ fStopAndKill
double G4double
Definition: G4Types.hh:83
int G4int
Definition: G4Types.hh:85
const G4int Z[17]
virtual double flat()=0
virtual void flatArray(const int size, double *vect)=0
G4ParticleChangeForGamma * fParticleChange
void SampleSecondaries(std::vector< G4DynamicParticle * > *, const G4MaterialCutsCouple *, const G4DynamicParticle *, G4double tmin, G4double maxEnergy) override
G4BetheHeitlerModel(const G4ParticleDefinition *p=nullptr, const G4String &nam="BetheHeitler")
const G4ParticleDefinition * fTheElectron
void ScreenFunction12(const G4double delta, G4double &f1, G4double &f2)
G4double ScreenFunction1(const G4double delta)
static const G4int gMaxZet
static std::vector< ElementData * > gElementData
const G4ParticleDefinition * fTheGamma
G4double ComputeCrossSectionPerAtom(const G4ParticleDefinition *, G4double kinEnergy, G4double Z, G4double A=0., G4double cut=0., G4double emax=DBL_MAX) override
void Initialise(const G4ParticleDefinition *, const G4DataVector &) override
const G4ParticleDefinition * fThePositron
G4double ScreenFunction2(const G4double delta)
void InitialiseLocal(const G4ParticleDefinition *, G4VEmModel *masterModel) override
G4double GetLogKineticEnergy() const
G4double GetKineticEnergy() const
static G4ElementTable * GetElementTable()
Definition: G4Element.cc:403
G4double GetfCoulomb() const
Definition: G4Element.hh:190
G4IonisParamElm * GetIonisation() const
Definition: G4Element.hh:198
G4int GetZasInt() const
Definition: G4Element.hh:132
G4double GetlogZ3() const
G4double GetZ3() const
void SetProposedKineticEnergy(G4double proposedKinEnergy)
Definition: G4Pow.hh:49
G4double A13(G4double A) const
Definition: G4Pow.cc:116
virtual void SamplePairDirections(const G4DynamicParticle *dp, G4double elecKinEnergy, G4double posiKinEnergy, G4ThreeVector &dirElectron, G4ThreeVector &dirPositron, G4int Z=0, const G4Material *mat=nullptr)
void SetElementSelectors(std::vector< G4EmElementSelector * > *)
Definition: G4VEmModel.hh:831
G4VEmAngularDistribution * GetAngularDistribution()
Definition: G4VEmModel.hh:600
G4ParticleChangeForGamma * GetParticleChangeForGamma()
Definition: G4VEmModel.cc:124
std::vector< G4EmElementSelector * > * GetElementSelectors()
Definition: G4VEmModel.hh:823
G4bool IsMaster() const
Definition: G4VEmModel.hh:725
void SetAngularDistribution(G4VEmAngularDistribution *)
Definition: G4VEmModel.hh:607
const G4Element * SelectTargetAtom(const G4MaterialCutsCouple *, const G4ParticleDefinition *, G4double kineticEnergy, G4double logKineticEnergy, G4double cutEnergy=0.0, G4double maxEnergy=DBL_MAX)
Definition: G4VEmModel.hh:577
void InitialiseElementSelectors(const G4ParticleDefinition *, const G4DataVector &)
Definition: G4VEmModel.cc:139
void ProposeTrackStatus(G4TrackStatus status)