Geant4 11.4.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 "G4LPMFunction.hh"
72#include "G4Exp.hh"
73#include "G4Log.hh"
74#include "G4Pow.hh"
75#include "G4EmParameters.hh"
76#include "G4AutoLock.hh"
77#include <thread>
78
79const G4int G4eBremsstrahlungRelModel::gMaxZet = 120;
80
81// constant DCS factor: 16\alpha r_0^2/3
83 = 16. * CLHEP::fine_structure_const * CLHEP::classic_electr_radius
84 * CLHEP::classic_electr_radius/3.;
85
86// Migdal's constant: 4\pi r_0*electron_reduced_compton_wavelength^2
88 = 4. * CLHEP::pi * CLHEP::classic_electr_radius
89 * CLHEP::electron_Compton_length * CLHEP::electron_Compton_length;
90
91// LPM constant: \alpha(mc^2)^2/(4\pi*\hbar c)
92const G4double G4eBremsstrahlungRelModel::gLPMconstant
93 = CLHEP::fine_structure_const * CLHEP::electron_mass_c2
94 * CLHEP::electron_mass_c2 / (4. * CLHEP::pi * CLHEP::hbarc);
95
96// abscissas and weights of an 8 point Gauss-Legendre quadrature
97// for numerical integration on [0,1]
98const G4double G4eBremsstrahlungRelModel::gXGL[] = {
99 1.98550718e-02, 1.01666761e-01, 2.37233795e-01, 4.08282679e-01,
100 5.91717321e-01, 7.62766205e-01, 8.98333239e-01, 9.80144928e-01
101};
102const G4double G4eBremsstrahlungRelModel::gWGL[] = {
103 5.06142681e-02, 1.11190517e-01, 1.56853323e-01, 1.81341892e-01,
104 1.81341892e-01, 1.56853323e-01, 1.11190517e-01, 5.06142681e-02
105};
106
107// elastic and inelatic radiation logarithms for light elements (where the
108// Thomas-Fermi model doesn't work): computed by using Dirac-Fock model of atom.
109const G4double G4eBremsstrahlungRelModel::gFelLowZet [] = {
110 0.0, 5.3104, 4.7935, 4.7402, 4.7112, 4.6694, 4.6134, 4.5520
111};
112const G4double G4eBremsstrahlungRelModel::gFinelLowZet[] = {
113 0.0, 5.9173, 5.6125, 5.5377, 5.4728, 5.4174, 5.3688, 5.3236
114};
115
116// special data structure per element i.e. per Z
117std::vector<G4eBremsstrahlungRelModel::ElementData*> G4eBremsstrahlungRelModel::gElementData;
118
119static std::once_flag applyOnce;
120
121namespace
122{
123 G4Mutex theBremRelMutex = G4MUTEX_INITIALIZER;
124}
125
127 const G4String& nam)
128: G4VEmModel(nam)
129{
131 //
132 fLowestKinEnergy = 1.0*CLHEP::MeV;
134 //
135 fLPMEnergyThreshold = 1.e+39;
136 fLPMEnergy = 0.;
138 //
139 if (nullptr != p) {
140 SetParticle(p);
141 }
142}
143
145{
146 if (fIsInitializer) {
147 // clear ElementData container
148 for (auto const & ptr : gElementData) { delete ptr; }
149 gElementData.clear();
150 }
151}
152
154 const G4DataVector& cuts)
155{
156 // parameters in each thread
157 if (fPrimaryParticle != p) {
158 SetParticle(p);
159 }
160 fUseLPM = G4EmParameters::Instance()->LPM();
161 fCurrentIZ = 0;
162
163 // init static element data and precompute LPM functions only once
164 std::call_once(applyOnce, [this]() { fIsInitializer = true; });
165
166 // for all treads and derived classes
167 if (fIsInitializer || gElementData.empty()) {
168 G4AutoLock l(&theBremRelMutex);
169 if (gElementData.empty()) {
170 gElementData.resize(gMaxZet+1, nullptr);
171 }
172 InitialiseElementData();
173 l.unlock();
174 }
175
176 // element selectors are initialized in the master thread
177 if (IsMaster()) {
179 }
180 // initialisation in all threads
181 if (nullptr == fParticleChange) {
183 }
184 if (GetTripletModel()) {
185 GetTripletModel()->Initialise(p, cuts);
186 fIsScatOffElectron = true;
187 }
188}
189
195
202
203// Sets kinematical variables like E_kin, E_t and some material dependent
204// variables like LPM energy and characteristic photon energy k_p (more exactly
205// k_p^2) for the Ter-Mikaelian suppression effect.
207 const G4Material* mat,
208 G4double kineticEnergy)
209{
211 fLPMEnergy = gLPMconstant*mat->GetRadlen();
212 // threshold for LPM effect (i.e. below which LPM hidden by density effect)
213 if (fUseLPM) {
214 fLPMEnergyThreshold = std::sqrt(fDensityFactor)*fLPMEnergy;
215 } else {
216 fLPMEnergyThreshold = 1.e+39; // i.e. do not use LPM effect
217 }
218 // calculate threshold for density effect: k_p = sqrt(fDensityCorr)
219 fPrimaryKinEnergy = kineticEnergy;
222 // set activation flag for LPM effects in the DCS
223 fIsLPMActive = (fPrimaryTotalEnergy>fLPMEnergyThreshold);
224}
225
226// minimum primary (e-/e+) energy at which discrete interaction is possible
233
234// Computes the restricted dE/dx as the appropriate weight of the individual
235// element contributions that are computed by numerically integrating the DCS.
238 const G4ParticleDefinition* p,
239 G4double kineticEnergy,
240 G4double cutEnergy)
241{
242 G4double dedx = 0.0;
243 if (nullptr == fPrimaryParticle) {
244 SetParticle(p);
245 }
246 if (kineticEnergy < LowEnergyLimit()) {
247 return dedx;
248 }
249 // maximum value of the dE/dx integral (the minimum is 0 of course)
250 G4double tmax = std::min(cutEnergy, kineticEnergy);
251 if (tmax == 0.0) {
252 return dedx;
253 }
254 // sets kinematical and material related variables
255 SetupForMaterial(fPrimaryParticle, material,kineticEnergy);
256 // get element compositions of the material
257 const G4ElementVector* theElemVector = material->GetElementVector();
258 const G4double* theAtomNumDensVector = material->GetAtomicNumDensityVector();
259 const std::size_t numberOfElements = theElemVector->size();
260 // loop over the elements of the material and compute their contributions to
261 // the restricted dE/dx by numerical integration of the dependent part of DCS
262 for (std::size_t ie = 0; ie < numberOfElements; ++ie) {
263 G4VEmModel::SetCurrentElement((*theElemVector)[ie]);
264 G4int zet = (*theElemVector)[ie]->GetZasInt();
265 fCurrentIZ = std::min(zet, gMaxZet);
266 dedx += (zet*zet)*theAtomNumDensVector[ie]*ComputeBremLoss(tmax);
267 }
268 // apply the constant factor C/Z = 16\alpha r_0^2/3
269 dedx *= gBremFactor;
270 return std::max(dedx,0.);
271}
272
273// Computes the integral part of the restricted dE/dx contribution from a given
274// element (Z) by numerically integrating the k dependent part of the DCS between
275// k_min=0 and k_max = tmax = min[gamma-cut, electron-kinetic-eenrgy].
276// The numerical integration is done by dividing the integration range into 'n'
277// subintervals and an 8 pint GL integral (on [0,1]) is performed on each sub-
278// inteval by tranforming k to alpha=k/E_t (E_t is the total energy of the e-)
279// and each sub-interavl is transformed to [0,1]. So the integrastion is done
280// in xi(alpha) = xi(k) = [k/E_t-alpha_i]/delta where alpha_i=(i-1)*delta for
281// the i = 1,2,..,n-th sub-interval so xi(k) in [0,1] on each sub-intevals.
282// This transformation from 'k' to 'xi(k)' results in a multiplicative factor
283// of E_t*delta at each step.
284// The restricted dE/dx = N int_{0}^{k_max} k*ds/dk dk. There are 2 DCS model
285// one with LPM and one without LPM effects (see them below). In both case not
286// the ds/dk(Z,k) but ds/dk(Z,k)*[F*k/C] is computed since:
287// (i) what we need here is ds/dk*k and not k so this multiplication is done
288// (ii) the Ter-Mikaelian suppression i.e. F related factor is done here
289// (iii) the constant factor C (includes Z^2 as well)is accounted in the caller
290G4double G4eBremsstrahlungRelModel::ComputeBremLoss(G4double tmax)
291{
292 // number of intervals and integration step
293 const G4double alphaMax = tmax/fPrimaryTotalEnergy;
294 const G4int nSub = (G4int)(20*alphaMax)+3;
295 const G4double delta = alphaMax/((G4double)nSub);
296 // set minimum value of the first sub-inteval
297 G4double alpha_i = 0.0;
298 G4double dedxInteg = 0.0;
299 for (G4int l = 0; l < nSub; ++l) {
300 for (G4int igl = 0; igl < 8; ++igl) {
301 // compute the emitted photon energy k
302 const G4double k = (alpha_i+gXGL[igl]*delta)*fPrimaryTotalEnergy;
303 // compute the DCS value at k (without the constant, the 1/k, 1/F factors)
304 const G4double dcs = fIsLPMActive
305 ? ComputeRelDXSectionPerAtom(k) // DCS WITHOUT LPM
306 : ComputeDXSectionPerAtom(k); // DCS WITH LPM
307 // account Ter-Mikaelian suppression: times 1/F with F = 1+(k_p/k)^2
308 dedxInteg += gWGL[igl]*dcs/(1.0+fDensityCorr/(k*k));
309 }
310 // update sub-interval minimum value
311 alpha_i += delta;
312 }
313 // apply corrections due to variable transformation i.e. E_t*delta
314 dedxInteg *= delta*fPrimaryTotalEnergy;
315 return std::max(dedxInteg,0.);
316}
317
318// Computes restrected atomic cross section by numerically integrating the
319// DCS between the proper kinematical limits accounting the gamma production cut
321 const G4ParticleDefinition* p,
322 G4double kineticEnergy,
323 G4double Z,
324 G4double,
325 G4double cut,
326 G4double maxEnergy)
327{
328 G4double crossSection = 0.0;
329 if (nullptr == fPrimaryParticle) {
330 SetParticle(p);
331 }
332 if (kineticEnergy < LowEnergyLimit()) {
333 return crossSection;
334 }
335 // min/max kinetic energy limits of the DCS integration:
336 const G4double tmin = std::min(cut, kineticEnergy);
337 const G4double tmax = std::min(maxEnergy, kineticEnergy);
338 // zero restricted x-section if e- kinetic energy is below gamma cut
339 if (tmin >= tmax) {
340 return crossSection;
341 }
342 fCurrentIZ = std::min(G4lrint(Z), gMaxZet);
343 // integrate numerically (dependent part of) the DCS between the kin. limits:
344 // a. integrate between tmin and kineticEnergy of the e-
345 crossSection = ComputeXSectionPerAtom(tmin);
346 // allow partial integration: only if maxEnergy < kineticEnergy
347 // b. integrate between tmax and kineticEnergy (tmax=maxEnergy in this case)
348 // (so the result in this case is the integral of DCS between tmin and
349 // maxEnergy)
350 if (tmax < kineticEnergy) {
351 crossSection -= ComputeXSectionPerAtom(tmax);
352 }
353 // multiply with the constant factors: 16\alpha r_0^2/3 Z^2
354 crossSection *= Z*Z*gBremFactor;
355 return std::max(crossSection, 0.);
356}
357
358// Numerical integral of the (k dependent part of) DCS between k_min=tmin and
359// k_max = E_k (where E_k is the kinetic energy of the e- and tmin is the
360// minimum of energy of the emitted photon). The integration is done in the
361// transformed alpha(k) = ln(k/E_t) variable (with E_t being the total energy of
362// the primary e-). The integration range is divided into n sub-intervals with
363// delta = [ln(k_min/E_t)-ln(k_max/E_t)]/n width each. An 8 point GL integral
364// on [0,1] is applied on each sub-inteval so alpha is transformed to
365// xi(alpha) = xi(k) = [ln(k/E_t)-alpha_i]/delta where alpha_i = ln(k_min/E_t) +
366// (i-1)*delta for the i = 1,2,..,n-th sub-interval and xi(k) in [0,1] on each
367// sub-intevals. From the transformed xi, k(xi) = E_t exp[xi*delta+alpha_i].
368// Since the integration is done in variable xi instead of k this
369// transformation results in a multiplicative factor of k*delta at each step.
370// However, DCS differential in k is ~1/k so the multiplicative factor is simple
371// becomes delta and the 1/k factor is dropped from the DCS computation.
372// NOTE:
373// - LPM suppression is accounted above threshold e- energy (corresponidng
374// flag is set in SetUpForMaterial() => 2 DCS with/without LPM
375// - Ter-Mikaelian suppression is always accounted
376G4double G4eBremsstrahlungRelModel::ComputeXSectionPerAtom(G4double tmin)
377{
378 G4double xSection = 0.0;
379 const G4double alphaMin = G4Log(tmin/fPrimaryTotalEnergy);
380 const G4double alphaMax = G4Log(fPrimaryKinEnergy/tmin);
381 const G4int nSub = std::max((G4int)(0.45*alphaMax), 0) + 4;
382 const G4double delta = alphaMax/((G4double)nSub);
383 // set minimum value of the first sub-inteval
384 G4double alpha_i = alphaMin;
385 for (G4int l = 0; l < nSub; ++l) {
386 for (G4int igl = 0; igl < 8; ++igl) {
387 // compute the emitted photon energy k
388 const G4double k = G4Exp(alpha_i+gXGL[igl]*delta)*fPrimaryTotalEnergy;
389 // compute the DCS value at k (without the constant, the 1/k, 1/F factors)
390 const G4double dcs = fIsLPMActive
391 ? ComputeRelDXSectionPerAtom(k) // DCS WITHOUT LPM
392 : ComputeDXSectionPerAtom(k); // DCS WITH LPM
393 // account Ter-Mikaelian suppression: times 1/F with F = 1+(k_p/k)^2
394 xSection += gWGL[igl]*dcs/(1.0+fDensityCorr/(k*k));
395 }
396 // update sub-interval minimum value
397 alpha_i += delta;
398 }
399 // apply corrections due to variable transformation
400 xSection *= delta;
401 // final check
402 return std::max(xSection, 0.);
403}
404
405// DCS WITH LPM EFFECT: complete screening aprx. and includes LPM suppression
406// 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]
407// +(1-y)*[1+1/Z]/12} with C = 16\alpha r_0^2/3 Z^2 and
408// Xi(s),G(s), Phi(s) are LPM suppression functions:
409//
410// LPM SUPPRESSION: The 's' is the suppression variable and F = F(k,k_p) =
411// 1+(k_p/k)^2 with k_p = hbar*w_p*E/(m*c^2) is a material (e- density)
412// dependent constant. F accounts the Ter-Mikaelian suppression with a smooth
413// transition in the emitted photon energy. Also, the LPM suppression functions
414// goes to 0 when s goes to 0 and goes to 1 when s is increasing (=1 at s=~2)
415// So evaluating the LPM suppression functions at 'sF' instead of 's' ensures a
416// smooth transition depending on the emitted photon energy 'k': LPM effect is
417// smoothly turned off i.e. Xi(sF)=G(sF)=Phi(sF)=1 when k << k_p because F >> 1
418// and sF ~ s when k >> k_p since F ~ 1 in that case.
419// HERE, ds/dk(Z,k)*[F*k/C] is computed since:
420// (i) DCS ~ 1/k factor will disappear due to the variable transformation
421// v(k)=ln(k/E_t) -> dk/dv=E_t*e^v=k -> ds/dv= ds/dk*dk/dv=ds/dk*k so it
422// would cnacell out the 1/k factor => 1/k don't included here
423// (ii) the constant factor C and Z don't depend on 'k' => not included here
424// (iii) the 1/F(k) factor is accounted in the callers: explicitly (cross sec-
425// tion computation) or implicitly through further variable transformaton
426// (in the final state sampling algorithm)
427// COMPLETE SCREENING: see more at the DCS without LPM effect below.
429G4eBremsstrahlungRelModel::ComputeRelDXSectionPerAtom(G4double gammaEnergy)
430{
431 G4double dxsec = 0.0;
432 if (gammaEnergy < 0.) {
433 return dxsec;
434 }
435 const G4double y = gammaEnergy/fPrimaryTotalEnergy;
436 const G4double onemy = 1.-y;
437 const G4double dum0 = 0.25*y*y;
438 // evaluate LPM functions (combined with the Ter-Mikaelian effect)
439 G4double funcGS, funcPhiS, funcXiS;
440 ComputeLPMfunctions(funcXiS, funcGS, funcPhiS, gammaEnergy);
441 const ElementData* elDat = gElementData[fCurrentIZ];
442 const G4double term1 = funcXiS*(dum0*funcGS+(onemy+2.0*dum0)*funcPhiS);
443 dxsec = term1*elDat->fZFactor1+onemy*elDat->fZFactor2;
444 //
445 if (fIsScatOffElectron) {
446 fSumTerm = dxsec;
447 fNucTerm = term1*elDat->fZFactor11 + onemy/12.;
448 }
449 return std::max(dxsec,0.0);
450}
451
452// DCS WITHOUT LPM EFFECT: DCS with sceening (Z>5) and Coulomb cor. no LPM
453// 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)
454// -2*ln(Z)/3)/Z]+ (1-y)*[(phi1(g)-phi2(g))+(psi1(e)-psi2(e))/Z]/8}
455// where f_c(Z) is the Coulomb correction factor and phi1(g),phi2(g) and psi1(e),
456// psi2(e) are coherent and incoherent screening functions. In the Thomas-Fermi
457// model of the atom, the screening functions will have a form that do not
458// depend on Z (not explicitly). These numerical screening functions can be
459// approximated as Tsai Eqs. [3.38-3.41] with the variables g=gamma and
460// e=epsilon given by Tsai Eqs. [3.30 and 3.31] (see more details at the method
461// ComputeScreeningFunctions()). Note, that in case of complete screening i.e.
462// g = e = 0 => 0.25*phi1(0)-ln(Z)/3 = ln(184.149/Z^(1/3)) = L_el and
463// 0.25*psi1(0)-2*ln(Z)/3=ln(1193.923/Z^(2/3))=L_inel and phi1(0)-phi2(0) =
464// psi1(0)-psi2(0) = 2/3 so the DCS in complete screening =>
465// COMPLETE SCREENING:
466// 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
467// used in case of DCS with LPM above (if all the suprression functions are
468// absent i.e. their value = 1).
469// Since the Thomas-Fermi model of the atom is not accurate at low Z, the DCS in
470// complete screening is used here at low Z(<5) with L_el(Z), L_inel(Z) values
471// computed by using the Dirac-Fock model of the atom.
472// NOTE: that the Ter-Mikaelian suppression is accounted in the DCS through the
473// 1/F factor but it is included in the caller and not considered here.
474// HERE, ds/dk(Z,k)*[F*k/C] is computed exactly like in the DCS with LPM case.
477{
478 G4double dxsec = 0.0;
479 if (gammaEnergy < 0.) {
480 return dxsec;
481 }
482 const G4double y = gammaEnergy/fPrimaryTotalEnergy;
483 const G4double onemy = 1.-y;
484 const G4double dum0 = onemy+0.75*y*y;
485 const ElementData* elDat = gElementData[fCurrentIZ];
486 // use complete screening and L_el, L_inel from Dirac-Fock model instead of TF
487 if (fCurrentIZ < 5 || fIsUseCompleteScreening) {
488 dxsec = dum0*elDat->fZFactor1;
489 dxsec += onemy*elDat->fZFactor2;
490 if (fIsScatOffElectron) {
491 fSumTerm = dxsec;
492 fNucTerm = dum0*elDat->fZFactor11+onemy/12.;
493 }
494 } else {
495 // use Tsai's analytical approx. (Tsai Eqs. [3.38-3.41]) to the 'universal'
496 // numerical screening functions computed by using the TF model of the atom
497 const G4double invZ = 1./(G4double)fCurrentIZ;
498 const G4double Fz = elDat->fFz;
499 const G4double logZ = elDat->fLogZ;
500 const G4double dum1 = y/(fPrimaryTotalEnergy-gammaEnergy);
501 const G4double gamma = dum1*elDat->fGammaFactor;
502 const G4double epsilon = dum1*elDat->fEpsilonFactor;
503 // evaluate the screening functions
504 G4double phi1, phi1m2, psi1, psi1m2;
505 ComputeScreeningFunctions(phi1, phi1m2, psi1, psi1m2, gamma, epsilon);
506 dxsec = dum0*((0.25*phi1-Fz) + (0.25*psi1-2.*logZ/3.)*invZ);
507 dxsec += 0.125*onemy*(phi1m2 + psi1m2*invZ);
508 if (fIsScatOffElectron) {
509 fSumTerm = dxsec;
510 fNucTerm = dum0*(0.25*phi1-Fz) + 0.125*onemy*phi1m2;
511 }
512 }
513 return std::max(dxsec,0.0);
514}
515
516// Coherent and incoherent screening function approximations (see Tsai
517// Eqs.[3.38-3.41]). Tsai's analytical approximations to the numerical screening
518// functions computed by using the Thomas-Fermi model of atom (Moliere's appro-
519// ximation to the numerical TF screening function). In the TF-model, these
520// screening functions can be expressed in a 'universal' i.e. Z (directly) inde-
521// pendent variable (see Tsai Eqs. Eqs. [3.30 and 3.31]).
522void G4eBremsstrahlungRelModel::ComputeScreeningFunctions(G4double& phi1,
523 G4double& phi1m2,
524 G4double& psi1,
525 G4double& psi1m2,
526 const G4double gam,
527 const G4double eps)
528{
529 const G4double gam2 = gam*gam;
530 phi1 = 16.863-2.0*G4Log(1.0+0.311877*gam2)+2.4*G4Exp(-0.9*gam)
531 +1.6*G4Exp(-1.5*gam);
532 phi1m2 = 2.0/(3.0+19.5*gam+18.0*gam2); // phi1-phi2
533 const G4double eps2 = eps*eps;
534 psi1 = 24.34-2.0*G4Log(1.0+13.111641*eps2)+2.8*G4Exp(-8.0*eps)
535 +1.2*G4Exp(-29.2*eps);
536 psi1m2 = 2.0/(3.0+120.0*eps+1200.0*eps2); //psi1-psi2
537}
538
539void
540G4eBremsstrahlungRelModel::SampleSecondaries(std::vector<G4DynamicParticle*>* vdp,
541 const G4MaterialCutsCouple* couple,
542 const G4DynamicParticle* dp,
543 G4double cutEnergy,
544 G4double maxEnergy)
545{
546 const G4double kineticEnergy = dp->GetKineticEnergy();
547 if (kineticEnergy < LowEnergyLimit()) {
548 return;
549 }
550 // min, max kinetic energy limits
551 const G4double tmin = std::min(cutEnergy, kineticEnergy);
552 const G4double tmax = std::min(maxEnergy, kineticEnergy);
553 if (tmin >= tmax) {
554 return;
555 }
556 //
557 SetupForMaterial(fPrimaryParticle, couple->GetMaterial(), kineticEnergy);
558 const G4Element* elm = SelectTargetAtom(couple,fPrimaryParticle,kineticEnergy,
559 dp->GetLogKineticEnergy(),tmin,tmax);
560 //
561 fCurrentIZ = elm->GetZasInt();
562 const ElementData* elDat = gElementData[fCurrentIZ];
563 const G4double funcMax = elDat->fZFactor1+elDat->fZFactor2;
564 // get the random engine
565 G4double rndm[2];
566 CLHEP::HepRandomEngine* rndmEngine = G4Random::getTheEngine();
567 // 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)]
568 const G4double xmin = G4Log(tmin*tmin+fDensityCorr);
569 const G4double xrange = G4Log(tmax*tmax+fDensityCorr)-xmin;
570 G4double gammaEnergy, funcVal;
571 do {
572 rndmEngine->flatArray(2, rndm);
573 gammaEnergy = std::sqrt(std::max(G4Exp(xmin+rndm[0]*xrange)-fDensityCorr, 0.0));
574 funcVal = fIsLPMActive
575 ? ComputeRelDXSectionPerAtom(gammaEnergy)
576 : ComputeDXSectionPerAtom(gammaEnergy);
577 // cross-check of proper function maximum in the rejection
578// if (funcVal > funcMax) {
579// G4cout << "### G4eBremsstrahlungRelModel Warning: Majoranta exceeded! "
580// << funcVal << " > " << funcMax
581// << " Egamma(MeV)= " << gammaEnergy
582// << " Ee(MeV)= " << kineticEnergy
583// << " " << GetName()
584// << G4endl;
585// }
586 // Loop checking, 03-Aug-2015, Vladimir Ivanchenko
587 } while (funcVal < funcMax*rndm[1]);
588 //
589 // scattering off nucleus or off e- by triplet model
590 if (fIsScatOffElectron && rndmEngine->flat()*fSumTerm>fNucTerm) {
591 GetTripletModel()->SampleSecondaries(vdp, couple, dp, cutEnergy, maxEnergy);
592 return;
593 }
594 //
595 // angles of the emitted gamma. ( Z - axis along the parent particle)
596 // use general interface
597 G4ThreeVector gamDir =
599 fCurrentIZ, couple->GetMaterial());
600 // create G4DynamicParticle object for the Gamma
601 auto gamma = new G4DynamicParticle(fGammaParticle, gamDir, gammaEnergy);
602 vdp->push_back(gamma);
603 // compute post-interaction kinematics of primary e-/e+ based on
604 // energy-momentum conservation
605 const G4double totMomentum = std::sqrt(kineticEnergy*(
606 fPrimaryTotalEnergy + CLHEP::electron_mass_c2));
607 G4ThreeVector dir =
608 (totMomentum*dp->GetMomentumDirection()-gammaEnergy*gamDir).unit();
609 const G4double finalE = kineticEnergy-gammaEnergy;
610 // if secondary gamma energy is higher than threshold(very high by default)
611 // then stop tracking the primary particle and create new secondary e-/e+
612 // instead of the primary one
613 if (gammaEnergy > SecondaryThreshold()) {
614 fParticleChange->ProposeTrackStatus(fStopAndKill);
615 fParticleChange->SetProposedKineticEnergy(0.0);
616 auto el = new G4DynamicParticle(
617 const_cast<G4ParticleDefinition*>(fPrimaryParticle), dir, finalE);
618 vdp->push_back(el);
619 } else { // continue tracking the primary e-/e+ otherwise
620 fParticleChange->SetProposedMomentumDirection(dir);
621 fParticleChange->SetProposedKineticEnergy(finalE);
622 }
623}
624
625void G4eBremsstrahlungRelModel::InitialiseElementData()
626{
627 // create for all elements that are in the detector
628 auto elemTable = G4Element::GetElementTable();
629 for (auto const & elem : *elemTable) {
630 const G4double zet = elem->GetZ();
631 const G4int izet = std::min(elem->GetZasInt(), gMaxZet);
632 if (nullptr == gElementData[izet]) {
633 auto elemData = new ElementData();
634 const G4double fc = elem->GetfCoulomb();
635 G4double Fel = 1.;
636 G4double Finel = 1.;
637 elemData->fLogZ = G4Log(zet);
638 elemData->fFz = elemData->fLogZ/3.+fc;
639 if (izet < 5) {
640 Fel = gFelLowZet[izet];
641 Finel = gFinelLowZet[izet];
642 } else {
643 Fel = G4Log(184.15) - elemData->fLogZ/3.;
644 Finel = G4Log(1194) - 2.*elemData->fLogZ/3.;
645 }
646 const G4double z13 = G4Pow::GetInstance()->Z13(izet);
647 const G4double z23 = z13*z13;
648 elemData->fZFactor1 = (Fel-fc)+Finel/zet;
649 elemData->fZFactor11 = (Fel-fc); // used only for the triplet
650 elemData->fZFactor2 = (1.+1./zet)/12.;
651 elemData->fVarS1 = z23/(184.15*184.15);
652 elemData->fILVarS1Cond = 1./(G4Log(std::sqrt(2.0)*elemData->fVarS1));
653 elemData->fILVarS1 = 1./G4Log(elemData->fVarS1);
654 elemData->fGammaFactor = 100.0*electron_mass_c2/z13;
655 elemData->fEpsilonFactor = 100.0*electron_mass_c2/z23;
656 gElementData[izet] = elemData;
657 }
658 }
659}
660
661void G4eBremsstrahlungRelModel::ComputeLPMfunctions(G4double& funcXiS,
662 G4double& funcGS,
663 G4double& funcPhiS,
664 const G4double egamma)
665{
666 static const G4double sqrt2 = std::sqrt(2.);
667 const G4double redegamma = egamma/fPrimaryTotalEnergy;
668 const G4double varSprime = std::sqrt(0.125*redegamma*fLPMEnergy/
669 ((1.0-redegamma)*fPrimaryTotalEnergy));
670 const ElementData* elDat = gElementData[fCurrentIZ];
671 const G4double varS1 = elDat->fVarS1;
672 const G4double condition = sqrt2*varS1;
673 G4double funcXiSprime = 2.0;
674 if (varSprime > 1.0) {
675 funcXiSprime = 1.0;
676 } else if (varSprime > condition) {
677 const G4double ilVarS1Cond = elDat->fILVarS1Cond;
678 const G4double funcHSprime = G4Log(varSprime)*ilVarS1Cond;
679 funcXiSprime = 1.0 + funcHSprime - 0.08*(1.0-funcHSprime)*funcHSprime
680 *(2.0-funcHSprime)*ilVarS1Cond;
681 }
682 const G4double varS = varSprime/std::sqrt(funcXiSprime);
683 // - include dielectric suppression effect into s according to Migdal
684 const G4double varShat = varS*(1.0+fDensityCorr/(egamma*egamma));
685 funcXiS = 2.0;
686 if (varShat > 1.0) {
687 funcXiS = 1.0;
688 } else if (varShat > varS1) {
689 funcXiS = 1.0+G4Log(varShat)*elDat->fILVarS1;
690 }
691 G4LPMFunction::GetLPMFunctions(funcGS, funcPhiS, varShat);
692 //MAKE SURE SUPPRESSION IS SMALLER THAN 1: due to Migdal's approximation on xi
693 if (funcXiS*funcPhiS > 1. || varShat > 0.57) {
694 funcXiS=1./funcPhiS;
695 }
696}
G4TemplateAutoLock< G4Mutex > G4AutoLock
G4double epsilon(G4double density, G4double temperature)
std::vector< const G4Element * > G4ElementVector
G4double condition(const G4ErrorSymMatrix &m)
G4double G4Exp(G4double initial_x)
Exponential Function double precision.
Definition G4Exp.hh:132
G4double G4Log(G4double x)
Definition G4Log.hh:169
#define elem(i, j)
#define G4MUTEX_INITIALIZER
std::mutex G4Mutex
CLHEP::Hep3Vector G4ThreeVector
@ 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:91
static const G4ElementTable * GetElementTable()
Definition G4Element.cc:401
G4int GetZasInt() const
Definition G4Element.hh:120
static G4EmParameters * Instance()
G4bool LPM() const
static G4Gamma * Gamma()
Definition G4Gamma.cc:81
const G4Material * GetMaterial() const
const G4ElementVector * GetElementVector() const
const G4double * GetAtomicNumDensityVector() const
G4double GetElectronDensity() const
G4double GetRadlen() const
static G4Pow * GetInstance()
Definition G4Pow.cc:41
G4double Z13(G4int Z) const
Definition G4Pow.hh:123
virtual G4ThreeVector & SampleDirection(const G4DynamicParticle *dp, G4double finalTotalEnergy, G4int Z, const G4Material *)=0
void SetElementSelectors(std::vector< G4EmElementSelector * > *)
G4VEmAngularDistribution * GetAngularDistribution()
G4double LowEnergyLimit() const
std::vector< G4EmElementSelector * > * GetElementSelectors()
G4bool IsMaster() const
G4VEmModel * GetTripletModel()
void SetCurrentElement(const G4Element *)
void SetLowEnergyLimit(G4double)
G4VEmModel(const G4String &nam)
Definition G4VEmModel.cc:67
void SetAngularDistribution(G4VEmAngularDistribution *)
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)
void InitialiseElementSelectors(const G4ParticleDefinition *, const G4DataVector &)
virtual void Initialise(const G4ParticleDefinition *, const G4DataVector &)=0
G4double SecondaryThreshold() const
G4ParticleChangeForLoss * GetParticleChangeForLoss()
void SetParticle(const G4ParticleDefinition *p)
G4double ComputeCrossSectionPerAtom(const G4ParticleDefinition *, G4double ekin, G4double zet, G4double, G4double cutEnergy, G4double maxEnergy=DBL_MAX) override
virtual G4double ComputeDXSectionPerAtom(G4double gammaEnergy)
const G4ParticleDefinition * fPrimaryParticle
void InitialiseLocal(const G4ParticleDefinition *, G4VEmModel *masterModel) override
void SampleSecondaries(std::vector< G4DynamicParticle * > *, const G4MaterialCutsCouple *, const G4DynamicParticle *, G4double cutEnergy, G4double maxEnergy) override
G4double ComputeDEDXPerVolume(const G4Material *, const G4ParticleDefinition *, G4double ekin, G4double cutEnergy) override
G4eBremsstrahlungRelModel(const G4ParticleDefinition *p=nullptr, const G4String &nam="eBremLPM")
void SetupForMaterial(const G4ParticleDefinition *, const G4Material *, G4double) override
G4ParticleChangeForLoss * fParticleChange
G4double MinPrimaryEnergy(const G4Material *, const G4ParticleDefinition *, G4double cutEnergy) override
void Initialise(const G4ParticleDefinition *, const G4DataVector &) override
void GetLPMFunctions(G4double &lpmFuncG, G4double &lpmFuncPhi, G4double sVar)
int G4lrint(double ad)
Definition templates.hh:134