Geant4 10.7.0
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
G4eBremsstrahlungRelModel.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: G4eBremsstrahlungRelModel
33//
34// Author: Andreas Schaelicke
35//
36// Creation date: 12.08.2008
37//
38// Modifications:
39//
40// 13.11.08 add SetLPMflag and SetLPMconstant methods
41// 13.11.08 change default LPMconstant value
42// 13.10.10 add angular distributon interface (VI)
43// 31.05.16 change LPMconstant such that it gives suppression variable 's'
44// that consistent to Migdal's one; fix a small bug in 'logTS1'
45// computation; better agreement with exp.(M.Novak)
46// 15.07.18 improved LPM suppression function approximation (no artificial
47// steps), code cleanup and optimizations,more implementation and
48// model related comments, consistent variable naming (M.Novak)
49//
50// Main References:
51// Y.-S.Tsai, Rev. Mod. Phys. 46 (1974) 815; Rev. Mod. Phys. 49 (1977) 421.
52// S.Klein, Rev. Mod. Phys. 71 (1999) 1501.
53// T.Stanev et.al., Phys. Rev. D25 (1982) 1291.
54// M.L.Ter-Mikaelian, High-energy Electromagnetic Processes in Condensed Media,
55// Wiley, 1972.
56//
57// -------------------------------------------------------------------
58//
59
62#include "G4SystemOfUnits.hh"
63#include "G4Electron.hh"
64#include "G4Gamma.hh"
65#include "Randomize.hh"
66#include "G4Material.hh"
67#include "G4Element.hh"
68#include "G4ElementVector.hh"
70#include "G4ModifiedTsai.hh"
71//#include "G4DipBustGenerator.hh"
72
73const G4int G4eBremsstrahlungRelModel::gMaxZet = 120;
74
75// constant DCS factor: 16\alpha r_0^2/3
77 = 16. * CLHEP::fine_structure_const * CLHEP::classic_electr_radius
78 * CLHEP::classic_electr_radius/3.;
79
80// Migdal's constant: 4\pi r_0*electron_reduced_compton_wavelength^2
82 = 4. * CLHEP::pi * CLHEP::classic_electr_radius
83 * CLHEP::electron_Compton_length * CLHEP::electron_Compton_length;
84
85// LPM constant: \alpha(mc^2)^2/(4\pi*\hbar c)
86const G4double G4eBremsstrahlungRelModel::gLPMconstant
87 = CLHEP::fine_structure_const * CLHEP::electron_mass_c2
88 * CLHEP::electron_mass_c2 / (4. * CLHEP::pi * CLHEP::hbarc);
89
90// abscissas and weights of an 8 point Gauss-Legendre quadrature
91// for numerical integration on [0,1]
92const G4double G4eBremsstrahlungRelModel::gXGL[] = {
93 1.98550718e-02, 1.01666761e-01, 2.37233795e-01, 4.08282679e-01,
94 5.91717321e-01, 7.62766205e-01, 8.98333239e-01, 9.80144928e-01
95};
96const G4double G4eBremsstrahlungRelModel::gWGL[] = {
97 5.06142681e-02, 1.11190517e-01, 1.56853323e-01, 1.81341892e-01,
98 1.81341892e-01, 1.56853323e-01, 1.11190517e-01, 5.06142681e-02
99};
100
101// elastic and inelatic radiation logarithms for light elements (where the
102// Thomas-Fermi model doesn't work): computed by using Dirac-Fock model of atom.
103const G4double G4eBremsstrahlungRelModel::gFelLowZet [] = {
104 0.0, 5.3104, 4.7935, 4.7402, 4.7112, 4.6694, 4.6134, 4.5520
105};
106const G4double G4eBremsstrahlungRelModel::gFinelLowZet[] = {
107 0.0, 5.9173, 5.6125, 5.5377, 5.4728, 5.4174, 5.3688, 5.3236
108};
109
110// LPM supression functions evaluated at initialisation time
111G4eBremsstrahlungRelModel::LPMFuncs G4eBremsstrahlungRelModel::gLPMFuncs;
112
113// special data structure per element i.e. per Z
114std::vector<G4eBremsstrahlungRelModel::ElementData*> G4eBremsstrahlungRelModel::gElementData;
115
117 const G4String& nam)
118: G4VEmModel(nam), fIsElectron(true), fIsScatOffElectron(false),
119 fIsLPMActive(false), fPrimaryParticle(nullptr), fIsUseCompleteScreening(false)
120{
121 fCurrentIZ = 0;
122 //
126 fDensityFactor = 0.;
127 fDensityCorr = 0.;
128 fNucTerm = 0.;
129 fSumTerm = 0.;
130 //
131 fPrimaryParticle = nullptr;
133 fParticleChange = nullptr;
134 //
135 fLowestKinEnergy = 1.0*MeV;
137 //
138 fLPMEnergyThreshold = 1.e+39;
139 fLPMEnergy = 0.;
140
141 SetLPMFlag(true);
142 //
144 //SetAngularDistribution(new G4DipBustGenerator());
145 //
146 if (p) {
147 SetParticle(p);
148 }
149}
150
152{
153 if (IsMaster()) {
154 // clear ElementData container
155 for (size_t iz = 0; iz < gElementData.size(); ++iz) {
156 if (gElementData[iz]) {
157 delete gElementData[iz];
158 }
159 }
160 gElementData.clear();
161 // clear LPMFunctions (if any)
162 if (LPMFlag()) {
163 gLPMFuncs.fLPMFuncG.clear();
164 gLPMFuncs.fLPMFuncPhi.clear();
165 gLPMFuncs.fIsInitialized = false;
166 }
167 }
168}
169
171 const G4DataVector& cuts)
172{
173 if (p) {
174 SetParticle(p);
175 }
176 fCurrentIZ = 0;
177 // init element data and precompute LPM functions (only if lpmflag is true)
178 if (IsMaster()) {
179 InitialiseElementData();
180 if (LPMFlag()) { InitLPMFunctions(); }
183 }
184 }
186 if (GetTripletModel()) {
187 GetTripletModel()->Initialise(p, cuts);
188 fIsScatOffElectron = true;
189 }
190}
191
193 G4VEmModel* masterModel)
194{
197 }
198}
199
201{
205}
206
207// Sets kinematical variables like E_kin, E_t and some material dependent
208// variables like LPM energy and characteristic photon energy k_p (more exactly
209// k_p^2) for the Ter-Mikaelian suppression effect.
211 const G4Material* mat,
212 G4double kineticEnergy)
213{
215 fLPMEnergy = gLPMconstant*mat->GetRadlen();
216 // threshold for LPM effect (i.e. below which LPM hidden by density effect)
217 if (LPMFlag()) {
218 fLPMEnergyThreshold = std::sqrt(fDensityFactor)*fLPMEnergy;
219 } else {
220 fLPMEnergyThreshold = 1.e+39; // i.e. do not use LPM effect
221 }
222 // calculate threshold for density effect: k_p = sqrt(fDensityCorr)
223 fPrimaryKinEnergy = kineticEnergy;
226 // set activation flag for LPM effects in the DCS
227 fIsLPMActive = (fPrimaryTotalEnergy>fLPMEnergyThreshold);
228}
229
230// minimum primary (e-/e+) energy at which discrete interaction is possible
233 G4double cut)
234{
235 return std::max(fLowestKinEnergy, cut);
236}
237
238// Computes the restricted dE/dx as the appropriate weight of the individual
239// element contributions that are computed by numerically integrating the DCS.
242 const G4ParticleDefinition* p,
243 G4double kineticEnergy,
244 G4double cutEnergy)
245{
246 G4double dedx = 0.0;
247 if (!fPrimaryParticle) {
248 SetParticle(p);
249 }
250 if (kineticEnergy < LowEnergyLimit()) {
251 return dedx;
252 }
253 // maximum value of the dE/dx integral (the minimum is 0 of course)
254 G4double tmax = std::min(cutEnergy, kineticEnergy);
255 if (tmax == 0.0) {
256 return dedx;
257 }
258 // sets kinematical and material related variables
259 SetupForMaterial(fPrimaryParticle, material,kineticEnergy);
260 // get element compositions of the material
261 const G4ElementVector* theElemVector = material->GetElementVector();
262 const G4double* theAtomNumDensVector = material->GetAtomicNumDensityVector();
263 const size_t numberOfElements = theElemVector->size();
264 // loop over the elements of the material and compute their contributions to
265 // the restricted dE/dx by numerical integration of the dependent part of DCS
266 for (size_t ie = 0; ie < numberOfElements; ++ie) {
267 G4VEmModel::SetCurrentElement((*theElemVector)[ie]);
268 //SetCurrentElement((*theElementVector)[i]->GetZasInt());
269 const G4double zet = (*theElemVector)[ie]->GetZ();
270 fCurrentIZ = std::min(G4lrint(zet), gMaxZet);
271 dedx += theAtomNumDensVector[ie]*zet*zet*ComputeBremLoss(tmax);
272 }
273 // apply the constant factor C/Z = 16\alpha r_0^2/3
274 dedx *= gBremFactor;
275 return std::max(dedx,0.);
276}
277
278// Computes the integral part of the restricted dE/dx contribution from a given
279// element (Z) by numerically integrating the k dependent part of the DCS between
280// k_min=0 and k_max = tmax = min[gamma-cut, electron-kinetic-eenrgy].
281// The numerical integration is done by dividing the integration range into 'n'
282// subintervals and an 8 pint GL integral (on [0,1]) is performed on each sub-
283// inteval by tranforming k to alpha=k/E_t (E_t is the total energy of the e-)
284// and each sub-interavl is transformed to [0,1]. So the integrastion is done
285// in xi(alpha) = xi(k) = [k/E_t-alpha_i]/delta where alpha_i=(i-1)*delta for
286// the i = 1,2,..,n-th sub-interval so xi(k) in [0,1] on each sub-intevals.
287// This transformation from 'k' to 'xi(k)' results in a multiplicative factor
288// of E_t*delta at each step.
289// The restricted dE/dx = N int_{0}^{k_max} k*ds/dk dk. There are 2 DCS model
290// one with LPM and one without LPM effects (see them below). In both case not
291// the ds/dk(Z,k) but ds/dk(Z,k)*[F*k/C] is computed since:
292// (i) what we need here is ds/dk*k and not k so this multiplication is done
293// (ii) the Ter-Mikaelian suppression i.e. F related factor is done here
294// (iii) the constant factor C (includes Z^2 as well)is accounted in the caller
295G4double G4eBremsstrahlungRelModel::ComputeBremLoss(G4double tmax)
296{
297 // number of intervals and integration step
298 const G4double alphaMax = tmax/fPrimaryTotalEnergy;
299 const G4int nSub = (G4int)(20*alphaMax)+3;
300 const G4double delta = alphaMax/((G4double)nSub);
301 // set minimum value of the first sub-inteval
302 G4double alpha_i = 0.0;
303 G4double dedxInteg = 0.0;
304 for (G4int l = 0; l < nSub; ++l) {
305 for (G4int igl = 0; igl < 8; ++igl) {
306 // compute the emitted photon energy k
307 const G4double k = (alpha_i+gXGL[igl]*delta)*fPrimaryTotalEnergy;
308 // compute the DCS value at k (without the constant, the 1/k, 1/F factors)
309 const G4double dcs = fIsLPMActive
310 ? ComputeRelDXSectionPerAtom(k) // DCS WITHOUT LPM
311 : ComputeDXSectionPerAtom(k); // DCS WITH LPM
312 // account Ter-Mikaelian suppression: times 1/F with F = 1+(k_p/k)^2
313 dedxInteg += gWGL[igl]*dcs/(1.0+fDensityCorr/(k*k));
314 }
315 // update sub-interval minimum value
316 alpha_i += delta;
317 }
318 // apply corrections due to variable transformation i.e. E_t*delta
319 dedxInteg *= delta*fPrimaryTotalEnergy;
320 return std::max(dedxInteg,0.);
321}
322
323// Computes restrected atomic cross section by numerically integrating the
324// DCS between the proper kinematical limits accounting the gamma production cut
326 const G4ParticleDefinition* p,
327 G4double kineticEnergy,
328 G4double Z,
329 G4double,
330 G4double cut,
331 G4double maxEnergy)
332{
333 G4double crossSection = 0.0;
334 if (!fPrimaryParticle) {
335 SetParticle(p);
336 }
337 if (kineticEnergy < LowEnergyLimit()) {
338 return crossSection;
339 }
340 // min/max kinetic energy limits of the DCS integration:
341 const G4double tmin = std::min(cut, kineticEnergy);
342 const G4double tmax = std::min(maxEnergy, kineticEnergy);
343 // zero restricted x-section if e- kinetic energy is below gamma cut
344 if (tmin >= tmax) {
345 return crossSection;
346 }
347 fCurrentIZ = std::min(G4lrint(Z), gMaxZet);
348 // integrate numerically (dependent part of) the DCS between the kin. limits:
349 // a. integrate between tmin and kineticEnergy of the e-
350 crossSection = ComputeXSectionPerAtom(tmin);
351 // allow partial integration: only if maxEnergy < kineticEnergy
352 // b. integrate between tmax and kineticEnergy (tmax=maxEnergy in this case)
353 // (so the result in this case is the integral of DCS between tmin and
354 // maxEnergy)
355 if (tmax < kineticEnergy) {
356 crossSection -= ComputeXSectionPerAtom(tmax);
357 }
358 // multiply with the constant factors: 16\alpha r_0^2/3 Z^2
359 crossSection *= Z*Z*gBremFactor;
360 return std::max(crossSection, 0.);
361}
362
363// Numerical integral of the (k dependent part of) DCS between k_min=tmin and
364// k_max = E_k (where E_k is the kinetic energy of the e- and tmin is the
365// minimum of energy of the emitted photon). The integration is done in the
366// transformed alpha(k) = ln(k/E_t) variable (with E_t being the total energy of
367// the primary e-). The integration range is divided into n sub-intervals with
368// delta = [ln(k_min/E_t)-ln(k_max/E_t)]/n width each. An 8 point GL integral
369// on [0,1] is applied on each sub-inteval so alpha is transformed to
370// xi(alpha) = xi(k) = [ln(k/E_t)-alpha_i]/delta where alpha_i = ln(k_min/E_t) +
371// (i-1)*delta for the i = 1,2,..,n-th sub-interval and xi(k) in [0,1] on each
372// sub-intevals. From the transformed xi, k(xi) = E_t exp[xi*delta+alpha_i].
373// Since the integration is done in variable xi instead of k this
374// transformation results in a multiplicative factor of k*delta at each step.
375// However, DCS differential in k is ~1/k so the multiplicative factor is simple
376// becomes delta and the 1/k factor is dropped from the DCS computation.
377// NOTE:
378// - LPM suppression is accounted above threshold e- energy (corresponidng
379// flag is set in SetUpForMaterial() => 2 DCS with/without LPM
380// - Ter-Mikaelian suppression is always accounted
381G4double G4eBremsstrahlungRelModel::ComputeXSectionPerAtom(G4double tmin)
382{
383 G4double xSection = 0.0;
384 const G4double alphaMin = G4Log(tmin/fPrimaryTotalEnergy);
386 const G4int nSub = (G4int)(0.45*(alphaMax-alphaMin))+4;
387 const G4double delta = (alphaMax-alphaMin)/((G4double)nSub);
388 // set minimum value of the first sub-inteval
389 G4double alpha_i = alphaMin;
390 for (G4int l = 0; l < nSub; ++l) {
391 for (G4int igl = 0; igl < 8; ++igl) {
392 // compute the emitted photon energy k
393 const G4double k = G4Exp(alpha_i+gXGL[igl]*delta)*fPrimaryTotalEnergy;
394 // compute the DCS value at k (without the constant, the 1/k, 1/F factors)
395 const G4double dcs = fIsLPMActive
396 ? ComputeRelDXSectionPerAtom(k) // DCS WITHOUT LPM
397 : ComputeDXSectionPerAtom(k); // DCS WITH LPM
398 // account Ter-Mikaelian suppression: times 1/F with F = 1+(k_p/k)^2
399 xSection += gWGL[igl]*dcs/(1.0+fDensityCorr/(k*k));
400 }
401 // update sub-interval minimum value
402 alpha_i += delta;
403 }
404 // apply corrections due to variable transformation
405 xSection *= delta;
406 // final check
407 return std::max(xSection, 0.);
408}
409
410// DCS WITH LPM EFFECT: complete screening aprx. and includes LPM suppression
411// ds/dk(Z,k) = C/[F*k]*{ Xi(s*F)*[y^2*G/4 +(1-y+y^2/3)Phi]*[L_el-f_c+L_inel/Z]
412// +(1-y)*[1+1/Z]/12} with C = 16\alpha r_0^2/3 Z^2 and
413// Xi(s),G(s), Phi(s) are LPM suppression functions:
414//
415// LPM SUPPRESSION: The 's' is the suppression variable and F = F(k,k_p) =
416// 1+(k_p/k)^2 with k_p = hbar*w_p*E/(m*c^2) is a material (e- density)
417// dependent constant. F accounts the Ter-Mikaelian suppression with a smooth
418// transition in the emitted photon energy. Also, the LPM suppression functions
419// goes to 0 when s goes to 0 and goes to 1 when s is increasing (=1 at s=~2)
420// So evaluating the LPM suppression functions at 'sF' instead of 's' ensures a
421// smooth transition depending on the emitted photon energy 'k': LPM effect is
422// smoothly turned off i.e. Xi(sF)=G(sF)=Phi(sF)=1 when k << k_p because F >> 1
423// and sF ~ s when k >> k_p since F ~ 1 in that case.
424// HERE, ds/dk(Z,k)*[F*k/C] is computed since:
425// (i) DCS ~ 1/k factor will disappear due to the variable transformation
426// v(k)=ln(k/E_t) -> dk/dv=E_t*e^v=k -> ds/dv= ds/dk*dk/dv=ds/dk*k so it
427// would cnacell out the 1/k factor => 1/k don't included here
428// (ii) the constant factor C and Z don't depend on 'k' => not included here
429// (iii) the 1/F(k) factor is accounted in the callers: explicitly (cross sec-
430// tion computation) or implicitly through further variable transformaton
431// (in the final state sampling algorithm)
432// COMPLETE SCREENING: see more at the DCS without LPM effect below.
434G4eBremsstrahlungRelModel::ComputeRelDXSectionPerAtom(G4double gammaEnergy)
435{
436 G4double dxsec = 0.0;
437 if (gammaEnergy < 0.) {
438 return dxsec;
439 }
440 const G4double y = gammaEnergy/fPrimaryTotalEnergy;
441 const G4double onemy = 1.-y;
442 const G4double dum0 = 0.25*y*y;
443 // evaluate LPM functions (combined with the Ter-Mikaelian effect)
444 G4double funcGS, funcPhiS, funcXiS;
445 ComputeLPMfunctions(funcXiS, funcGS, funcPhiS, gammaEnergy);
446 const ElementData* elDat = gElementData[fCurrentIZ];
447 const G4double term1 = funcXiS*(dum0*funcGS+(onemy+2.0*dum0)*funcPhiS);
448 dxsec = term1*elDat->fZFactor1+onemy*elDat->fZFactor2;
449 //
450 if (fIsScatOffElectron) {
451 fSumTerm = dxsec;
452 fNucTerm = term1*elDat->fZFactor11 + onemy/12.;
453 }
454 return std::max(dxsec,0.0);
455}
456
457// DCS WITHOUT LPM EFFECT: DCS with sceening (Z>5) and Coulomb cor. no LPM
458// ds/dk(Z,k)=C/[F*k]*{(1-y+3*y^2/4)*[(0.25*phi1(g)-ln(Z)/3-f_c)+(0.25*psi1(e)
459// -2*ln(Z)/3)/Z]+ (1-y)*[(phi1(g)-phi2(g))+(psi1(e)-psi2(e))/Z]/8}
460// where f_c(Z) is the Coulomb correction factor and phi1(g),phi2(g) and psi1(e),
461// psi2(e) are coherent and incoherent screening functions. In the Thomas-Fermi
462// model of the atom, the screening functions will have a form that do not
463// depend on Z (not explicitly). These numerical screening functions can be
464// approximated as Tsai Eqs. [3.38-3.41] with the variables g=gamma and
465// e=epsilon given by Tsai Eqs. [3.30 and 3.31] (see more details at the method
466// ComputeScreeningFunctions()). Note, that in case of complete screening i.e.
467// g = e = 0 => 0.25*phi1(0)-ln(Z)/3 = ln(184.149/Z^(1/3)) = L_el and
468// 0.25*psi1(0)-2*ln(Z)/3=ln(1193.923/Z^(2/3))=L_inel and phi1(0)-phi2(0) =
469// psi1(0)-psi2(0) = 2/3 so the DCS in complete screening =>
470// COMPLETE SCREENING:
471// ds/dk(Z,k)=C/k*{(1-y+3*y^2/4)*[L_el-f_c+L_inel/Z] + (1-y)*[1+1/Z]/12} that is
472// used in case of DCS with LPM above (if all the suprression functions are
473// absent i.e. their value = 1).
474// Since the Thomas-Fermi model of the atom is not accurate at low Z, the DCS in
475// complete screening is used here at low Z(<5) with L_el(Z), L_inel(Z) values
476// computed by using the Dirac-Fock model of the atom.
477// NOTE: that the Ter-Mikaelian suppression is accounted in the DCS through the
478// 1/F factor but it is included in the caller and not considered here.
479// HERE, ds/dk(Z,k)*[F*k/C] is computed exactly like in the DCS with LPM case.
482{
483 G4double dxsec = 0.0;
484 if (gammaEnergy < 0.) {
485 return dxsec;
486 }
487 const G4double y = gammaEnergy/fPrimaryTotalEnergy;
488 const G4double onemy = 1.-y;
489 const G4double dum0 = onemy+0.75*y*y;
490 const ElementData* elDat = gElementData[fCurrentIZ];
491 // use complete screening and L_el, L_inel from Dirac-Fock model instead of TF
492 if (fCurrentIZ < 5 || fIsUseCompleteScreening) {
493 dxsec = dum0*elDat->fZFactor1;
494 dxsec += onemy*elDat->fZFactor2;
495 if (fIsScatOffElectron) {
496 fSumTerm = dxsec;
497 fNucTerm = dum0*elDat->fZFactor11+onemy/12.;
498 }
499 } else {
500 // use Tsai's analytical approx. (Tsai Eqs. [3.38-3.41]) to the 'universal'
501 // numerical screening functions computed by using the TF model of the atom
502 const G4double invZ = 1./(G4double)fCurrentIZ;
503 const G4double Fz = elDat->fFz;
504 const G4double logZ = elDat->fLogZ;
505 const G4double dum1 = y/(fPrimaryTotalEnergy-gammaEnergy);
506 const G4double gamma = dum1*elDat->fGammaFactor;
507 const G4double epsilon = dum1*elDat->fEpsilonFactor;
508 // evaluate the screening functions
509 G4double phi1, phi1m2, psi1, psi1m2;
510 ComputeScreeningFunctions(phi1, phi1m2, psi1, psi1m2, gamma, epsilon);
511 dxsec = dum0*((0.25*phi1-Fz) + (0.25*psi1-2.*logZ/3.)*invZ);
512 dxsec += 0.125*onemy*(phi1m2 + psi1m2*invZ);
513 if (fIsScatOffElectron) {
514 fSumTerm = dxsec;
515 fNucTerm = dum0*(0.25*phi1-Fz) + 0.125*onemy*phi1m2;
516 }
517 }
518 return std::max(dxsec,0.0);
519}
520
521// Coherent and incoherent screening function approximations (see Tsai
522// Eqs.[3.38-3.41]). Tsai's analytical approximations to the numerical screening
523// functions computed by using the Thomas-Fermi model of atom (Moliere's appro-
524// ximation to the numerical TF screening function). In the TF-model, these
525// screening functions can be expressed in a 'universal' i.e. Z (directly) inde-
526// pendent variable (see Tsai Eqs. Eqs. [3.30 and 3.31]).
527void G4eBremsstrahlungRelModel::ComputeScreeningFunctions(G4double& phi1,
528 G4double& phi1m2,
529 G4double& psi1,
530 G4double& psi1m2,
531 const G4double gam,
532 const G4double eps)
533{
534 const G4double gam2 = gam*gam;
535 phi1 = 16.863-2.0*G4Log(1.0+0.311877*gam2)+2.4*G4Exp(-0.9*gam)
536 +1.6*G4Exp(-1.5*gam);
537 phi1m2 = 2.0/(3.0+19.5*gam+18.0*gam2); // phi1-phi2
538 const G4double eps2 = eps*eps;
539 psi1 = 24.34-2.0*G4Log(1.0+13.111641*eps2)+2.8*G4Exp(-8.0*eps)
540 +1.2*G4Exp(-29.2*eps);
541 psi1m2 = 2.0/(3.0+120.0*eps+1200.0*eps2); //psi1-psi2
542}
543
544void
545G4eBremsstrahlungRelModel::SampleSecondaries(std::vector<G4DynamicParticle*>* vdp,
546 const G4MaterialCutsCouple* couple,
547 const G4DynamicParticle* dp,
548 G4double cutEnergy,
549 G4double maxEnergy)
550{
551 const G4double kineticEnergy = dp->GetKineticEnergy();
552// const G4double logKineticEnergy = dp->GetLogKineticEnergy();
553 if (kineticEnergy < LowEnergyLimit()) {
554 return;
555 }
556 // min, max kinetic energy limits
557 const G4double tmin = std::min(cutEnergy, kineticEnergy);
558 const G4double tmax = std::min(maxEnergy, kineticEnergy);
559 if (tmin >= tmax) {
560 return;
561 }
562 //
563 SetupForMaterial(fPrimaryParticle, couple->GetMaterial(), kineticEnergy);
564 const G4Element* elm = SelectTargetAtom(couple,fPrimaryParticle,kineticEnergy,
565 dp->GetLogKineticEnergy(),tmin,tmax);
566 //
567 fCurrentIZ = elm->GetZasInt();
568 const ElementData* elDat = gElementData[fCurrentIZ];
569 const G4double funcMax = elDat->fZFactor1+elDat->fZFactor2;
570 // get the random engine
571 G4double rndm[2];
572 CLHEP::HepRandomEngine* rndmEngine = G4Random::getTheEngine();
573 // min max of the transformed variable: x(k) = ln(k^2+k_p^2) that is in [ln(k_c^2+k_p^2), ln(E_k^2+k_p^2)]
574 const G4double xmin = G4Log(tmin*tmin+fDensityCorr);
575 const G4double xrange = G4Log(tmax*tmax+fDensityCorr)-xmin;
576 G4double gammaEnergy, funcVal;
577 do {
578 rndmEngine->flatArray(2, rndm);
579 gammaEnergy = std::sqrt(std::max(G4Exp(xmin+rndm[0]*xrange)-fDensityCorr, 0.0));
580 funcVal = fIsLPMActive
581 ? ComputeRelDXSectionPerAtom(gammaEnergy)
582 : ComputeDXSectionPerAtom(gammaEnergy);
583 // cross-check of proper function maximum in the rejection
584// if (funcVal > funcMax) {
585// G4cout << "### G4eBremsstrahlungRelModel Warning: Majoranta exceeded! "
586// << funcVal << " > " << funcMax
587// << " Egamma(MeV)= " << gammaEnergy
588// << " Ee(MeV)= " << kineticEnergy
589// << " " << GetName()
590// << G4endl;
591// }
592 // Loop checking, 03-Aug-2015, Vladimir Ivanchenko
593 } while (funcVal < funcMax*rndm[1]);
594 //
595 // scattering off nucleus or off e- by triplet model
596 if (fIsScatOffElectron && rndmEngine->flat()*fSumTerm>fNucTerm) {
597 GetTripletModel()->SampleSecondaries(vdp, couple, dp, cutEnergy, maxEnergy);
598 return;
599 }
600 //
601 // angles of the emitted gamma. ( Z - axis along the parent particle)
602 // use general interface
603 G4ThreeVector gamDir =
605 fCurrentIZ, couple->GetMaterial());
606 // create G4DynamicParticle object for the Gamma
608 gammaEnergy);
609 vdp->push_back(gamma);
610 // compute post-interaction kinematics of primary e-/e+ based on
611 // energy-momentum conservation
612 const G4double totMomentum = std::sqrt(kineticEnergy*(
613 fPrimaryTotalEnergy + CLHEP::electron_mass_c2));
614 G4ThreeVector dir =
615 (totMomentum*dp->GetMomentumDirection()-gammaEnergy*gamDir).unit();
616 const G4double finalE = kineticEnergy-gammaEnergy;
617 // if secondary gamma energy is higher than threshold(very high by default)
618 // then stop tracking the primary particle and create new secondary e-/e+
619 // instead of the primary one
620 if (gammaEnergy > SecondaryThreshold()) {
624 const_cast<G4ParticleDefinition*>(fPrimaryParticle), dir, finalE);
625 vdp->push_back(el);
626 } else { // continue tracking the primary e-/e+ otherwise
629 }
630}
631
632void G4eBremsstrahlungRelModel::InitialiseElementData()
633{
634 const G4int size = gElementData.size();
635 if (size < gMaxZet+1) {
636 gElementData.resize(gMaxZet+1, nullptr);
637 }
638 // create for all elements that are in the detector
639 const G4ElementTable* elemTable = G4Element::GetElementTable();
640 size_t numElems = (*elemTable).size();
641 for (size_t ielem=0; ielem<numElems; ++ielem) {
642 const G4Element* elem = (*elemTable)[ielem];
643 const G4double zet = elem->GetZ();
644 const G4int izet = std::min(G4lrint(zet),gMaxZet);
645 if (!gElementData[izet]) {
646 ElementData *elemData = new ElementData();
647 const G4double fc = elem->GetfCoulomb();
648 G4double Fel = 1.;
649 G4double Finel = 1.;
650 elemData->fLogZ = G4Log(zet);
651 elemData->fFz = elemData->fLogZ/3.+fc;
652 if (izet < 5) {
653 Fel = gFelLowZet[izet];
654 Finel = gFinelLowZet[izet];
655 } else {
656 Fel = G4Log(184.15) - elemData->fLogZ/3.;
657 Finel = G4Log(1194) - 2.*elemData->fLogZ/3.;
658 }
659 const G4double z23 = std::pow(zet,2./3.);
660 const G4double z13 = std::pow(zet,1./3.);
661 elemData->fZFactor1 = (Fel-fc)+Finel/zet;
662 elemData->fZFactor11 = (Fel-fc); // used only for the triplet
663 elemData->fZFactor2 = (1.+1./zet)/12.;
664 elemData->fVarS1 = z23/(184.15*184.15);
665 elemData->fILVarS1Cond = 1./(G4Log(std::sqrt(2.0)*elemData->fVarS1));
666 elemData->fILVarS1 = 1./G4Log(elemData->fVarS1);
667 elemData->fGammaFactor = 100.0*electron_mass_c2/z13;
668 elemData->fEpsilonFactor = 100.0*electron_mass_c2/z23;
669 gElementData[izet] = elemData;
670 }
671 }
672}
673
674void G4eBremsstrahlungRelModel::ComputeLPMfunctions(G4double& funcXiS,
675 G4double& funcGS,
676 G4double& funcPhiS,
677 const G4double egamma)
678{
679 static const G4double sqrt2 = std::sqrt(2.);
680 const G4double redegamma = egamma/fPrimaryTotalEnergy;
681 const G4double varSprime = std::sqrt(0.125*redegamma*fLPMEnergy/
682 ((1.0-redegamma)*fPrimaryTotalEnergy));
683 const ElementData* elDat = gElementData[fCurrentIZ];
684 const G4double varS1 = elDat->fVarS1;
685 const G4double condition = sqrt2*varS1;
686 G4double funcXiSprime = 2.0;
687 if (varSprime > 1.0) {
688 funcXiSprime = 1.0;
689 } else if (varSprime > condition) {
690 const G4double ilVarS1Cond = elDat->fILVarS1Cond;
691 const G4double funcHSprime = G4Log(varSprime)*ilVarS1Cond;
692 funcXiSprime = 1.0 + funcHSprime - 0.08*(1.0-funcHSprime)*funcHSprime
693 *(2.0-funcHSprime)*ilVarS1Cond;
694 }
695 const G4double varS = varSprime/std::sqrt(funcXiSprime);
696 // - include dielectric suppression effect into s according to Migdal
697 const G4double varShat = varS*(1.0+fDensityCorr/(egamma*egamma));
698 funcXiS = 2.0;
699 if (varShat > 1.0) {
700 funcXiS = 1.0;
701 } else if (varShat > varS1) {
702 funcXiS = 1.0+G4Log(varShat)*elDat->fILVarS1;
703 }
704 GetLPMFunctions(funcGS, funcPhiS, varShat);
705 //ComputeLPMGsPhis(funcGS, funcPhiS, varShat);
706 //
707 //MAKE SURE SUPPRESSION IS SMALLER THAN 1: due to Migdal's approximation on xi
708 if (funcXiS*funcPhiS > 1. || varShat > 0.57) {
709 funcXiS=1./funcPhiS;
710 }
711}
712
713void G4eBremsstrahlungRelModel::ComputeLPMGsPhis(G4double& funcGS,
714 G4double& funcPhiS,
715 const G4double varShat)
716{
717 if (varShat < 0.01) {
718 funcPhiS = 6.0*varShat*(1.0-CLHEP::pi*varShat);
719 funcGS = 12.0*varShat-2.0*funcPhiS;
720 } else {
721 const G4double varShat2 = varShat*varShat;
722 const G4double varShat3 = varShat*varShat2;
723 const G4double varShat4 = varShat2*varShat2;
724 // use Stanev approximation: for \psi(s) and compute G(s)
725 if (varShat < 0.415827) {
726 funcPhiS = 1.0-G4Exp(-6.0*varShat*(1.0+varShat*(3.0-CLHEP::pi))
727 + varShat3/(0.623+0.796*varShat+0.658*varShat2));
728 // 1-\exp \left\{-4s-\frac{8s^2}{1+3.936s+4.97s^2-0.05s^3+7.5s^4} \right\}
729 const G4double funcPsiS = 1.0 - G4Exp(-4.0*varShat
730 - 8.0*varShat2/(1.0+3.936*varShat+4.97*varShat2
731 - 0.05*varShat3 + 7.5*varShat4));
732 // G(s) = 3 \psi(s) - 2 \phi(s)
733 funcGS = 3.0*funcPsiS - 2.0*funcPhiS;
734 } else if (varShat<1.55) {
735 funcPhiS = 1.0-G4Exp(-6.0*varShat*(1.0+varShat*(3.0-CLHEP::pi))
736 + varShat3/(0.623+0.796*varShat+0.658*varShat2));
737 const G4double dum0 = -0.160723 + 3.755030*varShat
738 -1.798138*varShat2 + 0.672827*varShat3
739 -0.120772*varShat4;
740 funcGS = std::tanh(dum0);
741 } else {
742 funcPhiS = 1.0-0.011905/varShat4;
743 if (varShat<1.9156) {
744 const G4double dum0 = -0.160723 + 3.755030*varShat
745 -1.798138*varShat2 + 0.672827*varShat3
746 -0.120772*varShat4;
747 funcGS = std::tanh(dum0);
748 } else {
749 funcGS = 1.0-0.023065/varShat4;
750 }
751 }
752 }
753}
754
755// s goes up to 2 with ds = 0.01 to be the default bining
756void G4eBremsstrahlungRelModel::InitLPMFunctions()
757{
758 if (!gLPMFuncs.fIsInitialized) {
759 const G4int num = gLPMFuncs.fSLimit*gLPMFuncs.fISDelta+1;
760 gLPMFuncs.fLPMFuncG.resize(num);
761 gLPMFuncs.fLPMFuncPhi.resize(num);
762 for (G4int i = 0; i < num; ++i) {
763 const G4double sval=i/gLPMFuncs.fISDelta;
764 ComputeLPMGsPhis(gLPMFuncs.fLPMFuncG[i],gLPMFuncs.fLPMFuncPhi[i],sval);
765 }
766 gLPMFuncs.fIsInitialized = true;
767 }
768}
769
770void G4eBremsstrahlungRelModel::GetLPMFunctions(G4double& lpmGs,
771 G4double& lpmPhis,
772 const G4double sval)
773{
774 if (sval < gLPMFuncs.fSLimit) {
775 G4double val = sval*gLPMFuncs.fISDelta;
776 const G4int ilow = (G4int)val;
777 val -= ilow;
778 lpmGs = (gLPMFuncs.fLPMFuncG[ilow+1]-gLPMFuncs.fLPMFuncG[ilow])*val
779 + gLPMFuncs.fLPMFuncG[ilow];
780 lpmPhis = (gLPMFuncs.fLPMFuncPhi[ilow+1]-gLPMFuncs.fLPMFuncPhi[ilow])*val
781 + gLPMFuncs.fLPMFuncPhi[ilow];
782 } else {
783 G4double ss = sval*sval;
784 ss *= ss;
785 lpmPhis = 1.0-0.01190476/ss;
786 lpmGs = 1.0-0.0230655/ss;
787 }
788}
789
double epsilon(double density, double temperature)
std::vector< G4Element * > G4ElementTable
std::vector< G4Element * > G4ElementVector
G4double condition(const G4ErrorSymMatrix &m)
G4double G4Exp(G4double initial_x)
Exponential Function double precision.
Definition: G4Exp.hh:179
G4double G4Log(G4double x)
Definition: G4Log.hh:226
@ fStopAndKill
double G4double
Definition: G4Types.hh:83
int G4int
Definition: G4Types.hh:85
virtual double flat()=0
virtual void flatArray(const int size, double *vect)=0
const G4ThreeVector & GetMomentumDirection() const
G4double GetLogKineticEnergy() const
G4double GetKineticEnergy() const
static G4Electron * Electron()
Definition: G4Electron.cc:93
static G4ElementTable * GetElementTable()
Definition: G4Element.cc:397
G4double GetZ() const
Definition: G4Element.hh:130
G4double GetfCoulomb() const
Definition: G4Element.hh:190
G4int GetZasInt() const
Definition: G4Element.hh:131
static G4Gamma * Gamma()
Definition: G4Gamma.cc:85
const G4Material * GetMaterial() const
const G4ElementVector * GetElementVector() const
Definition: G4Material.hh:188
const G4double * GetAtomicNumDensityVector() const
Definition: G4Material.hh:214
G4double GetElectronDensity() const
Definition: G4Material.hh:215
G4double GetRadlen() const
Definition: G4Material.hh:218
void SetProposedKineticEnergy(G4double proposedKinEnergy)
void SetProposedMomentumDirection(const G4ThreeVector &dir)
virtual G4ThreeVector & SampleDirection(const G4DynamicParticle *dp, G4double finalTotalEnergy, G4int Z, const G4Material *)=0
void SetElementSelectors(std::vector< G4EmElementSelector * > *)
Definition: G4VEmModel.hh:842
G4VEmAngularDistribution * GetAngularDistribution()
Definition: G4VEmModel.hh:611
G4double LowEnergyLimit() const
Definition: G4VEmModel.hh:652
std::vector< G4EmElementSelector * > * GetElementSelectors()
Definition: G4VEmModel.hh:834
G4bool IsMaster() const
Definition: G4VEmModel.hh:736
G4VEmModel * GetTripletModel()
Definition: G4VEmModel.hh:628
void SetLPMFlag(G4bool val)
Definition: G4VEmModel.hh:806
G4double HighEnergyLimit() const
Definition: G4VEmModel.hh:645
void SetCurrentElement(const G4Element *)
Definition: G4VEmModel.hh:487
G4bool LPMFlag() const
Definition: G4VEmModel.hh:687
void SetLowEnergyLimit(G4double)
Definition: G4VEmModel.hh:764
void SetAngularDistribution(G4VEmAngularDistribution *)
Definition: G4VEmModel.hh:618
virtual void SampleSecondaries(std::vector< G4DynamicParticle * > *, const G4MaterialCutsCouple *, const G4DynamicParticle *, G4double tmin=0.0, G4double tmax=DBL_MAX)=0
const G4Element * SelectTargetAtom(const G4MaterialCutsCouple *, const G4ParticleDefinition *, G4double kineticEnergy, G4double logKineticEnergy, G4double cutEnergy=0.0, G4double maxEnergy=DBL_MAX)
Definition: G4VEmModel.hh:587
void InitialiseElementSelectors(const G4ParticleDefinition *, const G4DataVector &)
Definition: G4VEmModel.cc:148
virtual void Initialise(const G4ParticleDefinition *, const G4DataVector &)=0
G4double SecondaryThreshold() const
Definition: G4VEmModel.hh:680
G4ParticleChangeForLoss * GetParticleChangeForLoss()
Definition: G4VEmModel.cc:118
void ProposeTrackStatus(G4TrackStatus status)
void SetParticle(const G4ParticleDefinition *p)
virtual G4double ComputeCrossSectionPerAtom(const G4ParticleDefinition *, G4double ekin, G4double zet, G4double, G4double cutEnergy, G4double maxEnergy=DBL_MAX) override
G4eBremsstrahlungRelModel(const G4ParticleDefinition *p=0, const G4String &nam="eBremLPM")
virtual G4double ComputeDXSectionPerAtom(G4double gammaEnergy)
const G4ParticleDefinition * fPrimaryParticle
virtual void InitialiseLocal(const G4ParticleDefinition *, G4VEmModel *masterModel) override
virtual void SampleSecondaries(std::vector< G4DynamicParticle * > *, const G4MaterialCutsCouple *, const G4DynamicParticle *, G4double cutEnergy, G4double maxEnergy) override
virtual G4double ComputeDEDXPerVolume(const G4Material *, const G4ParticleDefinition *, G4double ekin, G4double cutEnergy) override
G4ParticleDefinition * fGammaParticle
virtual void SetupForMaterial(const G4ParticleDefinition *, const G4Material *, G4double) override
G4ParticleChangeForLoss * fParticleChange
virtual G4double MinPrimaryEnergy(const G4Material *, const G4ParticleDefinition *, G4double cutEnergy) override
virtual void Initialise(const G4ParticleDefinition *, const G4DataVector &) override
int G4lrint(double ad)
Definition: templates.hh:134