Geant4 Cross Reference |
1 // 1 // 2 // ******************************************* 2 // ******************************************************************** 3 // * License and Disclaimer 3 // * License and Disclaimer * 4 // * 4 // * * 5 // * The Geant4 software is copyright of th 5 // * The Geant4 software is copyright of the Copyright Holders of * 6 // * the Geant4 Collaboration. It is provided 6 // * the Geant4 Collaboration. It is provided under the terms and * 7 // * conditions of the Geant4 Software License 7 // * conditions of the Geant4 Software License, included in the file * 8 // * LICENSE and available at http://cern.ch/ 8 // * LICENSE and available at http://cern.ch/geant4/license . These * 9 // * include a list of copyright holders. 9 // * include a list of copyright holders. * 10 // * 10 // * * 11 // * Neither the authors of this software syst 11 // * Neither the authors of this software system, nor their employing * 12 // * institutes,nor the agencies providing fin 12 // * institutes,nor the agencies providing financial support for this * 13 // * work make any representation or warran 13 // * work make any representation or warranty, express or implied, * 14 // * regarding this software system or assum 14 // * regarding this software system or assume any liability for its * 15 // * use. Please see the license in the file 15 // * use. Please see the license in the file LICENSE and URL above * 16 // * for the full disclaimer and the limitatio 16 // * for the full disclaimer and the limitation of liability. * 17 // * 17 // * * 18 // * This code implementation is the result 18 // * This code implementation is the result of the scientific and * 19 // * technical work of the GEANT4 collaboratio 19 // * technical work of the GEANT4 collaboration. * 20 // * By using, copying, modifying or distri 20 // * By using, copying, modifying or distributing the software (or * 21 // * any work based on the software) you ag 21 // * any work based on the software) you agree to acknowledge its * 22 // * use in resulting scientific publicati 22 // * use in resulting scientific publications, and indicate your * 23 // * acceptance of all terms of the Geant4 Sof 23 // * acceptance of all terms of the Geant4 Software license. * 24 // ******************************************* 24 // ******************************************************************** 25 // 25 // 26 // 26 // 27 // ------------------------------------------- 27 // ------------------------------------------------------------------- 28 // 28 // 29 // GEANT4 Class file 29 // GEANT4 Class file 30 // 30 // 31 // 31 // 32 // File name: G4PairProductionRelModel 32 // File name: G4PairProductionRelModel 33 // 33 // 34 // Author: Andreas Schaelicke 34 // Author: Andreas Schaelicke 35 // 35 // 36 // Creation date: 02.04.2009 36 // Creation date: 02.04.2009 37 // 37 // 38 // Modifications: 38 // Modifications: 39 // 20.03.17 Change LPMconstant such that it gi 39 // 20.03.17 Change LPMconstant such that it gives suppression variable 's' 40 // that consistent to Migdal's one; f 40 // that consistent to Migdal's one; fix a small bug in 'logTS1' 41 // computation; suppression is consis 41 // computation; suppression is consistent now with the one in the 42 // brem. model (F.Hariri) 42 // brem. model (F.Hariri) 43 // 28-05-18 New version with improved screenin 43 // 28-05-18 New version with improved screening function approximation, improved 44 // LPM function approximation, effici 44 // LPM function approximation, efficiency, documentation and cleanup. 45 // Corrected call to selecting target 45 // Corrected call to selecting target atom in the final state sampling. 46 // (M. Novak) 46 // (M. Novak) 47 // 47 // 48 // Class Description: 48 // Class Description: 49 // 49 // 50 // Main References: 50 // Main References: 51 // J.W.Motz et.al., Rev. Mod. Phys. 41 (1969) 51 // J.W.Motz et.al., Rev. Mod. Phys. 41 (1969) 581. 52 // S.Klein, Rev. Mod. Phys. 71 (1999) 1501. 52 // S.Klein, Rev. Mod. Phys. 71 (1999) 1501. 53 // T.Stanev et.al., Phys. Rev. D25 (1982) 129 53 // T.Stanev et.al., Phys. Rev. D25 (1982) 1291. 54 // M.L.Ter-Mikaelian, High-energy Electromagn 54 // M.L.Ter-Mikaelian, High-energy Electromagnetic Processes in Condensed Media, 55 // Wiley, 1972. 55 // Wiley, 1972. 56 // 56 // 57 // ------------------------------------------- 57 // ------------------------------------------------------------------- 58 58 59 #include "G4PairProductionRelModel.hh" 59 #include "G4PairProductionRelModel.hh" 60 #include "G4PhysicalConstants.hh" 60 #include "G4PhysicalConstants.hh" 61 #include "G4SystemOfUnits.hh" 61 #include "G4SystemOfUnits.hh" 62 #include "G4Gamma.hh" 62 #include "G4Gamma.hh" 63 #include "G4Electron.hh" 63 #include "G4Electron.hh" 64 #include "G4Positron.hh" 64 #include "G4Positron.hh" 65 #include "G4ParticleChangeForGamma.hh" 65 #include "G4ParticleChangeForGamma.hh" 66 #include "G4LossTableManager.hh" 66 #include "G4LossTableManager.hh" 67 #include "G4ModifiedTsai.hh" 67 #include "G4ModifiedTsai.hh" 68 #include "G4Exp.hh" 68 #include "G4Exp.hh" 69 #include "G4Pow.hh" 69 #include "G4Pow.hh" 70 #include "G4AutoLock.hh" << 71 70 72 const G4int G4PairProductionRelModel::gMaxZet 71 const G4int G4PairProductionRelModel::gMaxZet = 120; 73 72 74 // LPM constant: \alpha(mc^2)^2/(4\pi*\hbar c) 73 // LPM constant: \alpha(mc^2)^2/(4\pi*\hbar c) 75 const G4double G4PairProductionRelModel::gLPMc 74 const G4double G4PairProductionRelModel::gLPMconstant = 76 CLHEP::fine_structure_const*CLHEP::electron_ 75 CLHEP::fine_structure_const*CLHEP::electron_mass_c2*CLHEP::electron_mass_c2 77 /(4.*CLHEP::pi*CLHEP::hbarc); 76 /(4.*CLHEP::pi*CLHEP::hbarc); 78 77 79 // abscissas and weights of an 8 point Gauss-L 78 // abscissas and weights of an 8 point Gauss-Legendre quadrature 80 // for numerical integration on [0,1] 79 // for numerical integration on [0,1] 81 const G4double G4PairProductionRelModel::gXGL[ 80 const G4double G4PairProductionRelModel::gXGL[] = { 82 1.98550718e-02, 1.01666761e-01, 2.37233795e- 81 1.98550718e-02, 1.01666761e-01, 2.37233795e-01, 4.08282679e-01, 83 5.91717321e-01, 7.62766205e-01, 8.98333239e- 82 5.91717321e-01, 7.62766205e-01, 8.98333239e-01, 9.80144928e-01 84 }; 83 }; 85 const G4double G4PairProductionRelModel::gWGL[ 84 const G4double G4PairProductionRelModel::gWGL[] = { 86 5.06142681e-02, 1.11190517e-01, 1.56853323e- 85 5.06142681e-02, 1.11190517e-01, 1.56853323e-01, 1.81341892e-01, 87 1.81341892e-01, 1.56853323e-01, 1.11190517e- 86 1.81341892e-01, 1.56853323e-01, 1.11190517e-01, 5.06142681e-02 88 }; 87 }; 89 88 90 // elastic and inelatic radiation logarithms f 89 // elastic and inelatic radiation logarithms for light elements (where the 91 // Thomas-Fermi model doesn't work): computed 90 // Thomas-Fermi model doesn't work): computed by using Dirac-Fock model of atom. 92 const G4double G4PairProductionRelModel::gFelL 91 const G4double G4PairProductionRelModel::gFelLowZet [] = { 93 0.0, 5.3104, 4.7935, 4.7402, 4.7112, 4.6694, 92 0.0, 5.3104, 4.7935, 4.7402, 4.7112, 4.6694, 4.6134, 4.5520 94 }; 93 }; 95 const G4double G4PairProductionRelModel::gFine 94 const G4double G4PairProductionRelModel::gFinelLowZet[] = { 96 0.0, 5.9173, 5.6125, 5.5377, 5.4728, 5.4174, 95 0.0, 5.9173, 5.6125, 5.5377, 5.4728, 5.4174, 5.3688, 5.3236 97 }; 96 }; 98 97 99 // constant cross section factor 98 // constant cross section factor 100 const G4double G4PairProductionRelModel::gXSec 99 const G4double G4PairProductionRelModel::gXSecFactor = 101 4.*CLHEP::fine_structure_const*CLHEP::classi 100 4.*CLHEP::fine_structure_const*CLHEP::classic_electr_radius 102 *CLHEP::classic_electr_radius; 101 *CLHEP::classic_electr_radius; 103 102 104 // gamma energy limit above which LPM suppress 103 // gamma energy limit above which LPM suppression will be applied (if the 105 // fIsUseLPMCorrection flag is true) 104 // fIsUseLPMCorrection flag is true) 106 const G4double G4PairProductionRelModel::gEgLP 105 const G4double G4PairProductionRelModel::gEgLPMActivation = 100.*CLHEP::GeV; 107 106 108 // special data structure per element i.e. per 107 // special data structure per element i.e. per Z 109 std::vector<G4PairProductionRelModel::ElementD 108 std::vector<G4PairProductionRelModel::ElementData*> G4PairProductionRelModel::gElementData; 110 109 111 // LPM supression functions evaluated at initi 110 // LPM supression functions evaluated at initialisation time 112 G4PairProductionRelModel::LPMFuncs G4PairProdu 111 G4PairProductionRelModel::LPMFuncs G4PairProductionRelModel::gLPMFuncs; 113 112 114 namespace << 115 { << 116 G4Mutex thePairProdRelMutex = G4MUTEX_INITIA << 117 } << 118 << 119 // CTR 113 // CTR 120 G4PairProductionRelModel::G4PairProductionRelM 114 G4PairProductionRelModel::G4PairProductionRelModel(const G4ParticleDefinition*, 121 115 const G4String& nam) 122 : G4VEmModel(nam), fIsUseLPMCorrection(true) 116 : G4VEmModel(nam), fIsUseLPMCorrection(true), fIsUseCompleteScreening(false), 123 fLPMEnergy(0.), fG4Calc(G4Pow::GetInstance() 117 fLPMEnergy(0.), fG4Calc(G4Pow::GetInstance()), fTheGamma(G4Gamma::Gamma()), 124 fTheElectron(G4Electron::Electron()), fThePo 118 fTheElectron(G4Electron::Electron()), fThePositron(G4Positron::Positron()), 125 fParticleChange(nullptr) 119 fParticleChange(nullptr) 126 { 120 { 127 // gamma energy below which the parametrized << 121 // gamma energy below which the parametrized atomic x-section is used (80 GeV) 128 fParametrizedXSectionThreshold = 30.0*CLHEP: 122 fParametrizedXSectionThreshold = 30.0*CLHEP::GeV; 129 // gamma energy below the Coulomb correction 123 // gamma energy below the Coulomb correction is turned off (50 MeV) 130 fCoulombCorrectionThreshold = 50.0*CLHEP: 124 fCoulombCorrectionThreshold = 50.0*CLHEP::MeV; 131 // set angular generator used in the final s 125 // set angular generator used in the final state kinematics computation 132 SetAngularDistribution(new G4ModifiedTsai()) 126 SetAngularDistribution(new G4ModifiedTsai()); 133 } 127 } 134 128 135 // DTR 129 // DTR 136 G4PairProductionRelModel::~G4PairProductionRel 130 G4PairProductionRelModel::~G4PairProductionRelModel() 137 { 131 { 138 if (isFirstInstance) { << 132 if (IsMaster()) { 139 // clear ElementData container 133 // clear ElementData container 140 for (auto const & ptr : gElementData) { de << 134 for (std::size_t iz = 0; iz < gElementData.size(); ++iz) { 141 gElementData.clear(); << 135 if (gElementData[iz]) delete gElementData[iz]; >> 136 } >> 137 gElementData.clear(); 142 // clear LPMFunctions (if any) 138 // clear LPMFunctions (if any) 143 if (fIsUseLPMCorrection) { 139 if (fIsUseLPMCorrection) { 144 gLPMFuncs.fLPMFuncG.clear(); 140 gLPMFuncs.fLPMFuncG.clear(); 145 gLPMFuncs.fLPMFuncPhi.clear(); 141 gLPMFuncs.fLPMFuncPhi.clear(); 146 gLPMFuncs.fIsInitialized = false; 142 gLPMFuncs.fIsInitialized = false; 147 } 143 } 148 } 144 } 149 } 145 } 150 146 151 void G4PairProductionRelModel::Initialise(cons 147 void G4PairProductionRelModel::Initialise(const G4ParticleDefinition* p, 152 cons 148 const G4DataVector& cuts) 153 { 149 { 154 if(nullptr == fParticleChange) { fParticleCh << 150 if (IsMaster()) { 155 << 156 if (isFirstInstance || gElementData.empty()) << 157 // init element data and LPM funcs 151 // init element data and LPM funcs 158 G4AutoLock l(&thePairProdRelMutex); << 152 if (IsMaster()) { 159 if (gElementData.empty()) { << 153 InitialiseElementData(); 160 isFirstInstance = true; << 154 if (fIsUseLPMCorrection) { 161 gElementData.resize(gMaxZet+1, nullptr); << 155 InitLPMFunctions(); 162 } << 156 } 163 // static data should be initialised only << 164 InitialiseElementData(); << 165 if (fIsUseLPMCorrection) { << 166 InitLPMFunctions(); << 167 } 157 } 168 l.unlock(); << 169 } 158 } 170 // element selectors should be initialised i << 159 if(!fParticleChange) { fParticleChange = GetParticleChangeForGamma(); } 171 if (IsMaster()) { << 160 if(IsMaster() && LowEnergyLimit() < HighEnergyLimit()) { 172 InitialiseElementSelectors(p, cuts); 161 InitialiseElementSelectors(p, cuts); 173 } 162 } 174 } 163 } 175 164 176 void G4PairProductionRelModel::InitialiseLocal 165 void G4PairProductionRelModel::InitialiseLocal(const G4ParticleDefinition*, 177 166 G4VEmModel* masterModel) 178 { 167 { 179 SetElementSelectors(masterModel->GetElementS << 168 if(LowEnergyLimit() < HighEnergyLimit()) { >> 169 SetElementSelectors(masterModel->GetElementSelectors()); >> 170 } 180 } 171 } 181 172 182 G4double G4PairProductionRelModel::ComputeXSec 173 G4double G4PairProductionRelModel::ComputeXSectionPerAtom(G4double gammaEnergy, 183 174 G4double Z) 184 { 175 { 185 G4double xSection = 0.0; 176 G4double xSection = 0.0; 186 // check if LPM suppression needs to be used 177 // check if LPM suppression needs to be used 187 const G4bool isLPM = (fIsUseLPMCorrection 178 const G4bool isLPM = (fIsUseLPMCorrection && gammaEnergy>gEgLPMActivation); 188 // determine the kinematical limits (taken i 179 // determine the kinematical limits (taken into account the correction due to 189 // the way in which the Coulomb correction i 180 // the way in which the Coulomb correction is applied i.e. avoid negative DCS) 190 const G4int iz = std::min(gMaxZet, G4 181 const G4int iz = std::min(gMaxZet, G4lrint(Z)); 191 const G4double eps0 = CLHEP::electron_mass 182 const G4double eps0 = CLHEP::electron_mass_c2/gammaEnergy; 192 // Coulomb correction is always included in 183 // Coulomb correction is always included in the DCS even below 50 MeV (note: 193 // that this DCS is only used to get the int 184 // that this DCS is only used to get the integrated x-section) 194 const G4double dmax = gElementData[iz]->fD 185 const G4double dmax = gElementData[iz]->fDeltaMaxHigh; 195 const G4double dmin = 4.*eps0*gElementData 186 const G4double dmin = 4.*eps0*gElementData[iz]->fDeltaFactor; 196 const G4double eps1 = 0.5 - 0.5*std::sqrt( 187 const G4double eps1 = 0.5 - 0.5*std::sqrt(1.-dmin/dmax); 197 const G4double epsMin = std::max(eps0, eps1) 188 const G4double epsMin = std::max(eps0, eps1); 198 const G4double epsMax = 0.5; // DCS is symme 189 const G4double epsMax = 0.5; // DCS is symmetric around eps=0.5 199 // let Et be the total energy transferred to 190 // let Et be the total energy transferred to the e- or to the e+ 200 // the [Et-min, Et-max] interval will be div 191 // the [Et-min, Et-max] interval will be divided into i=1,2,..,n subintervals 201 // with width of dInterv = (Et-max - Et-min) 192 // with width of dInterv = (Et-max - Et-min)/n and numerical integration will 202 // be done in each sub-inteval using the xi 193 // be done in each sub-inteval using the xi = (Et - Et_i-min)/dInterv variable 203 // that is in [0,1]. The 8-point GL q. is us 194 // that is in [0,1]. The 8-point GL q. is used for the integration on [0,1]. 204 const G4int numSub = 2; 195 const G4int numSub = 2; 205 const G4double dInterv= (epsMax - epsMin)*ga 196 const G4double dInterv= (epsMax - epsMin)*gammaEnergy/G4double(numSub); 206 G4double minEti = epsMin*gammaEnergy; 197 G4double minEti = epsMin*gammaEnergy; // Et-min i.e. Et_0-min 207 for (G4int i = 0; i < numSub; ++i) { 198 for (G4int i = 0; i < numSub; ++i) { 208 for (G4int ngl = 0; ngl < 8; ++ngl) { 199 for (G4int ngl = 0; ngl < 8; ++ngl) { 209 const G4double Et = (minEti + gXGL[ngl]* 200 const G4double Et = (minEti + gXGL[ngl]*dInterv); 210 const G4double xs = isLPM ? ComputeRelDX 201 const G4double xs = isLPM ? ComputeRelDXSectionPerAtom(Et, gammaEnergy, Z) 211 : ComputeDXSec 202 : ComputeDXSectionPerAtom(Et, gammaEnergy, Z); 212 xSection += gWGL[ngl]*xs; 203 xSection += gWGL[ngl]*xs; 213 } 204 } 214 // update minimum Et of the sub-inteval 205 // update minimum Et of the sub-inteval 215 minEti += dInterv; 206 minEti += dInterv; 216 } 207 } 217 // apply corrections of variable transformat 208 // apply corrections of variable transformation and half interval integration 218 xSection = std::max(2.*xSection*dInterv, 0.) 209 xSection = std::max(2.*xSection*dInterv, 0.); 219 return xSection; 210 return xSection; 220 } 211 } 221 212 222 // DCS WITHOUT LPM SUPPRESSION 213 // DCS WITHOUT LPM SUPPRESSION 223 // Computes DCS value for a given target eleme 214 // Computes DCS value for a given target element (Z), initial gamma energy (Eg), 224 // total energy transferred to one of the e-/e 215 // total energy transferred to one of the e-/e+ pair(Et) WITHOUT LPM suppression 225 // The constant factor 4 \alpha r_0^2 Z (Z +\e 216 // The constant factor 4 \alpha r_0^2 Z (Z +\eta(Z)) is not included here and 226 // the returned value will be differential in 217 // the returned value will be differential in total energy transfer instead of 227 // the eps=Et/Eg. The computed part of the DCS 218 // the eps=Et/Eg. The computed part of the DCS 228 // NORMAL CASE: DEFAULT STTING (i.e. fIsUseCom 219 // NORMAL CASE: DEFAULT STTING (i.e. fIsUseCompleteScreening = FALSE) 229 // ds/deps(Et,Eg,Z) = ds/deps(eps,Z) = (eps^2+ 220 // ds/deps(Et,Eg,Z) = ds/deps(eps,Z) = (eps^2+(1-eps)^2)*[phi1(d)/4-ln(Z)/3-fc] 230 // + 2*eps(1-eps)*[phi2(d)/4-ln(Z)/3-fc]/3 whe 221 // + 2*eps(1-eps)*[phi2(d)/4-ln(Z)/3-fc]/3 where the universal (in the TF model) 231 // screening variable d=d(eps)=136Z^(-1/3)eps0 222 // screening variable d=d(eps)=136Z^(-1/3)eps0/[eps*(1-eps)] with eps0=mc^2/Eg. 232 // COMPLETE SCREENING (when d(eps) approx-equa 223 // COMPLETE SCREENING (when d(eps) approx-equal-to 0) : NEED TO BE SET BY USER 233 // ds/deps(Et,Eg,Z) = ds/deps(eps,Z) = (eps^2+ 224 // ds/deps(Et,Eg,Z) = ds/deps(eps,Z) = (eps^2+(1-eps)^2+eps*(1-eps)/3)*[Lel-fc] 234 // -eps(1-eps)/9 where Lel=phi1(0)/4-ln(Z)/3 i 225 // -eps(1-eps)/9 where Lel=phi1(0)/4-ln(Z)/3 is the elastic(coherent) radiation 235 // logarithm, fc is the Coulomb correction and 226 // logarithm, fc is the Coulomb correction and the relation phi2(0)/4-ln(Z)/3 = 236 // phi1(0)/4-1/6-ln(Z)/3 = Lel-1/6 (due to phi 227 // phi1(0)/4-1/6-ln(Z)/3 = Lel-1/6 (due to phi2(0)=phi1(0)-2/3) was used. 237 G4double G4PairProductionRelModel::ComputeDXSe 228 G4double G4PairProductionRelModel::ComputeDXSectionPerAtom(G4double pEnergy, 238 229 G4double gammaEnergy, 239 230 G4double Z) 240 { 231 { 241 G4double xSection = 0.; 232 G4double xSection = 0.; 242 const G4int iz = std::min(gMaxZet, G4lr 233 const G4int iz = std::min(gMaxZet, G4lrint(Z)); 243 const G4double eps = pEnergy/gammaEnergy; 234 const G4double eps = pEnergy/gammaEnergy; 244 const G4double epsm = 1.-eps; 235 const G4double epsm = 1.-eps; 245 const G4double dum = eps*epsm; 236 const G4double dum = eps*epsm; 246 if (fIsUseCompleteScreening) { 237 if (fIsUseCompleteScreening) { 247 // complete screening: 238 // complete screening: 248 const G4double Lel = gElementData[iz]->f 239 const G4double Lel = gElementData[iz]->fLradEl; 249 const G4double fc = gElementData[iz]->f 240 const G4double fc = gElementData[iz]->fCoulomb; 250 xSection = (eps*eps + epsm*epsm + 2.*dum/3 241 xSection = (eps*eps + epsm*epsm + 2.*dum/3.)*(Lel-fc) - dum/9.; 251 } else { 242 } else { 252 // normal case: 243 // normal case: 253 const G4double eps0 = CLHEP::electron_mas 244 const G4double eps0 = CLHEP::electron_mass_c2/gammaEnergy; 254 const G4double fc = gElementData[iz]->f 245 const G4double fc = gElementData[iz]->fCoulomb; 255 const G4double lnZ13 = gElementData[iz]->f 246 const G4double lnZ13 = gElementData[iz]->fLogZ13; 256 const G4double delta = gElementData[iz]->f 247 const G4double delta = gElementData[iz]->fDeltaFactor*eps0/dum; 257 G4double phi1, phi2; 248 G4double phi1, phi2; 258 ComputePhi12(delta, phi1, phi2); 249 ComputePhi12(delta, phi1, phi2); 259 xSection = (eps*eps + epsm*epsm)*(0.25*ph 250 xSection = (eps*eps + epsm*epsm)*(0.25*phi1-lnZ13-fc) 260 + 2.*dum*(0.25*phi2-lnZ13-fc)/3 251 + 2.*dum*(0.25*phi2-lnZ13-fc)/3.; 261 } 252 } 262 // non-const. part of the DCS differential i 253 // non-const. part of the DCS differential in total energy transfer not in eps 263 // ds/dEt=ds/deps deps/dEt with deps/dEt=1/E 254 // ds/dEt=ds/deps deps/dEt with deps/dEt=1/Eg 264 return std::max(xSection, 0.0)/gammaEnergy; 255 return std::max(xSection, 0.0)/gammaEnergy; 265 } 256 } 266 257 267 // DCS WITH POSSIBLE LPM SUPPRESSION 258 // DCS WITH POSSIBLE LPM SUPPRESSION 268 // Computes DCS value for a given target eleme 259 // Computes DCS value for a given target element (Z), initial gamma energy (Eg), 269 // total energy transferred to one of the e-/e 260 // total energy transferred to one of the e-/e+ pair(Et) WITH LPM suppression. 270 // For a given Z, the LPM suppression will dep 261 // For a given Z, the LPM suppression will depend on the material through the 271 // LMP-Energy. This will determine the suppres 262 // LMP-Energy. This will determine the suppression variable s and the LPM sup- 272 // pression functions xi(s), fi(s) and G(s). 263 // pression functions xi(s), fi(s) and G(s). 273 // The constant factor 4 \alpha r_0^2 Z (Z +\e 264 // The constant factor 4 \alpha r_0^2 Z (Z +\eta(Z)) is not included here and 274 // the returned value will be differential in 265 // the returned value will be differential in total energy transfer instead of 275 // the eps=Et/Eg. The computed part of the DCS 266 // the eps=Et/Eg. The computed part of the DCS 276 // NORMAL CASE: DEFAULT STTING (i.e. fIsUseCom 267 // NORMAL CASE: DEFAULT STTING (i.e. fIsUseCompleteScreening = FALSE) 277 // ds/deps(Et,Eg,Z)=ds/deps(eps,Z) = xi(s)*{ ( 268 // ds/deps(Et,Eg,Z)=ds/deps(eps,Z) = xi(s)*{ (eps^2+(1-eps)^2)*[2fi(s)/3+G(s)/3] 278 // *[phi1(d)/4-ln(Z)/3-fc] + 2*eps(1-eps)*G(s) 269 // *[phi1(d)/4-ln(Z)/3-fc] + 2*eps(1-eps)*G(s)*[phi2(d)/4-ln(Z)/3-fc]/3 } where 279 // the universal (in the TF model) screening v 270 // the universal (in the TF model) screening variable d=d(eps)=136Z^(-1/3)eps0 280 // /[eps*(1-eps)] with eps0=mc^2/Eg. 271 // /[eps*(1-eps)] with eps0=mc^2/Eg. 281 // COMPLETE SCREENING (when d(eps) approx-equa 272 // COMPLETE SCREENING (when d(eps) approx-equal-to 0) : NEED TO BE SET BY USER 282 // ds/deps(Et,Eg,Z) = ds/deps(eps,Z) = xi(s)*{ 273 // ds/deps(Et,Eg,Z) = ds/deps(eps,Z) = xi(s)*{ [Lel-fc]*[ (eps^2+(1-eps)^2+eps 283 // *(1-eps)/3)*2fi(s)/3 + G(s)/3] - eps(1-eps) 274 // *(1-eps)/3)*2fi(s)/3 + G(s)/3] - eps(1-eps)*G(s)/9 } 284 // Note, that when the LPM suppression is abse 275 // Note, that when the LPM suppression is absent i.e. xi(s)=fi(s)=G(s)=1, both 285 // the normal and the complete screening DCS g 276 // the normal and the complete screening DCS give back the NO-LMP case above. 286 G4double G4PairProductionRelModel::ComputeRelD 277 G4double G4PairProductionRelModel::ComputeRelDXSectionPerAtom(G4double pEnergy, 287 278 G4double gammaEnergy, 288 279 G4double Z) 289 { 280 { 290 G4double xSection = 0.; 281 G4double xSection = 0.; 291 const G4int iz = std::min(gMaxZet, G4lr 282 const G4int iz = std::min(gMaxZet, G4lrint(Z)); 292 const G4double eps = pEnergy/gammaEnergy; 283 const G4double eps = pEnergy/gammaEnergy; 293 const G4double epsm = 1.-eps; 284 const G4double epsm = 1.-eps; 294 const G4double dum = eps*epsm; 285 const G4double dum = eps*epsm; 295 // evaluate LPM suppression functions 286 // evaluate LPM suppression functions 296 G4double fXiS, fGS, fPhiS; 287 G4double fXiS, fGS, fPhiS; 297 ComputeLPMfunctions(fXiS, fGS, fPhiS, eps, g 288 ComputeLPMfunctions(fXiS, fGS, fPhiS, eps, gammaEnergy, iz); 298 if (fIsUseCompleteScreening) { 289 if (fIsUseCompleteScreening) { 299 // complete screening: 290 // complete screening: 300 const G4double Lel = gElementData[iz]->f 291 const G4double Lel = gElementData[iz]->fLradEl; 301 const G4double fc = gElementData[iz]->f 292 const G4double fc = gElementData[iz]->fCoulomb; 302 xSection = (Lel-fc)*((eps*eps+epsm*epsm)*2 293 xSection = (Lel-fc)*((eps*eps+epsm*epsm)*2.*fPhiS + fGS)/3. - dum*fGS/9.; 303 } else { 294 } else { 304 // normal case: 295 // normal case: 305 const G4double eps0 = CLHEP::electron_mas 296 const G4double eps0 = CLHEP::electron_mass_c2/gammaEnergy; 306 const G4double fc = gElementData[iz]->f 297 const G4double fc = gElementData[iz]->fCoulomb; 307 const G4double lnZ13 = gElementData[iz]->f 298 const G4double lnZ13 = gElementData[iz]->fLogZ13; 308 const G4double delta = gElementData[iz]->f 299 const G4double delta = gElementData[iz]->fDeltaFactor*eps0/dum; 309 G4double phi1, phi2; 300 G4double phi1, phi2; 310 ComputePhi12(delta, phi1, phi2); 301 ComputePhi12(delta, phi1, phi2); 311 xSection = (eps*eps + epsm*epsm)*(2.*fPhi 302 xSection = (eps*eps + epsm*epsm)*(2.*fPhiS+fGS)*(0.25*phi1-lnZ13-fc)/3. 312 + 2.*dum*fGS*(0.25*phi2-lnZ13-f 303 + 2.*dum*fGS*(0.25*phi2-lnZ13-fc)/3.; 313 } 304 } 314 // non-const. part of the DCS differential i 305 // non-const. part of the DCS differential in total energy transfer not in eps 315 // ds/dEt=ds/deps deps/dEt with deps/dEt=1/E 306 // ds/dEt=ds/deps deps/dEt with deps/dEt=1/Eg 316 return std::max(fXiS*xSection, 0.0)/gammaEne 307 return std::max(fXiS*xSection, 0.0)/gammaEnergy; 317 } 308 } 318 309 319 G4double 310 G4double 320 G4PairProductionRelModel::ComputeCrossSectionP 311 G4PairProductionRelModel::ComputeCrossSectionPerAtom(const G4ParticleDefinition*, 321 G4double gammaEnergy, G4double Z, G4doub 312 G4double gammaEnergy, G4double Z, G4double, G4double, G4double) 322 { 313 { 323 G4double crossSection = 0.0 ; 314 G4double crossSection = 0.0 ; 324 // check kinematical limit 315 // check kinematical limit 325 if ( gammaEnergy <= 2.0*electron_mass_c2 ) { 316 if ( gammaEnergy <= 2.0*electron_mass_c2 ) { return crossSection; } 326 // compute the atomic cross section either b 317 // compute the atomic cross section either by using x-section parametrization 327 // or by numerically integrationg the DCS (w 318 // or by numerically integrationg the DCS (with or without LPM) 328 if ( gammaEnergy < fParametrizedXSectionThre 319 if ( gammaEnergy < fParametrizedXSectionThreshold) { 329 // using the parametrized cross sections ( 320 // using the parametrized cross sections (max up to 80 GeV) 330 crossSection = ComputeParametrizedXSection 321 crossSection = ComputeParametrizedXSectionPerAtom(gammaEnergy, Z); 331 } else { 322 } else { 332 // by numerical integration of the DCS: 323 // by numerical integration of the DCS: 333 // Computes the cross section with or with 324 // Computes the cross section with or without LPM suppression depending on 334 // settings (by default with if the gamma 325 // settings (by default with if the gamma energy is above a given threshold) 335 // and using or not using complete sreenin 326 // and using or not using complete sreening approximation (by default not). 336 // Only the dependent part is computed in 327 // Only the dependent part is computed in the numerical integration of the DCS 337 // i.e. the result must be multiplied here 328 // i.e. the result must be multiplied here with 4 \alpha r_0^2 Z(Z+\eta(Z)) 338 crossSection = ComputeXSectionPerAtom(gamm 329 crossSection = ComputeXSectionPerAtom(gammaEnergy, Z); 339 // apply the constant factors: 330 // apply the constant factors: 340 // - eta(Z) is a correction to account int 331 // - eta(Z) is a correction to account interaction in the field of e- 341 // - gXSecFactor = 4 \alpha r_0^2 332 // - gXSecFactor = 4 \alpha r_0^2 342 const G4int iz = std::min(gMaxZet, G4l 333 const G4int iz = std::min(gMaxZet, G4lrint(Z)); 343 const G4double eta = gElementData[iz]->fEt 334 const G4double eta = gElementData[iz]->fEtaValue; 344 crossSection *= gXSecFactor*Z*(Z+eta) 335 crossSection *= gXSecFactor*Z*(Z+eta); 345 } 336 } 346 // final protection 337 // final protection 347 return std::max(crossSection, 0.); 338 return std::max(crossSection, 0.); 348 } 339 } 349 340 350 void G4PairProductionRelModel::SetupForMateria 341 void G4PairProductionRelModel::SetupForMaterial(const G4ParticleDefinition*, 351 342 const G4Material* mat, G4double) 352 { 343 { 353 fLPMEnergy = mat->GetRadlen()*gLPMconstant; 344 fLPMEnergy = mat->GetRadlen()*gLPMconstant; 354 } 345 } 355 346 356 void 347 void 357 G4PairProductionRelModel::SampleSecondaries(st 348 G4PairProductionRelModel::SampleSecondaries(std::vector<G4DynamicParticle*>* fvect, 358 co 349 const G4MaterialCutsCouple* couple, 359 co 350 const G4DynamicParticle* aDynamicGamma, 360 G4 351 G4double, 361 G4 352 G4double) 362 // The secondaries e+e- energies are sampled u 353 // The secondaries e+e- energies are sampled using the Bethe - Heitler 363 // cross sections with Coulomb correction. 354 // cross sections with Coulomb correction. 364 // A modified version of the random number tec 355 // A modified version of the random number techniques of Butcher & Messel 365 // is used (Nuc Phys 20(1960),15). 356 // is used (Nuc Phys 20(1960),15). 366 // 357 // 367 // GEANT4 internal units. 358 // GEANT4 internal units. 368 // 359 // 369 // Note 1 : Effects due to the breakdown of th 360 // Note 1 : Effects due to the breakdown of the Born approximation at 370 // low energy are ignored. 361 // low energy are ignored. 371 // Note 2 : The differential cross section imp 362 // Note 2 : The differential cross section implicitly takes account of 372 // pair creation in both nuclear and 363 // pair creation in both nuclear and atomic electron fields. 373 // However triplet prodution is not g 364 // However triplet prodution is not generated. 374 { 365 { 375 const G4Material* mat = couple->GetM 366 const G4Material* mat = couple->GetMaterial(); 376 const G4double gammaEnergy = aDynamicGamm 367 const G4double gammaEnergy = aDynamicGamma->GetKineticEnergy(); 377 const G4double eps0 = CLHEP::elect 368 const G4double eps0 = CLHEP::electron_mass_c2/gammaEnergy ; 378 // 369 // 379 // check kinematical limit: gamma energy(Eg) 370 // check kinematical limit: gamma energy(Eg) must be at least 2 e- rest mass 380 // (but the model should be used at higher e 371 // (but the model should be used at higher energies above 100 MeV) 381 if (eps0 > 0.5) { return; } 372 if (eps0 > 0.5) { return; } 382 // 373 // 383 // select target atom of the material 374 // select target atom of the material 384 const G4Element* anElement = SelectTargetAto 375 const G4Element* anElement = SelectTargetAtom(couple, fTheGamma, gammaEnergy, 385 aDyna 376 aDynamicGamma->GetLogKineticEnergy()); 386 CLHEP::HepRandomEngine* rndmEngine = G4Rando 377 CLHEP::HepRandomEngine* rndmEngine = G4Random::getTheEngine(); 387 // 378 // 388 // 'eps' is the total energy transferred to 379 // 'eps' is the total energy transferred to one of the e-/e+ pair in initial 389 // gamma energy units Eg. Since the correspo 380 // gamma energy units Eg. Since the corresponding DCS is symmetric on eps=0.5, 390 // the kinematical limits for eps0=mc^2/Eg < 381 // the kinematical limits for eps0=mc^2/Eg <= eps <= 0.5 391 // 1. 'eps' is sampled uniformly on the [eps 382 // 1. 'eps' is sampled uniformly on the [eps0, 0.5] inteval if Eg<Egsmall 392 // 2. otherwise, on the [eps_min, 0.5] inter 383 // 2. otherwise, on the [eps_min, 0.5] interval according to the DCS (case 2.) 393 G4double eps; 384 G4double eps; 394 // case 1. 385 // case 1. 395 static const G4double Egsmall = 2.*CLHEP::Me 386 static const G4double Egsmall = 2.*CLHEP::MeV; 396 if (gammaEnergy < Egsmall) { 387 if (gammaEnergy < Egsmall) { 397 eps = eps0 + (0.5-eps0)*rndmEngine->flat() 388 eps = eps0 + (0.5-eps0)*rndmEngine->flat(); 398 } else { 389 } else { 399 // case 2. 390 // case 2. 400 // get the Coulomb factor for the target e 391 // get the Coulomb factor for the target element (Z) and gamma energy (Eg) 401 // F(Z) = 8*ln(Z)/3 if Eg <= 50 392 // F(Z) = 8*ln(Z)/3 if Eg <= 50 [MeV] => no Coulomb correction 402 // F(Z) = 8*ln(Z)/3 + 8*fc(Z) if Eg > 50 393 // F(Z) = 8*ln(Z)/3 + 8*fc(Z) if Eg > 50 [MeV] => fc(Z) is the Coulomb cor. 403 // 394 // 404 // The screening variable 'delta(eps)' = 1 395 // The screening variable 'delta(eps)' = 136*Z^{-1/3}*eps0/[eps(1-eps)] 405 // Due to the Coulomb correction, the DCS 396 // Due to the Coulomb correction, the DCS can go below zero even at 406 // kinematicaly allowed eps > eps0 values. 397 // kinematicaly allowed eps > eps0 values. In order to exclude this eps 407 // range with negative DCS, the minimum ep 398 // range with negative DCS, the minimum eps value will be set to eps_min = 408 // max[eps0, epsp] with epsp is the soluti 399 // max[eps0, epsp] with epsp is the solution of SF(delta(epsp)) - F(Z)/2 = 0 409 // with SF being the screening function (S 400 // with SF being the screening function (SF1=SF2 at high value of delta). 410 // The solution is epsp = 0.5 - 0.5*sqrt[ 401 // The solution is epsp = 0.5 - 0.5*sqrt[ 1 - 4*136*Z^{-1/3}eps0/deltap] 411 // with deltap = Exp[(42.038-F(Z))/8.29]-0 402 // with deltap = Exp[(42.038-F(Z))/8.29]-0.958. So the limits are: 412 // - when eps=eps_max = 0.5 => 403 // - when eps=eps_max = 0.5 => delta_min = 136*Z^{-1/3}*eps0/4 413 // - epsp = 0.5 - 0.5*sqrt[ 1 - delta_min/ 404 // - epsp = 0.5 - 0.5*sqrt[ 1 - delta_min/deltap] 414 // - and eps_min = max[eps0, epsp] 405 // - and eps_min = max[eps0, epsp] 415 const G4int iZet = std::min(gMax 406 const G4int iZet = std::min(gMaxZet, anElement->GetZasInt()); 416 const G4double deltaFactor = gElementData[ 407 const G4double deltaFactor = gElementData[iZet]->fDeltaFactor*eps0; 417 const G4double deltaMin = 4.*deltaFacto 408 const G4double deltaMin = 4.*deltaFactor; 418 G4double deltaMax = gElementData[ 409 G4double deltaMax = gElementData[iZet]->fDeltaMaxLow; 419 G4double FZ = 8.*gElementDa 410 G4double FZ = 8.*gElementData[iZet]->fLogZ13; 420 if ( gammaEnergy > fCoulombCorrectionThres 411 if ( gammaEnergy > fCoulombCorrectionThreshold ) { // Eg > 50 MeV ? 421 FZ += 8.*gElementData[iZet]->fCoulo 412 FZ += 8.*gElementData[iZet]->fCoulomb; 422 deltaMax = gElementData[iZet]->fDeltaMax 413 deltaMax = gElementData[iZet]->fDeltaMaxHigh; 423 } 414 } 424 // compute the limits of eps 415 // compute the limits of eps 425 const G4double epsp = 0.5 - 0.5*std 416 const G4double epsp = 0.5 - 0.5*std::sqrt(1. - deltaMin/deltaMax) ; 426 const G4double epsMin = std::max(eps0 417 const G4double epsMin = std::max(eps0,epsp); 427 const G4double epsRange = 0.5 - epsMin; 418 const G4double epsRange = 0.5 - epsMin; 428 // 419 // 429 // sample the energy rate (eps) of the cre 420 // sample the energy rate (eps) of the created electron (or positron) 430 G4double F10, F20; 421 G4double F10, F20; 431 ScreenFunction12(deltaMin, F10, F20); 422 ScreenFunction12(deltaMin, F10, F20); 432 F10 -= FZ; 423 F10 -= FZ; 433 F20 -= FZ; 424 F20 -= FZ; 434 const G4double NormF1 = std::max(F10 * e 425 const G4double NormF1 = std::max(F10 * epsRange * epsRange, 0.); 435 const G4double NormF2 = std::max(1.5 * F 426 const G4double NormF2 = std::max(1.5 * F20 , 0.); 436 const G4double NormCond = NormF1/(NormF1 + 427 const G4double NormCond = NormF1/(NormF1 + NormF2); 437 // check if LPM correction is active 428 // check if LPM correction is active 438 const G4bool isLPM = (fIsUseLPMCorrection 429 const G4bool isLPM = (fIsUseLPMCorrection && gammaEnergy>gEgLPMActivation); 439 fLPMEnergy = mat->GetRadlen()*gLPMconstant 430 fLPMEnergy = mat->GetRadlen()*gLPMconstant; 440 // we will need 3 uniform random number fo 431 // we will need 3 uniform random number for each trial of sampling 441 G4double rndmv[3]; 432 G4double rndmv[3]; 442 G4double greject = 0.; 433 G4double greject = 0.; 443 do { 434 do { 444 rndmEngine->flatArray(3, rndmv); 435 rndmEngine->flatArray(3, rndmv); 445 if (NormCond > rndmv[0]) { 436 if (NormCond > rndmv[0]) { 446 eps = 0.5 - epsRange * fG4Calc->A13(rn 437 eps = 0.5 - epsRange * fG4Calc->A13(rndmv[1]); 447 const G4double delta = deltaFactor/(ep 438 const G4double delta = deltaFactor/(eps*(1.-eps)); 448 if (isLPM) { 439 if (isLPM) { 449 G4double lpmXiS, lpmGS, lpmPhiS, phi 440 G4double lpmXiS, lpmGS, lpmPhiS, phi1, phi2; 450 ComputePhi12(delta, phi1, phi2); 441 ComputePhi12(delta, phi1, phi2); 451 ComputeLPMfunctions(lpmXiS, lpmGS, l 442 ComputeLPMfunctions(lpmXiS, lpmGS, lpmPhiS, eps, gammaEnergy, iZet); 452 greject = lpmXiS*((2.*lpmPhiS+lpmGS) 443 greject = lpmXiS*((2.*lpmPhiS+lpmGS)*phi1-lpmGS*phi2-lpmPhiS*FZ)/F10; 453 } else { 444 } else { 454 greject = (ScreenFunction1(delta)-FZ 445 greject = (ScreenFunction1(delta)-FZ)/F10; 455 } 446 } 456 } else { 447 } else { 457 eps = epsMin + epsRange*rndmv[1]; 448 eps = epsMin + epsRange*rndmv[1]; 458 const G4double delta = deltaFactor/(ep 449 const G4double delta = deltaFactor/(eps*(1.-eps)); 459 if (isLPM) { 450 if (isLPM) { 460 G4double lpmXiS, lpmGS, lpmPhiS, phi 451 G4double lpmXiS, lpmGS, lpmPhiS, phi1, phi2; 461 ComputePhi12(delta, phi1, phi2); 452 ComputePhi12(delta, phi1, phi2); 462 ComputeLPMfunctions(lpmXiS, lpmGS, l 453 ComputeLPMfunctions(lpmXiS, lpmGS, lpmPhiS, eps, gammaEnergy, iZet); 463 greject = lpmXiS*( (lpmPhiS+0.5*lpmG 454 greject = lpmXiS*( (lpmPhiS+0.5*lpmGS)*phi1 + 0.5*lpmGS*phi2 464 -0.5*(lpmGS+lpmPh 455 -0.5*(lpmGS+lpmPhiS)*FZ )/F20; 465 } else { 456 } else { 466 greject = (ScreenFunction2(delta)-FZ 457 greject = (ScreenFunction2(delta)-FZ)/F20; 467 } 458 } 468 } 459 } 469 // Loop checking, 03-Aug-2015, Vladimir 460 // Loop checking, 03-Aug-2015, Vladimir Ivanchenko 470 } while (greject < rndmv[2]); 461 } while (greject < rndmv[2]); 471 // end of eps sampling 462 // end of eps sampling 472 } 463 } 473 // 464 // 474 // select charges randomly 465 // select charges randomly 475 G4double eTotEnergy, pTotEnergy; 466 G4double eTotEnergy, pTotEnergy; 476 if (rndmEngine->flat() > 0.5) { 467 if (rndmEngine->flat() > 0.5) { 477 eTotEnergy = (1.-eps)*gammaEnergy; 468 eTotEnergy = (1.-eps)*gammaEnergy; 478 pTotEnergy = eps*gammaEnergy; 469 pTotEnergy = eps*gammaEnergy; 479 } else { 470 } else { 480 pTotEnergy = (1.-eps)*gammaEnergy; 471 pTotEnergy = (1.-eps)*gammaEnergy; 481 eTotEnergy = eps*gammaEnergy; 472 eTotEnergy = eps*gammaEnergy; 482 } 473 } 483 // 474 // 484 // sample pair kinematics 475 // sample pair kinematics 485 // 476 // 486 const G4double eKinEnergy = std::max(0.,eTot 477 const G4double eKinEnergy = std::max(0.,eTotEnergy - CLHEP::electron_mass_c2); 487 const G4double pKinEnergy = std::max(0.,pTot 478 const G4double pKinEnergy = std::max(0.,pTotEnergy - CLHEP::electron_mass_c2); 488 // 479 // 489 G4ThreeVector eDirection, pDirection; 480 G4ThreeVector eDirection, pDirection; 490 // 481 // 491 GetAngularDistribution()->SamplePairDirectio 482 GetAngularDistribution()->SamplePairDirections(aDynamicGamma, 492 eKinEnergy, pKinEnergy, eDirectio 483 eKinEnergy, pKinEnergy, eDirection, pDirection); 493 // create G4DynamicParticle object for the p 484 // create G4DynamicParticle object for the particle1 494 auto aParticle1 = new G4DynamicParticle(fThe 485 auto aParticle1 = new G4DynamicParticle(fTheElectron,eDirection,eKinEnergy); 495 486 496 // create G4DynamicParticle object for the p 487 // create G4DynamicParticle object for the particle2 497 auto aParticle2 = new G4DynamicParticle(fThe 488 auto aParticle2 = new G4DynamicParticle(fThePositron,pDirection,pKinEnergy); 498 // Fill output vector 489 // Fill output vector 499 fvect->push_back(aParticle1); 490 fvect->push_back(aParticle1); 500 fvect->push_back(aParticle2); 491 fvect->push_back(aParticle2); 501 // kill incident photon 492 // kill incident photon 502 fParticleChange->SetProposedKineticEnergy(0. 493 fParticleChange->SetProposedKineticEnergy(0.); 503 fParticleChange->ProposeTrackStatus(fStopAnd 494 fParticleChange->ProposeTrackStatus(fStopAndKill); 504 } 495 } 505 496 506 // should be called only by the master and at 497 // should be called only by the master and at initialisation 507 void G4PairProductionRelModel::InitialiseEleme 498 void G4PairProductionRelModel::InitialiseElementData() 508 { 499 { >> 500 G4int size = (G4int)gElementData.size(); >> 501 if (size < gMaxZet+1) { >> 502 gElementData.resize(gMaxZet+1, nullptr); >> 503 } 509 // create for all elements that are in the d 504 // create for all elements that are in the detector 510 auto elemTable = G4Element::GetElementTable( << 505 const G4ElementTable* elemTable = G4Element::GetElementTable(); 511 for (auto const & elem : *elemTable) { << 506 std::size_t numElems = (*elemTable).size(); 512 const G4int iz = std::min(gMaxZet, elem->G << 507 for (std::size_t ie = 0; ie < numElems; ++ie) { 513 if (nullptr == gElementData[iz]) { // crea << 508 const G4Element* elem = (*elemTable)[ie]; >> 509 const G4int iz = std::min(gMaxZet, elem->GetZasInt()); >> 510 if (!gElementData[iz]) { // create it if doesn't exist yet 514 const G4double logZ13 = elem->GetIonisat 511 const G4double logZ13 = elem->GetIonisation()->GetlogZ3(); 515 const G4double Z13 = elem->GetIonisat 512 const G4double Z13 = elem->GetIonisation()->GetZ3(); 516 const G4double fc = elem->GetfCoulom 513 const G4double fc = elem->GetfCoulomb(); 517 const G4double FZLow = 8.*logZ13; 514 const G4double FZLow = 8.*logZ13; 518 const G4double FZHigh = 8.*(logZ13 + fc) 515 const G4double FZHigh = 8.*(logZ13 + fc); 519 G4double Fel; 516 G4double Fel; 520 G4double Finel; 517 G4double Finel; 521 if (iz<5) { // use data from Dirac-Fock 518 if (iz<5) { // use data from Dirac-Fock atomic model 522 Fel = gFelLowZet[iz]; 519 Fel = gFelLowZet[iz]; 523 Finel = gFinelLowZet[iz]; 520 Finel = gFinelLowZet[iz]; 524 } else { // use the results of the T 521 } else { // use the results of the Thomas-Fermi-Moliere model 525 Fel = G4Log(184.) - logZ13; 522 Fel = G4Log(184.) - logZ13; 526 Finel = G4Log(1194.) - 2.*logZ13; 523 Finel = G4Log(1194.) - 2.*logZ13; 527 } 524 } 528 auto elD = new ElementData() 525 auto elD = new ElementData(); 529 elD->fLogZ13 = logZ13; 526 elD->fLogZ13 = logZ13; 530 elD->fCoulomb = fc; 527 elD->fCoulomb = fc; 531 elD->fLradEl = Fel; 528 elD->fLradEl = Fel; 532 elD->fDeltaFactor = 136./Z13; 529 elD->fDeltaFactor = 136./Z13; 533 elD->fDeltaMaxLow = G4Exp((42.038 - F 530 elD->fDeltaMaxLow = G4Exp((42.038 - FZLow)/8.29) - 0.958; 534 elD->fDeltaMaxHigh = G4Exp((42.038 - F 531 elD->fDeltaMaxHigh = G4Exp((42.038 - FZHigh)/8.29) - 0.958; 535 elD->fEtaValue = Finel/(Fel-fc); 532 elD->fEtaValue = Finel/(Fel-fc); 536 elD->fLPMVarS1Cond = std::sqrt(2.)*Z13 533 elD->fLPMVarS1Cond = std::sqrt(2.)*Z13*Z13/(184.*184.); 537 elD->fLPMILVarS1Cond = 1./G4Log(elD->fLP 534 elD->fLPMILVarS1Cond = 1./G4Log(elD->fLPMVarS1Cond); 538 gElementData[iz] = elD; 535 gElementData[iz] = elD; 539 } 536 } 540 } 537 } 541 } 538 } 542 539 543 // s goes up to 2 with ds = 0.01 be default 540 // s goes up to 2 with ds = 0.01 be default 544 void G4PairProductionRelModel::InitLPMFunction 541 void G4PairProductionRelModel::InitLPMFunctions() { 545 if (!gLPMFuncs.fIsInitialized) { 542 if (!gLPMFuncs.fIsInitialized) { 546 const G4int num = gLPMFuncs.fSLimit*gLPMFu 543 const G4int num = gLPMFuncs.fSLimit*gLPMFuncs.fISDelta+1; 547 gLPMFuncs.fLPMFuncG.resize(num); 544 gLPMFuncs.fLPMFuncG.resize(num); 548 gLPMFuncs.fLPMFuncPhi.resize(num); 545 gLPMFuncs.fLPMFuncPhi.resize(num); 549 for (G4int i=0; i<num; ++i) { 546 for (G4int i=0; i<num; ++i) { 550 const G4double sval = i/gLPMFuncs.fISDel 547 const G4double sval = i/gLPMFuncs.fISDelta; 551 ComputeLPMGsPhis(gLPMFuncs.fLPMFuncG[i], 548 ComputeLPMGsPhis(gLPMFuncs.fLPMFuncG[i],gLPMFuncs.fLPMFuncPhi[i],sval); 552 } 549 } 553 gLPMFuncs.fIsInitialized = true; 550 gLPMFuncs.fIsInitialized = true; 554 } 551 } 555 } 552 } 556 553 557 // used only at initialisation time 554 // used only at initialisation time 558 void G4PairProductionRelModel::ComputeLPMGsPhi 555 void G4PairProductionRelModel::ComputeLPMGsPhis(G4double &funcGS, G4double &funcPhiS, const G4double varShat) { 559 if (varShat < 0.01) { 556 if (varShat < 0.01) { 560 funcPhiS = 6.0*varShat*(1.0-CLHEP::pi*varS 557 funcPhiS = 6.0*varShat*(1.0-CLHEP::pi*varShat); 561 funcGS = 12.0*varShat-2.0*funcPhiS; 558 funcGS = 12.0*varShat-2.0*funcPhiS; 562 } else { 559 } else { 563 const G4double varShat2 = varShat*varShat; 560 const G4double varShat2 = varShat*varShat; 564 const G4double varShat3 = varShat*varShat2 561 const G4double varShat3 = varShat*varShat2; 565 const G4double varShat4 = varShat2*varShat 562 const G4double varShat4 = varShat2*varShat2; 566 if (varShat < 0.415827397755) { // Stanev 563 if (varShat < 0.415827397755) { // Stanev ap.: for \psi(s) and compute G(s) 567 funcPhiS = 1.0-G4Exp( -6.0*varShat*(1.0+ 564 funcPhiS = 1.0-G4Exp( -6.0*varShat*(1.0+varShat*(3.0-CLHEP::pi)) 568 + varShat3/(0.623+0 565 + varShat3/(0.623+0.796*varShat+0.658*varShat2)); 569 // 1-\exp \left\{-4s-\frac{8s^2}{1+3.936 566 // 1-\exp \left\{-4s-\frac{8s^2}{1+3.936s+4.97s^2-0.05s^3+7.5s^4} \right\} 570 const G4double funcPsiS = 1.0-G4Exp( -4. 567 const G4double funcPsiS = 1.0-G4Exp( -4.0*varShat - 8.0*varShat2/(1.0 571 + 3.936*varShat+4.97*varS 568 + 3.936*varShat+4.97*varShat2-0.05*varShat3+7.5*varShat4)); 572 // G(s) = 3 \psi(s) - 2 \phi(s) 569 // G(s) = 3 \psi(s) - 2 \phi(s) 573 funcGS = 3.0*funcPsiS - 2.0*funcPhiS; 570 funcGS = 3.0*funcPsiS - 2.0*funcPhiS; 574 } else if (varShat < 1.55) { 571 } else if (varShat < 1.55) { 575 funcPhiS = 1.0-G4Exp( -6.0*varShat*(1.0+ 572 funcPhiS = 1.0-G4Exp( -6.0*varShat*(1.0+varShat*(3.0-CLHEP::pi)) 576 + varShat3/(0.623+0 573 + varShat3/(0.623+0.796*varShat+0.658*varShat2)); 577 const G4double dum0 = -0.16072300849123 574 const G4double dum0 = -0.16072300849123999+3.7550300067531581*varShat 578 -1.79813830690100 575 -1.7981383069010097 *varShat2 579 +0.67282686077812 576 +0.67282686077812381*varShat3 580 -0.12077229098792 577 -0.1207722909879257 *varShat4; 581 funcGS = std::tanh(dum0); 578 funcGS = std::tanh(dum0); 582 } else { 579 } else { 583 funcPhiS = 1.0-0.01190476/varShat4; 580 funcPhiS = 1.0-0.01190476/varShat4; 584 if (varShat < 1.9156) { 581 if (varShat < 1.9156) { 585 const G4double dum0 = -0.1607230084912 582 const G4double dum0 = -0.16072300849123999+3.7550300067531581*varShat 586 -1.7981383069010 583 -1.7981383069010097 *varShat2 587 +0.6728268607781 584 +0.67282686077812381*varShat3 588 -0.1207722909879 585 -0.1207722909879257 *varShat4; 589 funcGS = std::tanh(dum0); 586 funcGS = std::tanh(dum0); 590 } else { 587 } else { 591 funcGS = 1.0-0.0230655/varShat4; 588 funcGS = 1.0-0.0230655/varShat4; 592 } 589 } 593 } 590 } 594 } 591 } 595 } 592 } 596 593 597 // used at run-time to get some pre-computed L 594 // used at run-time to get some pre-computed LPM function values 598 void G4PairProductionRelModel::GetLPMFunctions 595 void G4PairProductionRelModel::GetLPMFunctions(G4double &lpmGs, 599 596 G4double &lpmPhis, 600 597 const G4double sval) { 601 if (sval < gLPMFuncs.fSLimit) { 598 if (sval < gLPMFuncs.fSLimit) { 602 G4double val = sval*gLPMFuncs.fISDelta 599 G4double val = sval*gLPMFuncs.fISDelta; 603 const G4int ilow = (G4int)val; 600 const G4int ilow = (G4int)val; 604 val -= ilow; 601 val -= ilow; 605 lpmGs = (gLPMFuncs.fLPMFuncG[ilow+1]-gL 602 lpmGs = (gLPMFuncs.fLPMFuncG[ilow+1]-gLPMFuncs.fLPMFuncG[ilow])*val 606 + gLPMFuncs.fLPMFuncG[ilow]; 603 + gLPMFuncs.fLPMFuncG[ilow]; 607 lpmPhis = (gLPMFuncs.fLPMFuncPhi[ilow+1]- 604 lpmPhis = (gLPMFuncs.fLPMFuncPhi[ilow+1]-gLPMFuncs.fLPMFuncPhi[ilow])*val 608 + gLPMFuncs.fLPMFuncPhi[ilow]; 605 + gLPMFuncs.fLPMFuncPhi[ilow]; 609 } else { 606 } else { 610 G4double ss = sval*sval; 607 G4double ss = sval*sval; 611 ss *= ss; 608 ss *= ss; 612 lpmPhis = 1.0-0.01190476/ss; 609 lpmPhis = 1.0-0.01190476/ss; 613 lpmGs = 1.0-0.0230655/ss; 610 lpmGs = 1.0-0.0230655/ss; 614 } 611 } 615 } 612 } 616 613 617 void G4PairProductionRelModel::ComputeLPMfunct 614 void G4PairProductionRelModel::ComputeLPMfunctions(G4double &funcXiS, 618 G4double &funcGS, G4double &f 615 G4double &funcGS, G4double &funcPhiS, const G4double eps, 619 const G4double egamma, const 616 const G4double egamma, const G4int izet) 620 { 617 { 621 // 1. y = E_+/E_{\gamma} with E_+ being the 618 // 1. y = E_+/E_{\gamma} with E_+ being the total energy transfered 622 // to one of the e-/e 619 // to one of the e-/e+ pair 623 // s' = \sqrt{ \frac{1}{8} \frac{1}{y(1-y)} 620 // s' = \sqrt{ \frac{1}{8} \frac{1}{y(1-y)} \frac{E^{KL}_{LPM}}{E_{\gamma}} } 624 const G4double varSprime = std::sqrt(0.125*f 621 const G4double varSprime = std::sqrt(0.125*fLPMEnergy/(eps*egamma*(1.0-eps))); 625 const G4double condition = gElementData[izet 622 const G4double condition = gElementData[izet]->fLPMVarS1Cond; 626 funcXiS = 2.0; 623 funcXiS = 2.0; 627 if (varSprime > 1.0) { 624 if (varSprime > 1.0) { 628 funcXiS = 1.0; 625 funcXiS = 1.0; 629 } else if (varSprime > condition) { 626 } else if (varSprime > condition) { 630 const G4double dum = gElementData[izet]->f 627 const G4double dum = gElementData[izet]->fLPMILVarS1Cond; 631 const G4double funcHSprime = G4Log(varSpri 628 const G4double funcHSprime = G4Log(varSprime)*dum; 632 funcXiS = 1.0 + funcHSprime 629 funcXiS = 1.0 + funcHSprime 633 - 0.08*(1.0-funcHSprime)*funcHSpr 630 - 0.08*(1.0-funcHSprime)*funcHSprime*(2.0-funcHSprime)*dum; 634 } 631 } 635 // 2. s=\frac{s'}{\sqrt{\xi(s')}} 632 // 2. s=\frac{s'}{\sqrt{\xi(s')}} 636 const G4double varShat = varSprime / std::sq 633 const G4double varShat = varSprime / std::sqrt(funcXiS); 637 GetLPMFunctions(funcGS, funcPhiS, varShat); 634 GetLPMFunctions(funcGS, funcPhiS, varShat); 638 // MAKE SURE SUPPRESSION IS SMALLER THAN 1: 635 // MAKE SURE SUPPRESSION IS SMALLER THAN 1: due to Migdal's approximation on xi 639 if (funcXiS * funcPhiS > 1. || varShat > 0.5 636 if (funcXiS * funcPhiS > 1. || varShat > 0.57) { 640 funcXiS = 1. / funcPhiS; 637 funcXiS = 1. / funcPhiS; 641 } 638 } 642 } 639 } 643 640 644 // Calculates the microscopic cross section in 641 // Calculates the microscopic cross section in GEANT4 internal units. Same as in 645 // G4BetheHeitlerModel and should be used belo 642 // G4BetheHeitlerModel and should be used below 80 GeV since it start to deverge 646 // from the cross section data above 80-90 GeV 643 // from the cross section data above 80-90 GeV: 647 // Parametrized formula (L. Urban) is used to 644 // Parametrized formula (L. Urban) is used to estimate the atomic cross sections 648 // given numerically in the table of [Hubbell, 645 // given numerically in the table of [Hubbell, J. H., Heinz Albert Gimm, and I. 649 // Overbo: "Pair, Triplet, and Total Atomic Cr 646 // Overbo: "Pair, Triplet, and Total Atomic Cross Sections (and Mass Attenuation 650 // Coefficients) for 1 MeV‐100 GeV Photons i 647 // Coefficients) for 1 MeV‐100 GeV Photons in Elements Z= 1 to 100." Journal of 651 // physical and chemical reference data 9.4 (1 648 // physical and chemical reference data 9.4 (1980): 1023-1148.] 652 // 649 // 653 // The formula gives a good approximation of t 650 // The formula gives a good approximation of the data from 1.5 MeV to 100 GeV. 654 // below 1.5 MeV: sigma=sigma(1.5MeV)*(GammaEn 651 // below 1.5 MeV: sigma=sigma(1.5MeV)*(GammaEnergy-2electronmass) 655 // *(GammaEn 652 // *(GammaEnergy-2electronmass) 656 G4double 653 G4double 657 G4PairProductionRelModel::ComputeParametrizedX 654 G4PairProductionRelModel::ComputeParametrizedXSectionPerAtom(G4double gammaE, 658 655 G4double Z) 659 { 656 { 660 G4double xSection = 0.0 ; 657 G4double xSection = 0.0 ; 661 // short versions 658 // short versions 662 static const G4double kMC2 = CLHEP::electro 659 static const G4double kMC2 = CLHEP::electron_mass_c2; 663 // zero cross section below the kinematical 660 // zero cross section below the kinematical limit: Eg<2mc^2 664 if (Z < 0.9 || gammaE <= 2.0*kMC2) { return 661 if (Z < 0.9 || gammaE <= 2.0*kMC2) { return xSection; } 665 // 662 // 666 static const G4double gammaEnergyLimit = 1.5 663 static const G4double gammaEnergyLimit = 1.5*CLHEP::MeV; 667 // set coefficients a, b c 664 // set coefficients a, b c 668 static const G4double a0 = 8.7842e+2*CLHEP: 665 static const G4double a0 = 8.7842e+2*CLHEP::microbarn; 669 static const G4double a1 = -1.9625e+3*CLHEP: 666 static const G4double a1 = -1.9625e+3*CLHEP::microbarn; 670 static const G4double a2 = 1.2949e+3*CLHEP: 667 static const G4double a2 = 1.2949e+3*CLHEP::microbarn; 671 static const G4double a3 = -2.0028e+2*CLHEP: 668 static const G4double a3 = -2.0028e+2*CLHEP::microbarn; 672 static const G4double a4 = 1.2575e+1*CLHEP: 669 static const G4double a4 = 1.2575e+1*CLHEP::microbarn; 673 static const G4double a5 = -2.8333e-1*CLHEP: 670 static const G4double a5 = -2.8333e-1*CLHEP::microbarn; 674 671 675 static const G4double b0 = -1.0342e+1*CLHEP: 672 static const G4double b0 = -1.0342e+1*CLHEP::microbarn; 676 static const G4double b1 = 1.7692e+1*CLHEP: 673 static const G4double b1 = 1.7692e+1*CLHEP::microbarn; 677 static const G4double b2 = -8.2381 *CLHEP: 674 static const G4double b2 = -8.2381 *CLHEP::microbarn; 678 static const G4double b3 = 1.3063 *CLHEP: 675 static const G4double b3 = 1.3063 *CLHEP::microbarn; 679 static const G4double b4 = -9.0815e-2*CLHEP: 676 static const G4double b4 = -9.0815e-2*CLHEP::microbarn; 680 static const G4double b5 = 2.3586e-3*CLHEP: 677 static const G4double b5 = 2.3586e-3*CLHEP::microbarn; 681 678 682 static const G4double c0 = -4.5263e+2*CLHEP: 679 static const G4double c0 = -4.5263e+2*CLHEP::microbarn; 683 static const G4double c1 = 1.1161e+3*CLHEP: 680 static const G4double c1 = 1.1161e+3*CLHEP::microbarn; 684 static const G4double c2 = -8.6749e+2*CLHEP: 681 static const G4double c2 = -8.6749e+2*CLHEP::microbarn; 685 static const G4double c3 = 2.1773e+2*CLHEP: 682 static const G4double c3 = 2.1773e+2*CLHEP::microbarn; 686 static const G4double c4 = -2.0467e+1*CLHEP: 683 static const G4double c4 = -2.0467e+1*CLHEP::microbarn; 687 static const G4double c5 = 6.5372e-1*CLHEP: 684 static const G4double c5 = 6.5372e-1*CLHEP::microbarn; 688 // check low energy limit of the approximati 685 // check low energy limit of the approximation (1.5 MeV) 689 G4double gammaEnergyOrg = gammaE; 686 G4double gammaEnergyOrg = gammaE; 690 if (gammaE < gammaEnergyLimit) { gammaE = ga 687 if (gammaE < gammaEnergyLimit) { gammaE = gammaEnergyLimit; } 691 // compute gamma energy variables 688 // compute gamma energy variables 692 const G4double x = G4Log(gammaE/kMC2); 689 const G4double x = G4Log(gammaE/kMC2); 693 const G4double x2 = x *x; 690 const G4double x2 = x *x; 694 const G4double x3 = x2*x; 691 const G4double x3 = x2*x; 695 const G4double x4 = x3*x; 692 const G4double x4 = x3*x; 696 const G4double x5 = x4*x; 693 const G4double x5 = x4*x; 697 // 694 // 698 const G4double F1 = a0 + a1*x + a2*x2 + a3*x 695 const G4double F1 = a0 + a1*x + a2*x2 + a3*x3 + a4*x4 + a5*x5; 699 const G4double F2 = b0 + b1*x + b2*x2 + b3*x 696 const G4double F2 = b0 + b1*x + b2*x2 + b3*x3 + b4*x4 + b5*x5; 700 const G4double F3 = c0 + c1*x + c2*x2 + c3*x 697 const G4double F3 = c0 + c1*x + c2*x2 + c3*x3 + c4*x4 + c5*x5; 701 // compute the approximated cross section 698 // compute the approximated cross section 702 xSection = (Z + 1.)*(F1*Z + F2*Z*Z + F3); 699 xSection = (Z + 1.)*(F1*Z + F2*Z*Z + F3); 703 // check if we are below the limit of the ap 700 // check if we are below the limit of the approximation and apply correction 704 if (gammaEnergyOrg < gammaEnergyLimit) { 701 if (gammaEnergyOrg < gammaEnergyLimit) { 705 const G4double dum = (gammaEnergyOrg-2.*kM 702 const G4double dum = (gammaEnergyOrg-2.*kMC2)/(gammaEnergyLimit-2.*kMC2); 706 xSection *= dum*dum; 703 xSection *= dum*dum; 707 } 704 } 708 return xSection; 705 return xSection; 709 } 706 } 710 707 711 708 712 709