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