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 // $Id: G4PairProductionRelModel.cc,v 1.3 2009/05/15 17:12:33 vnivanch Exp $ >> 27 // GEANT4 tag $Name: geant4-09-03-patch-02 $ 26 // 28 // 27 // ------------------------------------------- 29 // ------------------------------------------------------------------- 28 // 30 // 29 // GEANT4 Class file 31 // GEANT4 Class file 30 // 32 // 31 // 33 // 32 // File name: G4PairProductionRelModel 34 // File name: G4PairProductionRelModel 33 // 35 // 34 // Author: Andreas Schaelicke 36 // Author: Andreas Schaelicke 35 // 37 // 36 // Creation date: 02.04.2009 38 // Creation date: 02.04.2009 37 // 39 // 38 // Modifications: 40 // Modifications: 39 // 20.03.17 Change LPMconstant such that it gi << 40 // that consistent to Migdal's one; f << 41 // computation; suppression is consis << 42 // brem. model (F.Hariri) << 43 // 28-05-18 New version with improved screenin << 44 // LPM function approximation, effici << 45 // Corrected call to selecting target << 46 // (M. Novak) << 47 // 41 // 48 // Class Description: 42 // Class Description: 49 // 43 // 50 // Main References: 44 // Main References: 51 // J.W.Motz et.al., Rev. Mod. Phys. 41 (1969) 45 // J.W.Motz et.al., Rev. Mod. Phys. 41 (1969) 581. 52 // S.Klein, Rev. Mod. Phys. 71 (1999) 1501. 46 // S.Klein, Rev. Mod. Phys. 71 (1999) 1501. 53 // T.Stanev et.al., Phys. Rev. D25 (1982) 129 47 // T.Stanev et.al., Phys. Rev. D25 (1982) 1291. 54 // M.L.Ter-Mikaelian, High-energy Electromagn << 48 // M.L.Ter-Mikaelian, High-energy Electromagnetic Processes in Condensed Media, Wiley, 1972. 55 // Wiley, 1972. << 56 // 49 // 57 // ------------------------------------------- 50 // ------------------------------------------------------------------- >> 51 // >> 52 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... >> 53 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... 58 54 59 #include "G4PairProductionRelModel.hh" 55 #include "G4PairProductionRelModel.hh" 60 #include "G4PhysicalConstants.hh" << 61 #include "G4SystemOfUnits.hh" << 62 #include "G4Gamma.hh" 56 #include "G4Gamma.hh" 63 #include "G4Electron.hh" 57 #include "G4Electron.hh" 64 #include "G4Positron.hh" 58 #include "G4Positron.hh" >> 59 65 #include "G4ParticleChangeForGamma.hh" 60 #include "G4ParticleChangeForGamma.hh" 66 #include "G4LossTableManager.hh" 61 #include "G4LossTableManager.hh" 67 #include "G4ModifiedTsai.hh" << 68 #include "G4Exp.hh" << 69 #include "G4Pow.hh" << 70 #include "G4AutoLock.hh" << 71 << 72 const G4int G4PairProductionRelModel::gMaxZet << 73 << 74 // LPM constant: \alpha(mc^2)^2/(4\pi*\hbar c) << 75 const G4double G4PairProductionRelModel::gLPMc << 76 CLHEP::fine_structure_const*CLHEP::electron_ << 77 /(4.*CLHEP::pi*CLHEP::hbarc); << 78 << 79 // abscissas and weights of an 8 point Gauss-L << 80 // for numerical integration on [0,1] << 81 const G4double G4PairProductionRelModel::gXGL[ << 82 1.98550718e-02, 1.01666761e-01, 2.37233795e- << 83 5.91717321e-01, 7.62766205e-01, 8.98333239e- << 84 }; << 85 const G4double G4PairProductionRelModel::gWGL[ << 86 5.06142681e-02, 1.11190517e-01, 1.56853323e- << 87 1.81341892e-01, 1.56853323e-01, 1.11190517e- << 88 }; << 89 << 90 // elastic and inelatic radiation logarithms f << 91 // Thomas-Fermi model doesn't work): computed << 92 const G4double G4PairProductionRelModel::gFelL << 93 0.0, 5.3104, 4.7935, 4.7402, 4.7112, 4.6694, << 94 }; << 95 const G4double G4PairProductionRelModel::gFine << 96 0.0, 5.9173, 5.6125, 5.5377, 5.4728, 5.4174, << 97 }; << 98 << 99 // constant cross section factor << 100 const G4double G4PairProductionRelModel::gXSec << 101 4.*CLHEP::fine_structure_const*CLHEP::classi << 102 *CLHEP::classic_electr_radius; << 103 << 104 // gamma energy limit above which LPM suppress << 105 // fIsUseLPMCorrection flag is true) << 106 const G4double G4PairProductionRelModel::gEgLP << 107 << 108 // special data structure per element i.e. per << 109 std::vector<G4PairProductionRelModel::ElementD << 110 << 111 // LPM supression functions evaluated at initi << 112 G4PairProductionRelModel::LPMFuncs G4PairProdu << 113 62 114 namespace << 115 { << 116 G4Mutex thePairProdRelMutex = G4MUTEX_INITIA << 117 } << 118 63 119 // CTR << 64 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... >> 65 >> 66 using namespace std; >> 67 >> 68 >> 69 const G4double G4PairProductionRelModel::facFel = log(184.15); >> 70 const G4double G4PairProductionRelModel::facFinel = log(1194.); // 1440. >> 71 >> 72 const G4double G4PairProductionRelModel::preS1 = 1./(184.15*184.15); >> 73 const G4double G4PairProductionRelModel::logTwo = log(2.); >> 74 >> 75 const G4double G4PairProductionRelModel::xgi[]={ 0.0199, 0.1017, 0.2372, 0.4083, >> 76 0.5917, 0.7628, 0.8983, 0.9801 }; >> 77 const G4double G4PairProductionRelModel::wgi[]={ 0.0506, 0.1112, 0.1569, 0.1813, >> 78 0.1813, 0.1569, 0.1112, 0.0506 }; >> 79 const G4double G4PairProductionRelModel::Fel_light[] = {0., 5.31 , 4.79 , 4.74 , 4.71} ; >> 80 const G4double G4PairProductionRelModel::Finel_light[] = {0., 6.144 , 5.621 , 5.805 , 5.924} ; >> 81 >> 82 >> 83 120 G4PairProductionRelModel::G4PairProductionRelM 84 G4PairProductionRelModel::G4PairProductionRelModel(const G4ParticleDefinition*, 121 << 85 const G4String& nam) 122 : G4VEmModel(nam), fIsUseLPMCorrection(true) << 86 : G4VEmModel(nam), 123 fLPMEnergy(0.), fG4Calc(G4Pow::GetInstance() << 87 theCrossSectionTable(0), 124 fTheElectron(G4Electron::Electron()), fThePo << 88 nbins(10), 125 fParticleChange(nullptr) << 89 fLPMconstant(fine_structure_const*electron_mass_c2*electron_mass_c2/(4.*pi*hbarc)*0.5), 126 { << 90 fLPMflag(true), 127 // gamma energy below which the parametrized << 91 lpmEnergy(0.), 128 fParametrizedXSectionThreshold = 30.0*CLHEP: << 92 use_completescreening(false) 129 // gamma energy below the Coulomb correction << 93 { 130 fCoulombCorrectionThreshold = 50.0*CLHEP: << 94 fParticleChange = 0; 131 // set angular generator used in the final s << 95 theGamma = G4Gamma::Gamma(); 132 SetAngularDistribution(new G4ModifiedTsai()) << 96 thePositron = G4Positron::Positron(); >> 97 theElectron = G4Electron::Electron(); >> 98 >> 99 nist = G4NistManager::Instance(); >> 100 133 } 101 } 134 102 135 // DTR << 103 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... >> 104 136 G4PairProductionRelModel::~G4PairProductionRel 105 G4PairProductionRelModel::~G4PairProductionRelModel() 137 { 106 { 138 if (isFirstInstance) { << 107 if(theCrossSectionTable) { 139 // clear ElementData container << 108 theCrossSectionTable->clearAndDestroy(); 140 for (auto const & ptr : gElementData) { de << 109 delete theCrossSectionTable; 141 gElementData.clear(); << 110 } 142 // clear LPMFunctions (if any) << 111 } 143 if (fIsUseLPMCorrection) { << 112 144 gLPMFuncs.fLPMFuncG.clear(); << 113 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... 145 gLPMFuncs.fLPMFuncPhi.clear(); << 114 146 gLPMFuncs.fIsInitialized = false; << 115 void G4PairProductionRelModel::Initialise(const G4ParticleDefinition*, >> 116 const G4DataVector&) >> 117 { >> 118 fParticleChange = GetParticleChangeForGamma(); >> 119 >> 120 if(theCrossSectionTable) { >> 121 theCrossSectionTable->clearAndDestroy(); >> 122 delete theCrossSectionTable; >> 123 } >> 124 >> 125 const G4ElementTable* theElementTable = G4Element::GetElementTable(); >> 126 size_t nvect = G4Element::GetNumberOfElements(); >> 127 theCrossSectionTable = new G4PhysicsTable(nvect); >> 128 G4PhysicsLogVector* ptrVector; >> 129 G4double emin = LowEnergyLimit(); >> 130 G4double emax = HighEnergyLimit(); >> 131 G4int n = nbins*G4int(log10(emax/emin)); >> 132 G4bool spline = G4LossTableManager::Instance()->SplineFlag(); >> 133 G4double e, value; >> 134 >> 135 for(size_t j=0; j<nvect ; j++) { >> 136 >> 137 ptrVector = new G4PhysicsLogVector(emin, emax, n); >> 138 ptrVector->SetSpline(spline); >> 139 G4double Z = (*theElementTable)[j]->GetZ(); >> 140 G4VEmModel::SetCurrentElement((*theElementTable)[j]); >> 141 G4int iz = G4int(Z); >> 142 indexZ[iz] = j; >> 143 >> 144 for(G4int i=0; i<nbins; i++) { >> 145 e = ptrVector->GetLowEdgeEnergy( i ) ; >> 146 value = ComputeCrossSectionPerAtom(theGamma, e, Z); >> 147 ptrVector->PutValue( i, value ); 147 } 148 } >> 149 >> 150 theCrossSectionTable->insert(ptrVector); 148 } 151 } 149 } 152 } 150 153 151 void G4PairProductionRelModel::Initialise(cons << 154 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... 152 cons << 155 /* >> 156 G4double G4PairProductionRelModel::ComputeRelXSectionPerAtom(G4double k, G4double Z) 153 { 157 { 154 if(nullptr == fParticleChange) { fParticleCh << 155 158 156 if (isFirstInstance || gElementData.empty()) << 159 G4double cross = 0.0; 157 // init element data and LPM funcs << 160 158 G4AutoLock l(&thePairProdRelMutex); << 161 159 if (gElementData.empty()) { << 162 160 isFirstInstance = true; << 163 161 gElementData.resize(gMaxZet+1, nullptr); << 164 } 162 } << 165 */ 163 // static data should be initialised only << 166 164 InitialiseElementData(); << 167 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... 165 if (fIsUseLPMCorrection) { << 168 166 InitLPMFunctions(); << 169 G4double G4PairProductionRelModel::ComputeXSectionPerAtom(G4double totalEnergy, G4double Z) >> 170 { >> 171 G4double cross = 0.0; >> 172 >> 173 // number of intervals and integration step >> 174 G4double vcut = electron_mass_c2/totalEnergy ; >> 175 >> 176 // limits by the screening variable >> 177 G4double dmax = DeltaMax(); >> 178 G4double dmin = min(DeltaMin(totalEnergy),dmax); >> 179 G4double vcut1 = 0.5 - 0.5*sqrt(1. - dmin/dmax) ; >> 180 vcut = max(vcut, vcut1); >> 181 >> 182 >> 183 G4double vmax = 0.5; >> 184 G4int n = 1; // needs optimisation >> 185 >> 186 G4double delta = (vmax - vcut)*totalEnergy/G4double(n); >> 187 >> 188 G4double e0 = vcut*totalEnergy; >> 189 G4double xs; >> 190 >> 191 // simple integration >> 192 for(G4int l=0; l<n; l++,e0 += delta) { >> 193 for(G4int i=0; i<8; i++) { >> 194 >> 195 G4double eg = (e0 + xgi[i]*delta); >> 196 if (fLPMflag && totalEnergy>100.*GeV) >> 197 xs = ComputeRelDXSectionPerAtom(eg,totalEnergy,Z); >> 198 else >> 199 xs = ComputeDXSectionPerAtom(eg,totalEnergy,Z); >> 200 cross += wgi[i]*xs; >> 201 167 } 202 } 168 l.unlock(); << 169 } 203 } 170 // element selectors should be initialised i << 204 171 if (IsMaster()) { << 205 cross *= delta*2.; 172 InitialiseElementSelectors(p, cuts); << 206 >> 207 return cross; >> 208 } >> 209 >> 210 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... >> 211 >> 212 G4double >> 213 G4PairProductionRelModel::ComputeDXSectionPerAtom(G4double eplusEnergy, >> 214 G4double totalEnergy, >> 215 G4double /*Z*/) >> 216 { >> 217 // most simple case - complete screening: >> 218 >> 219 // dsig/dE+ = 4 * alpha * Z**2 * r0**2 / k >> 220 // * [ (y**2 + (1-y**2) + 2/3*y*(1-y) ) * ( log (183 * Z**-1/3) + 1/9 * y*(1-y) ] >> 221 // y = E+/k >> 222 G4double yp=eplusEnergy/totalEnergy; >> 223 G4double ym=1.-yp; >> 224 >> 225 G4double cross = 0.; >> 226 if (use_completescreening) >> 227 cross = (yp*yp + ym*ym + 2./3.*ym*yp)*(Fel - fCoulomb) + 1./9.*yp*ym; >> 228 else { >> 229 G4double delta = 0.25*DeltaMin(totalEnergy)/(yp*ym); >> 230 cross = (yp*yp + ym*ym)*(0.25*Phi1(delta) - lnZ/3. - fCoulomb) >> 231 + 2./3.*ym*yp*(0.25*Phi2(delta) - lnZ/3. - fCoulomb); 173 } 232 } >> 233 return cross/totalEnergy; >> 234 174 } 235 } >> 236 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... 175 237 176 void G4PairProductionRelModel::InitialiseLocal << 238 G4double 177 << 239 G4PairProductionRelModel::ComputeRelDXSectionPerAtom(G4double eplusEnergy, 178 { << 240 G4double totalEnergy, 179 SetElementSelectors(masterModel->GetElementS << 241 G4double /*Z*/) 180 } << 242 { 181 << 243 // most simple case - complete screening: 182 G4double G4PairProductionRelModel::ComputeXSec << 244 183 << 245 // dsig/dE+ = 4 * alpha * Z**2 * r0**2 / k 184 { << 246 // * [ (y**2 + (1-y**2) + 2/3*y*(1-y) ) * ( log (183 * Z**-1/3) + 1/9 * y*(1-y) ] 185 G4double xSection = 0.0; << 247 // y = E+/k 186 // check if LPM suppression needs to be used << 248 G4double yp=eplusEnergy/totalEnergy; 187 const G4bool isLPM = (fIsUseLPMCorrection << 249 G4double ym=1.-yp; 188 // determine the kinematical limits (taken i << 250 189 // the way in which the Coulomb correction i << 251 CalcLPMFunctions(totalEnergy,eplusEnergy); // gamma 190 const G4int iz = std::min(gMaxZet, G4 << 252 191 const G4double eps0 = CLHEP::electron_mass << 253 G4double cross = 0.; 192 // Coulomb correction is always included in << 254 if (use_completescreening) 193 // that this DCS is only used to get the int << 255 cross = xiLPM*(2./3.*phiLPM*(yp*yp + ym*ym) + gLPM)*(Fel - fCoulomb); 194 const G4double dmax = gElementData[iz]->fD << 256 else { 195 const G4double dmin = 4.*eps0*gElementData << 257 G4double delta = 0.25*DeltaMin(totalEnergy)/(yp*ym); 196 const G4double eps1 = 0.5 - 0.5*std::sqrt( << 258 cross = (1./3.*gLPM + 2./3.*phiLPM)*(yp*yp + ym*ym) 197 const G4double epsMin = std::max(eps0, eps1) << 259 *(0.25*Phi1(delta) - lnZ/3. - fCoulomb) 198 const G4double epsMax = 0.5; // DCS is symme << 260 + 2./3.*gLPM*ym*yp*(0.25*Phi2(delta) - lnZ/3. - fCoulomb); 199 // let Et be the total energy transferred to << 261 cross *= xiLPM; 200 // the [Et-min, Et-max] interval will be div << 201 // with width of dInterv = (Et-max - Et-min) << 202 // be done in each sub-inteval using the xi << 203 // that is in [0,1]. The 8-point GL q. is us << 204 const G4int numSub = 2; << 205 const G4double dInterv= (epsMax - epsMin)*ga << 206 G4double minEti = epsMin*gammaEnergy; << 207 for (G4int i = 0; i < numSub; ++i) { << 208 for (G4int ngl = 0; ngl < 8; ++ngl) { << 209 const G4double Et = (minEti + gXGL[ngl]* << 210 const G4double xs = isLPM ? ComputeRelDX << 211 : ComputeDXSec << 212 xSection += gWGL[ngl]*xs; << 213 } << 214 // update minimum Et of the sub-inteval << 215 minEti += dInterv; << 216 } 262 } 217 // apply corrections of variable transformat << 263 return cross/totalEnergy; 218 xSection = std::max(2.*xSection*dInterv, 0.) << 264 219 return xSection; << 220 } << 221 << 222 // DCS WITHOUT LPM SUPPRESSION << 223 // Computes DCS value for a given target eleme << 224 // total energy transferred to one of the e-/e << 225 // The constant factor 4 \alpha r_0^2 Z (Z +\e << 226 // the returned value will be differential in << 227 // the eps=Et/Eg. The computed part of the DCS << 228 // NORMAL CASE: DEFAULT STTING (i.e. fIsUseCom << 229 // ds/deps(Et,Eg,Z) = ds/deps(eps,Z) = (eps^2+ << 230 // + 2*eps(1-eps)*[phi2(d)/4-ln(Z)/3-fc]/3 whe << 231 // screening variable d=d(eps)=136Z^(-1/3)eps0 << 232 // COMPLETE SCREENING (when d(eps) approx-equa << 233 // ds/deps(Et,Eg,Z) = ds/deps(eps,Z) = (eps^2+ << 234 // -eps(1-eps)/9 where Lel=phi1(0)/4-ln(Z)/3 i << 235 // logarithm, fc is the Coulomb correction and << 236 // phi1(0)/4-1/6-ln(Z)/3 = Lel-1/6 (due to phi << 237 G4double G4PairProductionRelModel::ComputeDXSe << 238 << 239 << 240 { << 241 G4double xSection = 0.; << 242 const G4int iz = std::min(gMaxZet, G4lr << 243 const G4double eps = pEnergy/gammaEnergy; << 244 const G4double epsm = 1.-eps; << 245 const G4double dum = eps*epsm; << 246 if (fIsUseCompleteScreening) { << 247 // complete screening: << 248 const G4double Lel = gElementData[iz]->f << 249 const G4double fc = gElementData[iz]->f << 250 xSection = (eps*eps + epsm*epsm + 2.*dum/3 << 251 } else { << 252 // normal case: << 253 const G4double eps0 = CLHEP::electron_mas << 254 const G4double fc = gElementData[iz]->f << 255 const G4double lnZ13 = gElementData[iz]->f << 256 const G4double delta = gElementData[iz]->f << 257 G4double phi1, phi2; << 258 ComputePhi12(delta, phi1, phi2); << 259 xSection = (eps*eps + epsm*epsm)*(0.25*ph << 260 + 2.*dum*(0.25*phi2-lnZ13-fc)/3 << 261 } << 262 // non-const. part of the DCS differential i << 263 // ds/dEt=ds/deps deps/dEt with deps/dEt=1/E << 264 return std::max(xSection, 0.0)/gammaEnergy; << 265 } << 266 << 267 // DCS WITH POSSIBLE LPM SUPPRESSION << 268 // Computes DCS value for a given target eleme << 269 // total energy transferred to one of the e-/e << 270 // For a given Z, the LPM suppression will dep << 271 // LMP-Energy. This will determine the suppres << 272 // pression functions xi(s), fi(s) and G(s). << 273 // The constant factor 4 \alpha r_0^2 Z (Z +\e << 274 // the returned value will be differential in << 275 // the eps=Et/Eg. The computed part of the DCS << 276 // NORMAL CASE: DEFAULT STTING (i.e. fIsUseCom << 277 // ds/deps(Et,Eg,Z)=ds/deps(eps,Z) = xi(s)*{ ( << 278 // *[phi1(d)/4-ln(Z)/3-fc] + 2*eps(1-eps)*G(s) << 279 // the universal (in the TF model) screening v << 280 // /[eps*(1-eps)] with eps0=mc^2/Eg. << 281 // COMPLETE SCREENING (when d(eps) approx-equa << 282 // ds/deps(Et,Eg,Z) = ds/deps(eps,Z) = xi(s)*{ << 283 // *(1-eps)/3)*2fi(s)/3 + G(s)/3] - eps(1-eps) << 284 // Note, that when the LPM suppression is abse << 285 // the normal and the complete screening DCS g << 286 G4double G4PairProductionRelModel::ComputeRelD << 287 << 288 << 289 { << 290 G4double xSection = 0.; << 291 const G4int iz = std::min(gMaxZet, G4lr << 292 const G4double eps = pEnergy/gammaEnergy; << 293 const G4double epsm = 1.-eps; << 294 const G4double dum = eps*epsm; << 295 // evaluate LPM suppression functions << 296 G4double fXiS, fGS, fPhiS; << 297 ComputeLPMfunctions(fXiS, fGS, fPhiS, eps, g << 298 if (fIsUseCompleteScreening) { << 299 // complete screening: << 300 const G4double Lel = gElementData[iz]->f << 301 const G4double fc = gElementData[iz]->f << 302 xSection = (Lel-fc)*((eps*eps+epsm*epsm)*2 << 303 } else { << 304 // normal case: << 305 const G4double eps0 = CLHEP::electron_mas << 306 const G4double fc = gElementData[iz]->f << 307 const G4double lnZ13 = gElementData[iz]->f << 308 const G4double delta = gElementData[iz]->f << 309 G4double phi1, phi2; << 310 ComputePhi12(delta, phi1, phi2); << 311 xSection = (eps*eps + epsm*epsm)*(2.*fPhi << 312 + 2.*dum*fGS*(0.25*phi2-lnZ13-f << 313 } << 314 // non-const. part of the DCS differential i << 315 // ds/dEt=ds/deps deps/dEt with deps/dEt=1/E << 316 return std::max(fXiS*xSection, 0.0)/gammaEne << 317 } 265 } 318 266 319 G4double << 267 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... 320 G4PairProductionRelModel::ComputeCrossSectionP << 268 321 G4double gammaEnergy, G4double Z, G4doub << 269 void G4PairProductionRelModel::CalcLPMFunctions(G4double k, G4double eplus) 322 { 270 { 323 G4double crossSection = 0.0 ; << 271 // *** calculate lpm variable s & sprime *** 324 // check kinematical limit << 272 // Klein eqs. (78) & (79) 325 if ( gammaEnergy <= 2.0*electron_mass_c2 ) { << 273 G4double sprime = sqrt(0.125*k*lpmEnergy/(eplus*(k-eplus))); 326 // compute the atomic cross section either b << 274 327 // or by numerically integrationg the DCS (w << 275 G4double s1 = preS1*z23; 328 if ( gammaEnergy < fParametrizedXSectionThre << 276 G4double logS1 = 2./3.*lnZ-2.*facFel; 329 // using the parametrized cross sections ( << 277 G4double logTS1 = logTwo+logS1; 330 crossSection = ComputeParametrizedXSection << 278 331 } else { << 279 xiLPM = 2.; 332 // by numerical integration of the DCS: << 280 333 // Computes the cross section with or with << 281 if (sprime>1) 334 // settings (by default with if the gamma << 282 xiLPM = 1.; 335 // and using or not using complete sreenin << 283 else if (sprime>sqrt(2.)*s1) { 336 // Only the dependent part is computed in << 284 G4double h = log(sprime)/logTS1; 337 // i.e. the result must be multiplied here << 285 xiLPM = 1+h-0.08*(1-h)*(1-sqr(1-h))/logTS1; 338 crossSection = ComputeXSectionPerAtom(gamm << 286 } 339 // apply the constant factors: << 287 340 // - eta(Z) is a correction to account int << 288 G4double s = sprime/sqrt(xiLPM); 341 // - gXSecFactor = 4 \alpha r_0^2 << 289 // G4cout<<"k="<<k<<" y="<<eplus/k<<G4endl; 342 const G4int iz = std::min(gMaxZet, G4l << 290 // G4cout<<"s="<<s<<G4endl; 343 const G4double eta = gElementData[iz]->fEt << 291 344 crossSection *= gXSecFactor*Z*(Z+eta) << 292 // *** calculate supression functions phi and G *** >> 293 // Klein eqs. (77) >> 294 G4double s2=s*s; >> 295 G4double s3=s*s2; >> 296 G4double s4=s2*s2; >> 297 >> 298 if (s<0.1) { >> 299 // high suppression limit >> 300 phiLPM = 6.*s - 18.84955592153876*s2 + 39.47841760435743*s3 >> 301 - 57.69873135166053*s4; >> 302 gLPM = 37.69911184307752*s2 - 236.8705056261446*s3 + 807.7822389*s4; >> 303 } >> 304 else if (s<1.9516) { >> 305 // intermediate suppression >> 306 // using eq.77 approxim. valid s<2. >> 307 phiLPM = 1.-exp(-6.*s*(1.+(3.-pi)*s) >> 308 +s3/(0.623+0.795*s+0.658*s2)); >> 309 if (s<0.415827397755) { >> 310 // using eq.77 approxim. valid 0.07<s<2 >> 311 G4double psiLPM = 1-exp(-4*s-8*s2/(1+3.936*s+4.97*s2-0.05*s3+7.50*s4)); >> 312 gLPM = 3*psiLPM-2*phiLPM; >> 313 } >> 314 else { >> 315 // using alternative parametrisiation >> 316 G4double pre = -0.16072300849123999 + s*3.7550300067531581 + s2*-1.7981383069010097 >> 317 + s3*0.67282686077812381 + s4*-0.1207722909879257; >> 318 gLPM = tanh(pre); >> 319 } 345 } 320 } 346 // final protection << 321 else { 347 return std::max(crossSection, 0.); << 322 // low suppression limit valid s>2. >> 323 phiLPM = 1. - 0.0119048/s4; >> 324 gLPM = 1. - 0.0230655/s4; >> 325 } >> 326 >> 327 // *** make sure suppression is smaller than 1 *** >> 328 // *** caused by Migdal approximation in xi *** >> 329 if (xiLPM*phiLPM>1. || s>0.57) xiLPM=1./phiLPM; 348 } 330 } 349 331 350 void G4PairProductionRelModel::SetupForMateria << 332 351 << 333 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... >> 334 >> 335 G4double >> 336 G4PairProductionRelModel::ComputeCrossSectionPerAtom(const G4ParticleDefinition*, >> 337 G4double gammaEnergy, G4double Z, >> 338 G4double, G4double, G4double) 352 { 339 { 353 fLPMEnergy = mat->GetRadlen()*gLPMconstant; << 340 // static const G4double gammaEnergyLimit = 1.5*MeV; >> 341 G4double crossSection = 0.0 ; >> 342 if ( Z < 1. ) return crossSection; >> 343 if ( gammaEnergy <= 2.0*electron_mass_c2 ) return crossSection; >> 344 >> 345 SetCurrentElement(Z); >> 346 // choose calculator according to parameters and switches >> 347 // in the moment only one calculator: >> 348 crossSection=ComputeXSectionPerAtom(gammaEnergy,Z); >> 349 >> 350 G4double xi = Finel/(Fel - fCoulomb); // inelastic contribution >> 351 crossSection*=4.*Z*(Z+xi)*fine_structure_const*classic_electr_radius*classic_electr_radius; >> 352 >> 353 return crossSection; 354 } 354 } 355 355 356 void << 356 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... >> 357 >> 358 void 357 G4PairProductionRelModel::SampleSecondaries(st 359 G4PairProductionRelModel::SampleSecondaries(std::vector<G4DynamicParticle*>* fvect, 358 co << 360 const G4MaterialCutsCouple* couple, 359 co << 361 const G4DynamicParticle* aDynamicGamma, 360 G4 << 362 G4double, 361 G4 << 363 G4double) 362 // The secondaries e+e- energies are sampled u 364 // The secondaries e+e- energies are sampled using the Bethe - Heitler 363 // cross sections with Coulomb correction. 365 // cross sections with Coulomb correction. 364 // A modified version of the random number tec 366 // A modified version of the random number techniques of Butcher & Messel 365 // is used (Nuc Phys 20(1960),15). 367 // is used (Nuc Phys 20(1960),15). 366 // 368 // 367 // GEANT4 internal units. 369 // GEANT4 internal units. 368 // 370 // 369 // Note 1 : Effects due to the breakdown of th 371 // Note 1 : Effects due to the breakdown of the Born approximation at 370 // low energy are ignored. 372 // low energy are ignored. 371 // Note 2 : The differential cross section imp << 373 // Note 2 : The differential cross section implicitly takes account of 372 // pair creation in both nuclear and 374 // pair creation in both nuclear and atomic electron fields. 373 // However triplet prodution is not g 375 // However triplet prodution is not generated. 374 { 376 { 375 const G4Material* mat = couple->GetM << 377 const G4Material* aMaterial = couple->GetMaterial(); 376 const G4double gammaEnergy = aDynamicGamm << 378 377 const G4double eps0 = CLHEP::elect << 379 G4double GammaEnergy = aDynamicGamma->GetKineticEnergy(); 378 // << 380 G4ParticleMomentum GammaDirection = aDynamicGamma->GetMomentumDirection(); 379 // check kinematical limit: gamma energy(Eg) << 381 380 // (but the model should be used at higher e << 382 G4double epsil ; 381 if (eps0 > 0.5) { return; } << 383 G4double epsil0 = electron_mass_c2/GammaEnergy ; 382 // << 384 if(epsil0 > 1.0) return; 383 // select target atom of the material << 385 384 const G4Element* anElement = SelectTargetAto << 386 // do it fast if GammaEnergy < 2. MeV 385 aDyna << 387 static const G4double Egsmall=2.*MeV; 386 CLHEP::HepRandomEngine* rndmEngine = G4Rando << 388 387 // << 389 // select randomly one element constituing the material 388 // 'eps' is the total energy transferred to << 390 const G4Element* anElement = SelectRandomAtom(aMaterial, theGamma, GammaEnergy); 389 // gamma energy units Eg. Since the correspo << 391 390 // the kinematical limits for eps0=mc^2/Eg < << 392 if (GammaEnergy < Egsmall) { 391 // 1. 'eps' is sampled uniformly on the [eps << 393 392 // 2. otherwise, on the [eps_min, 0.5] inter << 394 epsil = epsil0 + (0.5-epsil0)*G4UniformRand(); 393 G4double eps; << 395 394 // case 1. << 395 static const G4double Egsmall = 2.*CLHEP::Me << 396 if (gammaEnergy < Egsmall) { << 397 eps = eps0 + (0.5-eps0)*rndmEngine->flat() << 398 } else { 396 } else { 399 // case 2. << 397 // now comes the case with GammaEnergy >= 2. MeV 400 // get the Coulomb factor for the target e << 398 401 // F(Z) = 8*ln(Z)/3 if Eg <= 50 << 399 // Extract Coulomb factor for this Element 402 // F(Z) = 8*ln(Z)/3 + 8*fc(Z) if Eg > 50 << 400 G4double FZ = 8.*(anElement->GetIonisation()->GetlogZ3()); >> 401 if (GammaEnergy > 50.*MeV) FZ += 8.*(anElement->GetfCoulomb()); >> 402 >> 403 // limits of the screening variable >> 404 G4double screenfac = 136.*epsil0/(anElement->GetIonisation()->GetZ3()); >> 405 G4double screenmax = exp ((42.24 - FZ)/8.368) - 0.952 ; >> 406 G4double screenmin = min(4.*screenfac,screenmax); >> 407 >> 408 // limits of the energy sampling >> 409 G4double epsil1 = 0.5 - 0.5*sqrt(1. - screenmin/screenmax) ; >> 410 G4double epsilmin = max(epsil0,epsil1) , epsilrange = 0.5 - epsilmin; >> 411 403 // 412 // 404 // The screening variable 'delta(eps)' = 1 << 413 // sample the energy rate of the created electron (or positron) 405 // Due to the Coulomb correction, the DCS << 406 // kinematicaly allowed eps > eps0 values. << 407 // range with negative DCS, the minimum ep << 408 // max[eps0, epsp] with epsp is the soluti << 409 // with SF being the screening function (S << 410 // The solution is epsp = 0.5 - 0.5*sqrt[ << 411 // with deltap = Exp[(42.038-F(Z))/8.29]-0 << 412 // - when eps=eps_max = 0.5 => << 413 // - epsp = 0.5 - 0.5*sqrt[ 1 - delta_min/ << 414 // - and eps_min = max[eps0, epsp] << 415 const G4int iZet = std::min(gMax << 416 const G4double deltaFactor = gElementData[ << 417 const G4double deltaMin = 4.*deltaFacto << 418 G4double deltaMax = gElementData[ << 419 G4double FZ = 8.*gElementDa << 420 if ( gammaEnergy > fCoulombCorrectionThres << 421 FZ += 8.*gElementData[iZet]->fCoulo << 422 deltaMax = gElementData[iZet]->fDeltaMax << 423 } << 424 // compute the limits of eps << 425 const G4double epsp = 0.5 - 0.5*std << 426 const G4double epsMin = std::max(eps0 << 427 const G4double epsRange = 0.5 - epsMin; << 428 // 414 // 429 // sample the energy rate (eps) of the cre << 415 //G4double epsil, screenvar, greject ; 430 G4double F10, F20; << 416 G4double screenvar, greject ; 431 ScreenFunction12(deltaMin, F10, F20); << 417 432 F10 -= FZ; << 418 G4double F10 = ScreenFunction1(screenmin) - FZ; 433 F20 -= FZ; << 419 G4double F20 = ScreenFunction2(screenmin) - FZ; 434 const G4double NormF1 = std::max(F10 * e << 420 G4double NormF1 = max(F10*epsilrange*epsilrange,0.); 435 const G4double NormF2 = std::max(1.5 * F << 421 G4double NormF2 = max(1.5*F20,0.); 436 const G4double NormCond = NormF1/(NormF1 + << 422 437 // check if LPM correction is active << 438 const G4bool isLPM = (fIsUseLPMCorrection << 439 fLPMEnergy = mat->GetRadlen()*gLPMconstant << 440 // we will need 3 uniform random number fo << 441 G4double rndmv[3]; << 442 G4double greject = 0.; << 443 do { 423 do { 444 rndmEngine->flatArray(3, rndmv); << 424 if ( NormF1/(NormF1+NormF2) > G4UniformRand() ) { 445 if (NormCond > rndmv[0]) { << 425 epsil = 0.5 - epsilrange*pow(G4UniformRand(), 0.333333); 446 eps = 0.5 - epsRange * fG4Calc->A13(rn << 426 screenvar = screenfac/(epsil*(1-epsil)); 447 const G4double delta = deltaFactor/(ep << 427 if (fLPMflag && GammaEnergy>100.*GeV) { 448 if (isLPM) { << 428 CalcLPMFunctions(GammaEnergy,GammaEnergy*epsil); 449 G4double lpmXiS, lpmGS, lpmPhiS, phi << 429 greject = xiLPM*((gLPM+2.*phiLPM)*Phi1(screenvar) - gLPM*Phi2(screenvar) - phiLPM*FZ)/F10; 450 ComputePhi12(delta, phi1, phi2); << 430 } 451 ComputeLPMfunctions(lpmXiS, lpmGS, l << 431 else { 452 greject = lpmXiS*((2.*lpmPhiS+lpmGS) << 432 greject = (ScreenFunction1(screenvar) - FZ)/F10; 453 } else { << 433 } 454 greject = (ScreenFunction1(delta)-FZ << 434 455 } << 435 } else { 456 } else { << 436 epsil = epsilmin + epsilrange*G4UniformRand(); 457 eps = epsMin + epsRange*rndmv[1]; << 437 screenvar = screenfac/(epsil*(1-epsil)); 458 const G4double delta = deltaFactor/(ep << 438 if (fLPMflag && GammaEnergy>100.*GeV) { 459 if (isLPM) { << 439 CalcLPMFunctions(GammaEnergy,GammaEnergy*epsil); 460 G4double lpmXiS, lpmGS, lpmPhiS, phi << 440 greject = xiLPM*((0.5*gLPM+phiLPM)*Phi1(screenvar) + 0.5*gLPM*Phi2(screenvar) - 0.5*(gLPM+phiLPM)*FZ)/F20; 461 ComputePhi12(delta, phi1, phi2); << 441 } 462 ComputeLPMfunctions(lpmXiS, lpmGS, l << 442 else { 463 greject = lpmXiS*( (lpmPhiS+0.5*lpmG << 443 greject = (ScreenFunction2(screenvar) - FZ)/F20; 464 -0.5*(lpmGS+lpmPh << 444 } 465 } else { << 466 greject = (ScreenFunction2(delta)-FZ << 467 } << 468 } 445 } 469 // Loop checking, 03-Aug-2015, Vladimir << 446 470 } while (greject < rndmv[2]); << 447 } while( greject < G4UniformRand() ); 471 // end of eps sampling << 448 472 } << 449 } // end of epsil sampling >> 450 473 // 451 // 474 // select charges randomly << 452 // fixe charges randomly 475 G4double eTotEnergy, pTotEnergy; << 453 // 476 if (rndmEngine->flat() > 0.5) { << 454 477 eTotEnergy = (1.-eps)*gammaEnergy; << 455 G4double ElectTotEnergy, PositTotEnergy; 478 pTotEnergy = eps*gammaEnergy; << 456 if (G4UniformRand() > 0.5) { >> 457 >> 458 ElectTotEnergy = (1.-epsil)*GammaEnergy; >> 459 PositTotEnergy = epsil*GammaEnergy; >> 460 479 } else { 461 } else { 480 pTotEnergy = (1.-eps)*gammaEnergy; << 462 481 eTotEnergy = eps*gammaEnergy; << 463 PositTotEnergy = (1.-epsil)*GammaEnergy; >> 464 ElectTotEnergy = epsil*GammaEnergy; 482 } 465 } >> 466 483 // 467 // 484 // sample pair kinematics << 468 // scattered electron (positron) angles. ( Z - axis along the parent photon) 485 // << 486 const G4double eKinEnergy = std::max(0.,eTot << 487 const G4double pKinEnergy = std::max(0.,pTot << 488 // 469 // 489 G4ThreeVector eDirection, pDirection; << 470 // universal distribution suggested by L. Urban >> 471 // (Geant3 manual (1993) Phys211), >> 472 // derived from Tsai distribution (Rev Mod Phys 49,421(1977)) >> 473 >> 474 G4double u; >> 475 const G4double a1 = 0.625 , a2 = 3.*a1 , d = 27. ; >> 476 >> 477 if (9./(9.+d) >G4UniformRand()) u= - log(G4UniformRand()*G4UniformRand())/a1; >> 478 else u= - log(G4UniformRand()*G4UniformRand())/a2; >> 479 >> 480 G4double TetEl = u*electron_mass_c2/ElectTotEnergy; >> 481 G4double TetPo = u*electron_mass_c2/PositTotEnergy; >> 482 G4double Phi = twopi * G4UniformRand(); >> 483 G4double dxEl= sin(TetEl)*cos(Phi),dyEl= sin(TetEl)*sin(Phi),dzEl=cos(TetEl); >> 484 G4double dxPo=-sin(TetPo)*cos(Phi),dyPo=-sin(TetPo)*sin(Phi),dzPo=cos(TetPo); >> 485 490 // 486 // 491 GetAngularDistribution()->SamplePairDirectio << 487 // kinematic of the created pair 492 eKinEnergy, pKinEnergy, eDirectio << 488 // 493 // create G4DynamicParticle object for the p << 489 // the electron and positron are assumed to have a symetric 494 auto aParticle1 = new G4DynamicParticle(fThe << 490 // angular distribution with respect to the Z axis along the parent photon. >> 491 >> 492 G4double ElectKineEnergy = max(0.,ElectTotEnergy - electron_mass_c2); >> 493 >> 494 G4ThreeVector ElectDirection (dxEl, dyEl, dzEl); >> 495 ElectDirection.rotateUz(GammaDirection); >> 496 >> 497 // create G4DynamicParticle object for the particle1 >> 498 G4DynamicParticle* aParticle1= new G4DynamicParticle( >> 499 theElectron,ElectDirection,ElectKineEnergy); >> 500 >> 501 // the e+ is always created (even with Ekine=0) for further annihilation. >> 502 >> 503 G4double PositKineEnergy = max(0.,PositTotEnergy - electron_mass_c2); >> 504 >> 505 G4ThreeVector PositDirection (dxPo, dyPo, dzPo); >> 506 PositDirection.rotateUz(GammaDirection); >> 507 >> 508 // create G4DynamicParticle object for the particle2 >> 509 G4DynamicParticle* aParticle2= new G4DynamicParticle( >> 510 thePositron,PositDirection,PositKineEnergy); 495 511 496 // create G4DynamicParticle object for the p << 497 auto aParticle2 = new G4DynamicParticle(fThe << 498 // Fill output vector 512 // Fill output vector 499 fvect->push_back(aParticle1); 513 fvect->push_back(aParticle1); 500 fvect->push_back(aParticle2); 514 fvect->push_back(aParticle2); >> 515 501 // kill incident photon 516 // kill incident photon 502 fParticleChange->SetProposedKineticEnergy(0. 517 fParticleChange->SetProposedKineticEnergy(0.); 503 fParticleChange->ProposeTrackStatus(fStopAnd << 518 fParticleChange->ProposeTrackStatus(fStopAndKill); 504 } << 505 << 506 // should be called only by the master and at << 507 void G4PairProductionRelModel::InitialiseEleme << 508 { << 509 // create for all elements that are in the d << 510 auto elemTable = G4Element::GetElementTable( << 511 for (auto const & elem : *elemTable) { << 512 const G4int iz = std::min(gMaxZet, elem->G << 513 if (nullptr == gElementData[iz]) { // crea << 514 const G4double logZ13 = elem->GetIonisat << 515 const G4double Z13 = elem->GetIonisat << 516 const G4double fc = elem->GetfCoulom << 517 const G4double FZLow = 8.*logZ13; << 518 const G4double FZHigh = 8.*(logZ13 + fc) << 519 G4double Fel; << 520 G4double Finel; << 521 if (iz<5) { // use data from Dirac-Fock << 522 Fel = gFelLowZet[iz]; << 523 Finel = gFinelLowZet[iz]; << 524 } else { // use the results of the T << 525 Fel = G4Log(184.) - logZ13; << 526 Finel = G4Log(1194.) - 2.*logZ13; << 527 } << 528 auto elD = new ElementData() << 529 elD->fLogZ13 = logZ13; << 530 elD->fCoulomb = fc; << 531 elD->fLradEl = Fel; << 532 elD->fDeltaFactor = 136./Z13; << 533 elD->fDeltaMaxLow = G4Exp((42.038 - F << 534 elD->fDeltaMaxHigh = G4Exp((42.038 - F << 535 elD->fEtaValue = Finel/(Fel-fc); << 536 elD->fLPMVarS1Cond = std::sqrt(2.)*Z13 << 537 elD->fLPMILVarS1Cond = 1./G4Log(elD->fLP << 538 gElementData[iz] = elD; << 539 } << 540 } << 541 } << 542 << 543 // s goes up to 2 with ds = 0.01 be default << 544 void G4PairProductionRelModel::InitLPMFunction << 545 if (!gLPMFuncs.fIsInitialized) { << 546 const G4int num = gLPMFuncs.fSLimit*gLPMFu << 547 gLPMFuncs.fLPMFuncG.resize(num); << 548 gLPMFuncs.fLPMFuncPhi.resize(num); << 549 for (G4int i=0; i<num; ++i) { << 550 const G4double sval = i/gLPMFuncs.fISDel << 551 ComputeLPMGsPhis(gLPMFuncs.fLPMFuncG[i], << 552 } << 553 gLPMFuncs.fIsInitialized = true; << 554 } << 555 } << 556 << 557 // used only at initialisation time << 558 void G4PairProductionRelModel::ComputeLPMGsPhi << 559 if (varShat < 0.01) { << 560 funcPhiS = 6.0*varShat*(1.0-CLHEP::pi*varS << 561 funcGS = 12.0*varShat-2.0*funcPhiS; << 562 } else { << 563 const G4double varShat2 = varShat*varShat; << 564 const G4double varShat3 = varShat*varShat2 << 565 const G4double varShat4 = varShat2*varShat << 566 if (varShat < 0.415827397755) { // Stanev << 567 funcPhiS = 1.0-G4Exp( -6.0*varShat*(1.0+ << 568 + varShat3/(0.623+0 << 569 // 1-\exp \left\{-4s-\frac{8s^2}{1+3.936 << 570 const G4double funcPsiS = 1.0-G4Exp( -4. << 571 + 3.936*varShat+4.97*varS << 572 // G(s) = 3 \psi(s) - 2 \phi(s) << 573 funcGS = 3.0*funcPsiS - 2.0*funcPhiS; << 574 } else if (varShat < 1.55) { << 575 funcPhiS = 1.0-G4Exp( -6.0*varShat*(1.0+ << 576 + varShat3/(0.623+0 << 577 const G4double dum0 = -0.16072300849123 << 578 -1.79813830690100 << 579 +0.67282686077812 << 580 -0.12077229098792 << 581 funcGS = std::tanh(dum0); << 582 } else { << 583 funcPhiS = 1.0-0.01190476/varShat4; << 584 if (varShat < 1.9156) { << 585 const G4double dum0 = -0.1607230084912 << 586 -1.7981383069010 << 587 +0.6728268607781 << 588 -0.1207722909879 << 589 funcGS = std::tanh(dum0); << 590 } else { << 591 funcGS = 1.0-0.0230655/varShat4; << 592 } << 593 } << 594 } << 595 } 519 } 596 520 597 // used at run-time to get some pre-computed L << 521 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... 598 void G4PairProductionRelModel::GetLPMFunctions << 599 << 600 << 601 if (sval < gLPMFuncs.fSLimit) { << 602 G4double val = sval*gLPMFuncs.fISDelta << 603 const G4int ilow = (G4int)val; << 604 val -= ilow; << 605 lpmGs = (gLPMFuncs.fLPMFuncG[ilow+1]-gL << 606 + gLPMFuncs.fLPMFuncG[ilow]; << 607 lpmPhis = (gLPMFuncs.fLPMFuncPhi[ilow+1]- << 608 + gLPMFuncs.fLPMFuncPhi[ilow]; << 609 } else { << 610 G4double ss = sval*sval; << 611 ss *= ss; << 612 lpmPhis = 1.0-0.01190476/ss; << 613 lpmGs = 1.0-0.0230655/ss; << 614 } << 615 } << 616 522 617 void G4PairProductionRelModel::ComputeLPMfunct << 618 G4double &funcGS, G4double &f << 619 const G4double egamma, const << 620 { << 621 // 1. y = E_+/E_{\gamma} with E_+ being the << 622 // to one of the e-/e << 623 // s' = \sqrt{ \frac{1}{8} \frac{1}{y(1-y)} << 624 const G4double varSprime = std::sqrt(0.125*f << 625 const G4double condition = gElementData[izet << 626 funcXiS = 2.0; << 627 if (varSprime > 1.0) { << 628 funcXiS = 1.0; << 629 } else if (varSprime > condition) { << 630 const G4double dum = gElementData[izet]->f << 631 const G4double funcHSprime = G4Log(varSpri << 632 funcXiS = 1.0 + funcHSprime << 633 - 0.08*(1.0-funcHSprime)*funcHSpr << 634 } << 635 // 2. s=\frac{s'}{\sqrt{\xi(s')}} << 636 const G4double varShat = varSprime / std::sq << 637 GetLPMFunctions(funcGS, funcPhiS, varShat); << 638 // MAKE SURE SUPPRESSION IS SMALLER THAN 1: << 639 if (funcXiS * funcPhiS > 1. || varShat > 0.5 << 640 funcXiS = 1. / funcPhiS; << 641 } << 642 } << 643 523 644 // Calculates the microscopic cross section in << 524 void G4PairProductionRelModel::SetupForMaterial(const G4ParticleDefinition*, 645 // G4BetheHeitlerModel and should be used belo << 525 const G4Material* mat, G4double) 646 // from the cross section data above 80-90 GeV << 526 { 647 // Parametrized formula (L. Urban) is used to << 527 lpmEnergy = mat->GetRadlen()*fLPMconstant; 648 // given numerically in the table of [Hubbell, << 528 // G4cout<<" lpmEnergy="<<lpmEnergy<<G4endl; 649 // Overbo: "Pair, Triplet, and Total Atomic Cr << 650 // Coefficients) for 1 MeV‐100 GeV Photons i << 651 // physical and chemical reference data 9.4 (1 << 652 // << 653 // The formula gives a good approximation of t << 654 // below 1.5 MeV: sigma=sigma(1.5MeV)*(GammaEn << 655 // *(GammaEn << 656 G4double << 657 G4PairProductionRelModel::ComputeParametrizedX << 658 << 659 { << 660 G4double xSection = 0.0 ; << 661 // short versions << 662 static const G4double kMC2 = CLHEP::electro << 663 // zero cross section below the kinematical << 664 if (Z < 0.9 || gammaE <= 2.0*kMC2) { return << 665 // << 666 static const G4double gammaEnergyLimit = 1.5 << 667 // set coefficients a, b c << 668 static const G4double a0 = 8.7842e+2*CLHEP: << 669 static const G4double a1 = -1.9625e+3*CLHEP: << 670 static const G4double a2 = 1.2949e+3*CLHEP: << 671 static const G4double a3 = -2.0028e+2*CLHEP: << 672 static const G4double a4 = 1.2575e+1*CLHEP: << 673 static const G4double a5 = -2.8333e-1*CLHEP: << 674 << 675 static const G4double b0 = -1.0342e+1*CLHEP: << 676 static const G4double b1 = 1.7692e+1*CLHEP: << 677 static const G4double b2 = -8.2381 *CLHEP: << 678 static const G4double b3 = 1.3063 *CLHEP: << 679 static const G4double b4 = -9.0815e-2*CLHEP: << 680 static const G4double b5 = 2.3586e-3*CLHEP: << 681 << 682 static const G4double c0 = -4.5263e+2*CLHEP: << 683 static const G4double c1 = 1.1161e+3*CLHEP: << 684 static const G4double c2 = -8.6749e+2*CLHEP: << 685 static const G4double c3 = 2.1773e+2*CLHEP: << 686 static const G4double c4 = -2.0467e+1*CLHEP: << 687 static const G4double c5 = 6.5372e-1*CLHEP: << 688 // check low energy limit of the approximati << 689 G4double gammaEnergyOrg = gammaE; << 690 if (gammaE < gammaEnergyLimit) { gammaE = ga << 691 // compute gamma energy variables << 692 const G4double x = G4Log(gammaE/kMC2); << 693 const G4double x2 = x *x; << 694 const G4double x3 = x2*x; << 695 const G4double x4 = x3*x; << 696 const G4double x5 = x4*x; << 697 // << 698 const G4double F1 = a0 + a1*x + a2*x2 + a3*x << 699 const G4double F2 = b0 + b1*x + b2*x2 + b3*x << 700 const G4double F3 = c0 + c1*x + c2*x2 + c3*x << 701 // compute the approximated cross section << 702 xSection = (Z + 1.)*(F1*Z + F2*Z*Z + F3); << 703 // check if we are below the limit of the ap << 704 if (gammaEnergyOrg < gammaEnergyLimit) { << 705 const G4double dum = (gammaEnergyOrg-2.*kM << 706 xSection *= dum*dum; << 707 } << 708 return xSection; << 709 } 529 } 710 530 711 << 531 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... 712 532