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: G4eBremsstrahlungRelModel.cc,v 1.14 2009/04/09 18:41:18 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: G4eBremsstrahlungRelModel 34 // File name: G4eBremsstrahlungRelModel 33 // 35 // 34 // Author: Andreas Schaelicke << 36 // Author: Andreas Schaelicke 35 // 37 // 36 // Creation date: 12.08.2008 38 // Creation date: 12.08.2008 37 // 39 // 38 // Modifications: 40 // Modifications: 39 // 41 // 40 // 13.11.08 add SetLPMflag and SetLPMconsta 42 // 13.11.08 add SetLPMflag and SetLPMconstant methods 41 // 13.11.08 change default LPMconstant valu 43 // 13.11.08 change default LPMconstant value 42 // 13.10.10 add angular distributon interfa << 43 // 31.05.16 change LPMconstant such that it << 44 // that consistent to Migdal's one << 45 // computation; better agreement w << 46 // 15.07.18 improved LPM suppression functi << 47 // steps), code cleanup and optimi << 48 // model related comments, consist << 49 // 44 // 50 // Main References: 45 // Main References: 51 // Y.-S.Tsai, Rev. Mod. Phys. 46 (1974) 815; << 46 // Y.-S.Tsai, Rev. Mod. Phys. 46 (1974) 815; Rev. Mod. Phys. 49 (1977) 421. 52 // S.Klein, Rev. Mod. Phys. 71 (1999) 1501. 47 // S.Klein, Rev. Mod. Phys. 71 (1999) 1501. 53 // T.Stanev et.al., Phys. Rev. D25 (1982) 129 48 // T.Stanev et.al., Phys. Rev. D25 (1982) 1291. 54 // M.L.Ter-Mikaelian, High-energy Electromagn << 49 // M.L.Ter-Mikaelian, High-energy Electromagnetic Processes in Condensed Media, Wiley, 1972. 55 // Wiley, 1972. << 56 // 50 // 57 // ------------------------------------------- 51 // ------------------------------------------------------------------- 58 // 52 // >> 53 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... >> 54 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... 59 55 60 #include "G4eBremsstrahlungRelModel.hh" 56 #include "G4eBremsstrahlungRelModel.hh" 61 #include "G4PhysicalConstants.hh" << 62 #include "G4SystemOfUnits.hh" << 63 #include "G4Electron.hh" 57 #include "G4Electron.hh" >> 58 #include "G4Positron.hh" 64 #include "G4Gamma.hh" 59 #include "G4Gamma.hh" 65 #include "Randomize.hh" 60 #include "Randomize.hh" 66 #include "G4Material.hh" 61 #include "G4Material.hh" 67 #include "G4Element.hh" 62 #include "G4Element.hh" 68 #include "G4ElementVector.hh" 63 #include "G4ElementVector.hh" >> 64 #include "G4ProductionCutsTable.hh" 69 #include "G4ParticleChangeForLoss.hh" 65 #include "G4ParticleChangeForLoss.hh" 70 #include "G4ModifiedTsai.hh" << 66 #include "G4LossTableManager.hh" 71 #include "G4Exp.hh" << 67 72 #include "G4Log.hh" << 68 73 #include "G4Pow.hh" << 69 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... 74 #include "G4EmParameters.hh" << 75 #include "G4AutoLock.hh" << 76 #include <thread> << 77 << 78 const G4int G4eBremsstrahlungRelModel::gMaxZet << 79 << 80 // constant DCS factor: 16\alpha r_0^2/3 << 81 const G4double G4eBremsstrahlungRelModel::gBre << 82 = 16. * CLHEP::fine_structure_const * CLHEP: << 83 * CLHEP::classic_electr_radius/3.; << 84 << 85 // Migdal's constant: 4\pi r_0*electron_reduce << 86 const G4double G4eBremsstrahlungRelModel::gMig << 87 = 4. * CLHEP::pi * CLHEP::classic_electr_rad << 88 * CLHEP::electron_Compton_length * CLHEP:: << 89 << 90 // LPM constant: \alpha(mc^2)^2/(4\pi*\hbar c) << 91 const G4double G4eBremsstrahlungRelModel::gLPM << 92 = CLHEP::fine_structure_const * CLHEP::elect << 93 * CLHEP::electron_mass_c2 / (4. * CLHEP::p << 94 << 95 // abscissas and weights of an 8 point Gauss-L << 96 // for numerical integration on [0,1] << 97 const G4double G4eBremsstrahlungRelModel::gXGL << 98 1.98550718e-02, 1.01666761e-01, 2.37233795e- << 99 5.91717321e-01, 7.62766205e-01, 8.98333239e- << 100 }; << 101 const G4double G4eBremsstrahlungRelModel::gWGL << 102 5.06142681e-02, 1.11190517e-01, 1.56853323e- << 103 1.81341892e-01, 1.56853323e-01, 1.11190517e- << 104 }; << 105 << 106 // elastic and inelatic radiation logarithms f << 107 // Thomas-Fermi model doesn't work): computed << 108 const G4double G4eBremsstrahlungRelModel::gFel << 109 0.0, 5.3104, 4.7935, 4.7402, 4.7112, 4.6694, << 110 }; << 111 const G4double G4eBremsstrahlungRelModel::gFin << 112 0.0, 5.9173, 5.6125, 5.5377, 5.4728, 5.4174, << 113 }; << 114 << 115 // LPM supression functions evaluated at initi << 116 std::shared_ptr<G4eBremsstrahlungRelModel::LPM << 117 { << 118 // We have to use shared pointer for the LPM << 119 // by the G4eBremsstrahlungRelModel used in << 120 // model is owned (well deleted) by (at leas << 121 // a G4SeltzerBergerModel which is owned by << 122 // which owned by a G4ThreadLocalSingleton<G << 123 // which is a static global and thus deleted << 124 // is deleted. << 125 static auto _instance = std::make_shared<G4e << 126 return _instance; << 127 } << 128 << 129 // special data structure per element i.e. per << 130 std::shared_ptr<std::vector<G4eBremsstrahlungR << 131 { << 132 // Same code comment as for gLPMFuncs. << 133 static auto _instance = std::make_shared<std << 134 return _instance; << 135 } << 136 70 137 static std::once_flag applyOnce; << 71 const G4double G4eBremsstrahlungRelModel::xgi[]={ 0.0199, 0.1017, 0.2372, 0.4083, >> 72 0.5917, 0.7628, 0.8983, 0.9801 }; >> 73 const G4double G4eBremsstrahlungRelModel::wgi[]={ 0.0506, 0.1112, 0.1569, 0.1813, >> 74 0.1813, 0.1569, 0.1112, 0.0506 }; >> 75 const G4double G4eBremsstrahlungRelModel::Fel_light[] = {0., 5.31 , 4.79 , 4.74 , 4.71} ; >> 76 const G4double G4eBremsstrahlungRelModel::Finel_light[] = {0., 6.144 , 5.621 , 5.805 , 5.924} ; 138 77 139 namespace << 78 >> 79 using namespace std; >> 80 >> 81 G4eBremsstrahlungRelModel::G4eBremsstrahlungRelModel(const G4ParticleDefinition* p, >> 82 const G4String& name) >> 83 : G4VEmModel(name), >> 84 particle(0), >> 85 fXiLPM(0), fPhiLPM(0), fGLPM(0), >> 86 isElectron(true), >> 87 fMigdalConstant(classic_electr_radius*electron_Compton_length*electron_Compton_length*4.0*pi), >> 88 fLPMconstant(fine_structure_const*electron_mass_c2*electron_mass_c2/(4.*pi*hbarc)*0.5), >> 89 bremFactor(fine_structure_const*classic_electr_radius*classic_electr_radius*16./3.), >> 90 use_completescreening(true),isInitialised(false) 140 { 91 { 141 G4Mutex theBremRelMutex = G4MUTEX_INITIALIZE << 92 if(p) SetParticle(p); >> 93 theGamma = G4Gamma::Gamma(); >> 94 >> 95 minThreshold = 1.0*keV; >> 96 SetLowEnergyLimit(GeV); >> 97 >> 98 nist = G4NistManager::Instance(); >> 99 InitialiseConstants(); >> 100 >> 101 SetLPMFlag(true); 142 } 102 } 143 103 144 G4eBremsstrahlungRelModel::G4eBremsstrahlungRe << 104 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... 145 << 105 146 : G4VEmModel(nam), fLPMFuncs(gLPMFuncs()), fEl << 106 void G4eBremsstrahlungRelModel::InitialiseConstants() 147 { 107 { 148 fGammaParticle = G4Gamma::Gamma(); << 108 facFel = log(184.15); 149 // << 109 facFinel = log(1194.); 150 fLowestKinEnergy = 1.0*CLHEP::MeV; << 110 151 SetLowEnergyLimit(fLowestKinEnergy); << 111 preS1 = 1./(184.15*184.15); 152 // << 112 logTwo = log(2.); 153 fLPMEnergyThreshold = 1.e+39; << 154 fLPMEnergy = 0.; << 155 SetAngularDistribution(new G4ModifiedTsai()) << 156 // << 157 if (nullptr != p) { << 158 SetParticle(p); << 159 } << 160 } 113 } 161 114 >> 115 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... >> 116 162 G4eBremsstrahlungRelModel::~G4eBremsstrahlungR 117 G4eBremsstrahlungRelModel::~G4eBremsstrahlungRelModel() 163 { 118 { 164 if (fIsInitializer) { << 165 // clear ElementData container << 166 for (auto const & ptr : *fElementData) { d << 167 fElementData->clear(); << 168 // clear LPMFunctions (if any) << 169 if (fLPMFuncs->fIsInitialized) { << 170 fLPMFuncs->fLPMFuncG.clear(); << 171 fLPMFuncs->fLPMFuncPhi.clear(); << 172 fLPMFuncs->fIsInitialized = false; << 173 } << 174 } << 175 } 119 } 176 120 177 void G4eBremsstrahlungRelModel::Initialise(con << 121 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... 178 con << 179 { << 180 // parameters in each thread << 181 if (fPrimaryParticle != p) { << 182 SetParticle(p); << 183 } << 184 fUseLPM = G4EmParameters::Instance()->LPM(); << 185 fCurrentIZ = 0; << 186 122 187 // init static element data and precompute L << 123 void G4eBremsstrahlungRelModel::SetParticle(const G4ParticleDefinition* p) 188 std::call_once(applyOnce, [this]() { fIsInit << 124 { >> 125 particle = p; >> 126 particleMass = p->GetPDGMass(); >> 127 if(p == G4Electron::Electron()) isElectron = true; >> 128 else isElectron = false; >> 129 } 189 130 190 // for all treads and derived classes << 131 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... 191 if (fIsInitializer || fElementData->empty()) << 192 G4AutoLock l(&theBremRelMutex); << 193 if (fElementData->empty()) { << 194 fElementData->resize(gMaxZet+1, nullptr) << 195 } << 196 InitialiseElementData(); << 197 InitLPMFunctions(); << 198 l.unlock(); << 199 } << 200 132 201 // element selectors are initialized in the << 133 G4double G4eBremsstrahlungRelModel::MinEnergyCut(const G4ParticleDefinition*, 202 if (IsMaster()) { << 134 const G4MaterialCutsCouple*) 203 InitialiseElementSelectors(p, cuts); << 135 { 204 } << 136 return minThreshold; 205 // initialisation in all threads << 206 if (nullptr == fParticleChange) { << 207 fParticleChange = GetParticleChangeForLoss << 208 } << 209 if (GetTripletModel()) { << 210 GetTripletModel()->Initialise(p, cuts); << 211 fIsScatOffElectron = true; << 212 } << 213 } 137 } 214 138 215 void G4eBremsstrahlungRelModel::InitialiseLoca << 139 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... 216 << 140 >> 141 void G4eBremsstrahlungRelModel::SetupForMaterial(const G4ParticleDefinition*, >> 142 const G4Material* mat, G4double kineticEnergy) 217 { 143 { 218 SetElementSelectors(masterModel->GetElementS << 144 densityFactor = mat->GetElectronDensity()*fMigdalConstant; >> 145 lpmEnergy = mat->GetRadlen()*fLPMconstant; >> 146 >> 147 // Threshold for LPM effect (i.e. below which LPM hidden by density effect) >> 148 if (LPMFlag()) >> 149 energyThresholdLPM=sqrt(densityFactor)*lpmEnergy; >> 150 else >> 151 energyThresholdLPM=1.e39; // i.e. do not use LPM effect >> 152 >> 153 // calculate threshold for density effect >> 154 kinEnergy = kineticEnergy; >> 155 totalEnergy = kineticEnergy + particleMass; >> 156 densityCorr = densityFactor*totalEnergy*totalEnergy; >> 157 >> 158 // define critical gamma energies (important for integration/dicing) >> 159 klpm=totalEnergy*totalEnergy/lpmEnergy; >> 160 kp=sqrt(densityCorr); >> 161 219 } 162 } 220 163 221 void G4eBremsstrahlungRelModel::SetParticle(co << 164 >> 165 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... >> 166 >> 167 void G4eBremsstrahlungRelModel::Initialise(const G4ParticleDefinition* p, >> 168 const G4DataVector& cuts) 222 { 169 { 223 fPrimaryParticle = p; << 170 if(p) SetParticle(p); 224 fPrimaryParticleMass = p->GetPDGMass(); << 171 225 fIsElectron = (p==G4Electron::Elect << 172 highKinEnergy = HighEnergyLimit(); >> 173 lowKinEnergy = LowEnergyLimit(); >> 174 >> 175 currentZ = 0.; >> 176 >> 177 InitialiseElementSelectors(p, cuts); >> 178 >> 179 if(isInitialised) return; >> 180 fParticleChange = GetParticleChangeForLoss(); >> 181 isInitialised = true; 226 } 182 } 227 183 228 // Sets kinematical variables like E_kin, E_t << 184 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... 229 // variables like LPM energy and characteristi << 185 230 // k_p^2) for the Ter-Mikaelian suppression ef << 186 G4double G4eBremsstrahlungRelModel::ComputeDEDXPerVolume( 231 void G4eBremsstrahlungRelModel::SetupForMateri << 187 const G4Material* material, 232 << 188 const G4ParticleDefinition* p, 233 << 189 G4double kineticEnergy, 234 { << 190 G4double cutEnergy) 235 fDensityFactor = gMigdalConstant*mat->GetEle << 236 fLPMEnergy = gLPMconstant*mat->GetRadlen << 237 // threshold for LPM effect (i.e. below whic << 238 if (fUseLPM) { << 239 fLPMEnergyThreshold = std::sqrt(fDensityFa << 240 } else { << 241 fLPMEnergyThreshold = 1.e+39; // i.e. do << 242 } << 243 // calculate threshold for density effect: k << 244 fPrimaryKinEnergy = kineticEnergy; << 245 fPrimaryTotalEnergy = kineticEnergy+fPrimary << 246 fDensityCorr = fDensityFactor*fPrimar << 247 // set activation flag for LPM effects in th << 248 fIsLPMActive = (fPrimaryTotalEnergy>fLPMEner << 249 } << 250 << 251 // minimum primary (e-/e+) energy at which dis << 252 G4double G4eBremsstrahlungRelModel::MinPrimary << 253 << 254 << 255 { << 256 return std::max(fLowestKinEnergy, cut); << 257 } << 258 << 259 // Computes the restricted dE/dx as the approp << 260 // element contributions that are computed by << 261 G4double << 262 G4eBremsstrahlungRelModel::ComputeDEDXPerVolum << 263 << 264 << 265 << 266 { 191 { >> 192 if(!particle) SetParticle(p); >> 193 if(kineticEnergy < lowKinEnergy) return 0.0; >> 194 G4double cut = std::min(cutEnergy, kineticEnergy); >> 195 if(cut == 0.0) return 0.0; >> 196 >> 197 SetupForMaterial(particle, material,kineticEnergy); >> 198 >> 199 const G4ElementVector* theElementVector = material->GetElementVector(); >> 200 const G4double* theAtomicNumDensityVector = material->GetAtomicNumDensityVector(); >> 201 267 G4double dedx = 0.0; 202 G4double dedx = 0.0; 268 if (nullptr == fPrimaryParticle) { << 203 269 SetParticle(p); << 204 // loop for elements in the material 270 } << 205 for (size_t i=0; i<material->GetNumberOfElements(); i++) { 271 if (kineticEnergy < LowEnergyLimit()) { << 206 272 return dedx; << 207 G4VEmModel::SetCurrentElement((*theElementVector)[i]); 273 } << 208 SetCurrentElement((*theElementVector)[i]->GetZ()); 274 // maximum value of the dE/dx integral (the << 209 275 G4double tmax = std::min(cutEnergy, kineticE << 210 dedx += theAtomicNumDensityVector[i]*currentZ*currentZ*ComputeBremLoss(cut); 276 if (tmax == 0.0) { << 277 return dedx; << 278 } << 279 // sets kinematical and material related var << 280 SetupForMaterial(fPrimaryParticle, material, << 281 // get element compositions of the material << 282 const G4ElementVector* theElemVector = mater << 283 const G4double* theAtomNumDensVector = mater << 284 const std::size_t numberOfElements = theElem << 285 // loop over the elements of the material an << 286 // the restricted dE/dx by numerical integra << 287 for (std::size_t ie = 0; ie < numberOfElemen << 288 G4VEmModel::SetCurrentElement((*theElemVec << 289 G4int zet = (*theElemVector)[ie]->GetZasIn << 290 fCurrentIZ = std::min(zet, gMaxZet); << 291 dedx += (zet*zet)*theAtomNumD << 292 } 211 } 293 // apply the constant factor C/Z = 16\alpha << 212 dedx *= bremFactor; 294 dedx *= gBremFactor; << 213 295 return std::max(dedx,0.); << 214 296 } << 215 return dedx; 297 << 216 } 298 // Computes the integral part of the restricte << 217 299 // element (Z) by numerically integrating the << 218 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... 300 // k_min=0 and k_max = tmax = min[gamma-cut, e << 219 301 // The numerical integration is done by dividi << 220 G4double G4eBremsstrahlungRelModel::ComputeBremLoss(G4double cut) 302 // subintervals and an 8 pint GL integral (on << 221 { 303 // inteval by tranforming k to alpha=k/E_t (E_ << 222 G4double loss = 0.0; 304 // and each sub-interavl is transformed to [0, << 223 305 // in xi(alpha) = xi(k) = [k/E_t-alpha_i]/delt << 224 // number of intervals and integration step 306 // the i = 1,2,..,n-th sub-interval so xi(k) i << 225 G4double vcut = cut/totalEnergy; 307 // This transformation from 'k' to 'xi(k)' res << 226 G4int n = (G4int)(20*vcut) + 3; 308 // of E_t*delta at each step. << 227 G4double delta = vcut/G4double(n); 309 // The restricted dE/dx = N int_{0}^{k_max} k* << 228 310 // one with LPM and one without LPM effects (s << 229 G4double e0 = 0.0; 311 // the ds/dk(Z,k) but ds/dk(Z,k)*[F*k/C] is co << 230 G4double xs; 312 // (i) what we need here is ds/dk*k and not << 231 313 // (ii) the Ter-Mikaelian suppression i.e. F << 232 // integration 314 // (iii) the constant factor C (includes Z^2 << 233 for(G4int l=0; l<n; l++) { 315 G4double G4eBremsstrahlungRelModel::ComputeBre << 234 316 { << 235 for(G4int i=0; i<8; i++) { 317 // number of intervals and integration step << 236 318 const G4double alphaMax = tmax/fPrimaryTotal << 237 G4double eg = (e0 + xgi[i]*delta)*totalEnergy; 319 const G4int nSub = (G4int)(20*alphaMa << 238 320 const G4double delta = alphaMax/((G4doubl << 239 if(totalEnergy > energyThresholdLPM) { 321 // set minimum value of the first sub-inteva << 240 xs = ComputeRelDXSectionPerAtom(eg); 322 G4double alpha_i = 0.0; << 241 } else { 323 G4double dedxInteg = 0.0; << 242 xs = ComputeDXSectionPerAtom(eg); 324 for (G4int l = 0; l < nSub; ++l) { << 243 } 325 for (G4int igl = 0; igl < 8; ++igl) { << 244 loss += wgi[i]*xs/(1.0 + densityCorr/(eg*eg)); 326 // compute the emitted photon energy k << 327 const G4double k = (alpha_i+gXGL[igl]* << 328 // compute the DCS value at k (without t << 329 const G4double dcs = fIsLPMActive << 330 ? ComputeRelDXSectio << 331 : ComputeDXSectionPe << 332 // account Ter-Mikaelian suppression: ti << 333 dedxInteg += gWGL[igl]*dcs/(1.0+fDensity << 334 } 245 } 335 // update sub-interval minimum value << 246 e0 += delta; 336 alpha_i += delta; << 337 } 247 } 338 // apply corrections due to variable transfo << 248 339 dedxInteg *= delta*fPrimaryTotalEnergy; << 249 loss *= delta*totalEnergy; 340 return std::max(dedxInteg,0.); << 250 >> 251 return loss; 341 } 252 } 342 253 343 // Computes restrected atomic cross section by << 254 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... 344 // DCS between the proper kinematical limits a << 255 345 G4double G4eBremsstrahlungRelModel::ComputeCro 256 G4double G4eBremsstrahlungRelModel::ComputeCrossSectionPerAtom( 346 << 257 const G4ParticleDefinition* p, 347 << 258 G4double kineticEnergy, 348 << 259 G4double Z, G4double, 349 << 260 G4double cutEnergy, 350 << 261 G4double maxEnergy) 351 << 262 { 352 { << 263 if(!particle) SetParticle(p); 353 G4double crossSection = 0.0; << 264 if(kineticEnergy < lowKinEnergy) return 0.0; 354 if (nullptr == fPrimaryParticle) { << 265 G4double cut = std::min(cutEnergy, kineticEnergy); 355 SetParticle(p); << 266 G4double tmax = std::min(maxEnergy, kineticEnergy); 356 } << 267 357 if (kineticEnergy < LowEnergyLimit()) { << 268 if(cut >= tmax) return 0.0; 358 return crossSection; << 269 359 } << 270 SetCurrentElement(Z); 360 // min/max kinetic energy limits of the DCS << 271 361 const G4double tmin = std::min(cut, kineticE << 272 G4double cross = ComputeXSectionPerAtom(cut); 362 const G4double tmax = std::min(maxEnergy, ki << 273 363 // zero restricted x-section if e- kinetic e << 274 // allow partial integration 364 if (tmin >= tmax) { << 275 if(tmax < kinEnergy) cross -= ComputeXSectionPerAtom(tmax); 365 return crossSection; << 276 366 } << 277 cross *= Z*Z*bremFactor; 367 fCurrentIZ = std::min(G4lrint(Z), gMaxZet); << 278 368 // integrate numerically (dependent part of) << 279 return cross; 369 // a. integrate between tmin and kineticEner << 370 crossSection = ComputeXSectionPerAtom(tmin); << 371 // allow partial integration: only if maxEne << 372 // b. integrate between tmax and kineticEner << 373 // (so the result in this case is the integr << 374 // maxEnergy) << 375 if (tmax < kineticEnergy) { << 376 crossSection -= ComputeXSectionPerAtom(tma << 377 } << 378 // multiply with the constant factors: 16\al << 379 crossSection *= Z*Z*gBremFactor; << 380 return std::max(crossSection, 0.); << 381 } << 382 << 383 // Numerical integral of the (k dependent part << 384 // k_max = E_k (where E_k is the kinetic energ << 385 // minimum of energy of the emitted photon). << 386 // transformed alpha(k) = ln(k/E_t) variable ( << 387 // the primary e-). The integration range is d << 388 // delta = [ln(k_min/E_t)-ln(k_max/E_t)]/n wid << 389 // on [0,1] is applied on each sub-inteval so << 390 // xi(alpha) = xi(k) = [ln(k/E_t)-alpha_i]/del << 391 // (i-1)*delta for the i = 1,2,..,n-th sub-int << 392 // sub-intevals. From the transformed xi, k(xi << 393 // Since the integration is done in variable x << 394 // transformation results in a multiplicative << 395 // However, DCS differential in k is ~1/k so t << 396 // becomes delta and the 1/k factor is dropped << 397 // NOTE: << 398 // - LPM suppression is accounted above thre << 399 // flag is set in SetUpForMaterial() => 2 << 400 // - Ter-Mikaelian suppression is always acc << 401 G4double G4eBremsstrahlungRelModel::ComputeXSe << 402 { << 403 G4double xSection = 0.0; << 404 const G4double alphaMin = G4Log(tmin/fPrimar << 405 const G4double alphaMax = G4Log(fPrimaryKinE << 406 const G4int nSub = std::max((G4int)(0.45*alp << 407 const G4double delta = alphaMax/((G4double)n << 408 // set minimum value of the first sub-inteva << 409 G4double alpha_i = alphaMin; << 410 for (G4int l = 0; l < nSub; ++l) { << 411 for (G4int igl = 0; igl < 8; ++igl) { << 412 // compute the emitted photon energy k << 413 const G4double k = G4Exp(alpha_i+gXGL[ << 414 // compute the DCS value at k (without t << 415 const G4double dcs = fIsLPMActive << 416 ? ComputeRelDXSectio << 417 : ComputeDXSectionPe << 418 // account Ter-Mikaelian suppression: ti << 419 xSection += gWGL[igl]*dcs/(1.0+fDensityC << 420 } << 421 // update sub-interval minimum value << 422 alpha_i += delta; << 423 } << 424 // apply corrections due to variable transfo << 425 xSection *= delta; << 426 // final check << 427 return std::max(xSection, 0.); << 428 } << 429 << 430 // DCS WITH LPM EFFECT: complete screening apr << 431 // ds/dk(Z,k) = C/[F*k]*{ Xi(s*F)*[y^2*G/4 +(1 << 432 // +(1-y)*[1+1/Z]/12} << 433 // Xi(s),G(s), Phi(s) are LPM suppression func << 434 // << 435 // LPM SUPPRESSION: The 's' is the suppression << 436 // 1+(k_p/k)^2 with k_p = hbar*w_p*E/(m*c^2) i << 437 // dependent constant. F accounts the Ter-Mika << 438 // transition in the emitted photon energy. Al << 439 // goes to 0 when s goes to 0 and goes to 1 wh << 440 // So evaluating the LPM suppression functions << 441 // smooth transition depending on the emitted << 442 // smoothly turned off i.e. Xi(sF)=G(sF)=Phi(s << 443 // and sF ~ s when k >> k_p since F ~ 1 in tha << 444 // HERE, ds/dk(Z,k)*[F*k/C] is computed since: << 445 // (i) DCS ~ 1/k factor will disappear due << 446 // v(k)=ln(k/E_t) -> dk/dv=E_t*e^v=k -> << 447 // would cnacell out the 1/k factor => << 448 // (ii) the constant factor C and Z don't de << 449 // (iii) the 1/F(k) factor is accounted in th << 450 // tion computation) or implicitly thro << 451 // (in the final state sampling algorit << 452 // COMPLETE SCREENING: see more at the DCS wit << 453 G4double << 454 G4eBremsstrahlungRelModel::ComputeRelDXSection << 455 { << 456 G4double dxsec = 0.0; << 457 if (gammaEnergy < 0.) { << 458 return dxsec; << 459 } << 460 const G4double y = gammaEnergy/fPrimaryT << 461 const G4double onemy = 1.-y; << 462 const G4double dum0 = 0.25*y*y; << 463 // evaluate LPM functions (combined with the << 464 G4double funcGS, funcPhiS, funcXiS; << 465 ComputeLPMfunctions(funcXiS, funcGS, funcPhi << 466 const ElementData* elDat = (*fElementData)[f << 467 const G4double term1 = funcXiS*(dum0*fun << 468 dxsec = term1*elDat->fZFactor1+onemy*elDat-> << 469 // << 470 if (fIsScatOffElectron) { << 471 fSumTerm = dxsec; << 472 fNucTerm = term1*elDat->fZFactor11 + onemy << 473 } << 474 return std::max(dxsec,0.0); << 475 } 280 } >> 281 >> 282 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... 476 283 477 // DCS WITHOUT LPM EFFECT: DCS with sceening ( << 284 478 // ds/dk(Z,k)=C/[F*k]*{(1-y+3*y^2/4)*[(0.25*ph << 285 G4double G4eBremsstrahlungRelModel::ComputeXSectionPerAtom(G4double cut) 479 // -2*ln(Z)/3)/Z]+ (1-y)*[(phi1(g)-phi2(g))+(p << 286 { 480 // where f_c(Z) is the Coulomb correction fact << 287 G4double cross = 0.0; 481 // psi2(e) are coherent and incoherent screeni << 288 482 // model of the atom, the screening functions << 289 // number of intervals and integration step 483 // depend on Z (not explicitly). These numeric << 290 G4double vcut = log(cut/totalEnergy); 484 // approximated as Tsai Eqs. [3.38-3.41] with << 291 G4double vmax = log(kinEnergy/totalEnergy); 485 // e=epsilon given by Tsai Eqs. [3.30 and 3.31 << 292 G4int n = (G4int)(0.45*(vmax - vcut)) + 4; 486 // ComputeScreeningFunctions()). Note, that in << 293 // n=1; // integration test 487 // g = e = 0 => 0.25*phi1(0)-ln(Z)/3 = ln(184. << 294 G4double delta = (vmax - vcut)/G4double(n); 488 // 0.25*psi1(0)-2*ln(Z)/3=ln(1193.923/Z^(2/3)) << 295 489 // psi1(0)-psi2(0) = 2/3 so the DCS in complet << 296 G4double e0 = vcut; 490 // COMPLETE SCREENING: << 297 G4double xs; 491 // ds/dk(Z,k)=C/k*{(1-y+3*y^2/4)*[L_el-f_c+L_i << 298 492 // used in case of DCS with LPM above (if all << 299 // integration 493 // absent i.e. their value = 1). << 300 for(G4int l=0; l<n; l++) { 494 // Since the Thomas-Fermi model of the atom is << 301 495 // complete screening is used here at low Z(<5 << 302 for(G4int i=0; i<8; i++) { 496 // computed by using the Dirac-Fock model of t << 303 497 // NOTE: that the Ter-Mikaelian suppression is << 304 G4double eg = exp(e0 + xgi[i]*delta)*totalEnergy; 498 // 1/F factor but it is included in the caller << 305 499 // HERE, ds/dk(Z,k)*[F*k/C] is computed exactl << 306 if(totalEnergy > energyThresholdLPM) { 500 G4double << 307 xs = ComputeRelDXSectionPerAtom(eg); 501 G4eBremsstrahlungRelModel::ComputeDXSectionPer << 308 } else { 502 { << 309 xs = ComputeDXSectionPerAtom(eg); 503 G4double dxsec = 0.0; << 310 } 504 if (gammaEnergy < 0.) { << 311 cross += wgi[i]*xs/(1.0 + densityCorr/(eg*eg)); 505 return dxsec; << 506 } << 507 const G4double y = gammaEnergy/fPrim << 508 const G4double onemy = 1.-y; << 509 const G4double dum0 = onemy+0.75*y*y; << 510 const ElementData* elDat = (*fElementData)[f << 511 // use complete screening and L_el, L_inel f << 512 if (fCurrentIZ < 5 || fIsUseCompleteScreenin << 513 dxsec = dum0*elDat->fZFactor1; << 514 dxsec += onemy*elDat->fZFactor2; << 515 if (fIsScatOffElectron) { << 516 fSumTerm = dxsec; << 517 fNucTerm = dum0*elDat->fZFactor11+onemy/ << 518 } << 519 } else { << 520 // use Tsai's analytical approx. (Tsai Eqs << 521 // numerical screening functions computed << 522 const G4double invZ = 1./(G4double)fCur << 523 const G4double Fz = elDat->fFz; << 524 const G4double logZ = elDat->fLogZ; << 525 const G4double dum1 = y/(fPrimaryTotalE << 526 const G4double gamma = dum1*elDat->fGamm << 527 const G4double epsilon = dum1*elDat->fEpsi << 528 // evaluate the screening functions << 529 G4double phi1, phi1m2, psi1, psi1m2; << 530 ComputeScreeningFunctions(phi1, phi1m2, ps << 531 dxsec = dum0*((0.25*phi1-Fz) + (0.25*psi1 << 532 dxsec += 0.125*onemy*(phi1m2 + psi1m2*invZ << 533 if (fIsScatOffElectron) { << 534 fSumTerm = dxsec; << 535 fNucTerm = dum0*(0.25*phi1-Fz) + 0.125*o << 536 } 312 } >> 313 e0 += delta; 537 } 314 } 538 return std::max(dxsec,0.0); << 315 >> 316 cross *= delta; >> 317 >> 318 return cross; 539 } 319 } 540 320 541 // Coherent and incoherent screening function << 321 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... 542 // Eqs.[3.38-3.41]). Tsai's analytical approxi << 322 void G4eBremsstrahlungRelModel::CalcLPMFunctions(G4double k) 543 // functions computed by using the Thomas-Ferm << 323 { 544 // ximation to the numerical TF screening func << 324 // *** calculate lpm variable s & sprime *** 545 // screening functions can be expressed in a ' << 325 // Klein eqs. (78) & (79) 546 // pendent variable (see Tsai Eqs. Eqs. [3.30 << 326 G4double sprime = sqrt(0.125*k*lpmEnergy/(totalEnergy*(totalEnergy-k))); 547 void G4eBremsstrahlungRelModel::ComputeScreeni << 327 548 << 328 G4double s1 = preS1*z23; 549 << 329 G4double logS1 = 2./3.*lnZ-2.*facFel; 550 << 330 G4double logTS1 = logTwo+logS1; 551 << 331 552 << 332 xiLPM = 2.; 553 { << 333 554 const G4double gam2 = gam*gam; << 334 if (sprime>1) 555 phi1 = 16.863-2.0*G4Log(1.0+0.311877*gam2) << 335 xiLPM = 1.; 556 +1.6*G4Exp(-1.5*gam); << 336 else if (sprime>sqrt(2.)*s1) { 557 phi1m2 = 2.0/(3.0+19.5*gam+18.0*gam2); // << 337 G4double h = log(sprime)/logTS1; 558 const G4double eps2 = eps*eps; << 338 xiLPM = 1+h-0.08*(1-h)*(1-sqr(1-h))/logTS1; 559 psi1 = 24.34-2.0*G4Log(1.0+13.111641*eps2) << 560 +1.2*G4Exp(-29.2*eps); << 561 psi1m2 = 2.0/(3.0+120.0*eps+1200.0*eps2); // << 562 } << 563 << 564 void << 565 G4eBremsstrahlungRelModel::SampleSecondaries(s << 566 c << 567 c << 568 G << 569 G << 570 { << 571 const G4double kineticEnergy = dp->GetKin << 572 if (kineticEnergy < LowEnergyLimit()) { << 573 return; << 574 } 339 } 575 // min, max kinetic energy limits << 340 576 const G4double tmin = std::min(cutEnergy, ki << 341 G4double s = sprime/sqrt(xiLPM); 577 const G4double tmax = std::min(maxEnergy, ki << 342 578 if (tmin >= tmax) { << 343 // *** merging with density effect*** should be only necessary in region "close to" kp, e.g. k<100*kp 579 return; << 344 // using Ter-Mikaelian eq. (20.9) >> 345 G4double k2 = k*k; >> 346 s = s * (1 + (densityCorr/k2) ); >> 347 >> 348 // recalculate Xi using modified s above >> 349 // Klein eq. (75) >> 350 xiLPM = 1.; >> 351 if (s<=s1) xiLPM = 2.; >> 352 else if ( (s1<s) && (s<=1) ) xiLPM = 1. + log(s)/logS1; >> 353 >> 354 >> 355 // *** calculate supression functions phi and G *** >> 356 // Klein eqs. (77) >> 357 G4double s2=s*s; >> 358 G4double s3=s*s2; >> 359 G4double s4=s2*s2; >> 360 >> 361 if (s<0.1) { >> 362 // high suppression limit >> 363 phiLPM = 6.*s - 18.84955592153876*s2 + 39.47841760435743*s3 >> 364 - 57.69873135166053*s4; >> 365 gLPM = 37.69911184307752*s2 - 236.8705056261446*s3 + 807.7822389*s4; 580 } 366 } 581 // << 367 else if (s<1.9516) { 582 SetupForMaterial(fPrimaryParticle, couple->G << 368 // intermediate suppression 583 const G4Element* elm = SelectTargetAtom(coup << 369 // using eq.77 approxim. valid s<2. 584 dp-> << 370 phiLPM = 1.-exp(-6.*s*(1.+(3.-pi)*s) 585 // << 371 +s3/(0.623+0.795*s+0.658*s2)); 586 fCurrentIZ = elm->GetZasInt(); << 372 if (s<0.415827397755) { 587 const ElementData* elDat = (*fElementData)[f << 373 // using eq.77 approxim. valid 0.07<s<2 588 const G4double funcMax = elDat->fZFactor1+el << 374 G4double psiLPM = 1-exp(-4*s-8*s2/(1+3.936*s+4.97*s2-0.05*s3+7.50*s4)); 589 // get the random engine << 375 gLPM = 3*psiLPM-2*phiLPM; 590 G4double rndm[2]; << 376 } 591 CLHEP::HepRandomEngine* rndmEngine = G4Rando << 377 else { 592 // min max of the transformed variable: x(k) << 378 // using alternative parametrisiation 593 const G4double xmin = G4Log(tmin*tmin+fDen << 379 G4double pre = -0.16072300849123999 + s*3.7550300067531581 + s2*-1.7981383069010097 594 const G4double xrange = G4Log(tmax*tmax+fDen << 380 + s3*0.67282686077812381 + s4*-0.1207722909879257; 595 G4double gammaEnergy, funcVal; << 381 gLPM = tanh(pre); 596 do { << 382 } 597 rndmEngine->flatArray(2, rndm); << 598 gammaEnergy = std::sqrt(std::max(G4Exp(xmi << 599 funcVal = fIsLPMActive << 600 ? ComputeRelDXSectionPerAtom( << 601 : ComputeDXSectionPerAtom(gam << 602 // cross-check of proper function maximum << 603 // if (funcVal > funcMax) { << 604 // G4cout << "### G4eBremsstrahlungRelMod << 605 // << funcVal << " > " << funcMax << 606 // << " Egamma(MeV)= " << gammaEnergy << 607 // << " Ee(MeV)= " << kineticEnergy << 608 // << " " << GetName() << 609 // << G4endl; << 610 // } << 611 // Loop checking, 03-Aug-2015, Vladimir Iv << 612 } while (funcVal < funcMax*rndm[1]); << 613 // << 614 // scattering off nucleus or off e- by tripl << 615 if (fIsScatOffElectron && rndmEngine->flat() << 616 GetTripletModel()->SampleSecondaries(vdp, << 617 return; << 618 } 383 } 619 // << 384 else { 620 // angles of the emitted gamma. ( Z - axis a << 385 // low suppression limit valid s>2. 621 // use general interface << 386 phiLPM = 1. - 0.0119048/s4; 622 G4ThreeVector gamDir = << 387 gLPM = 1. - 0.0230655/s4; 623 GetAngularDistribution()->SampleDirection( << 624 << 625 // create G4DynamicParticle object for the G << 626 auto gamma = new G4DynamicParticle(fGammaPar << 627 vdp->push_back(gamma); << 628 // compute post-interaction kinematics of pr << 629 // energy-momentum conservation << 630 const G4double totMomentum = std::sqrt(kinet << 631 fPrimaryTotalEn << 632 G4ThreeVector dir = << 633 (totMomentum*dp->GetMomentumDirec << 634 const G4double finalE = kineticEnergy-gamm << 635 // if secondary gamma energy is higher than << 636 // then stop tracking the primary particle a << 637 // instead of the primary one << 638 if (gammaEnergy > SecondaryThreshold()) { << 639 fParticleChange->ProposeTrackStatus(fStopA << 640 fParticleChange->SetProposedKineticEnergy( << 641 auto el = new G4DynamicParticle( << 642 const_cast<G4ParticleDefinition* << 643 vdp->push_back(el); << 644 } else { // continue tracking the primary e- << 645 fParticleChange->SetProposedMomentumDirect << 646 fParticleChange->SetProposedKineticEnergy( << 647 } 388 } >> 389 >> 390 // *** make sure suppression is smaller than 1 *** >> 391 // *** caused by Migdal approximation in xi *** >> 392 if (xiLPM*phiLPM>1. || s>0.57) xiLPM=1./phiLPM; 648 } 393 } 649 394 650 void G4eBremsstrahlungRelModel::InitialiseElem << 395 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... >> 396 >> 397 >> 398 G4double G4eBremsstrahlungRelModel::ComputeRelDXSectionPerAtom(G4double gammaEnergy) >> 399 // Ultra relativistic model >> 400 // only valid for very high energies, but includes LPM suppression >> 401 // * complete screening 651 { 402 { 652 // create for all elements that are in the d << 403 if(gammaEnergy < 0.0) return 0.0; 653 auto elemTable = G4Element::GetElementTable( << 404 654 for (auto const & elem : *elemTable) { << 405 G4double y = gammaEnergy/totalEnergy; 655 const G4double zet = elem->GetZ(); << 406 G4double y2 = y*y*.25; 656 const G4int izet = std::min(elem->GetZasIn << 407 G4double yone2 = (1.-y+2.*y2); 657 if (nullptr == (*fElementData)[izet]) { << 408 658 auto elemData = new ElementData(); << 409 // ** form factors complete screening case ** 659 const G4double fc = elem->GetfCoulomb(); << 410 660 G4double Fel = 1.; << 411 // ** calc LPM functions -- include ter-mikaelian merging with density effect ** 661 G4double Finel = 1.; << 412 // G4double xiLPM, gLPM, phiLPM; // to be made member variables !!! 662 elemData->fLogZ = G4Log(zet); << 413 CalcLPMFunctions(gammaEnergy); 663 elemData->fFz = elemData->fLogZ/3.+f << 414 664 if (izet < 5) { << 415 G4double mainLPM = xiLPM*(y2 * gLPM + yone2*phiLPM) * ( (Fel-fCoulomb) + Finel/currentZ ); 665 Fel = gFelLowZet[izet]; << 416 G4double secondTerm = (1.-y)/12.*(1.+1./currentZ); 666 Finel = gFinelLowZet[izet]; << 417 667 } else { << 418 G4double cross = mainLPM+secondTerm; 668 Fel = G4Log(184.15) - elemData->f << 419 return cross; 669 Finel = G4Log(1194) - 2.*elemData->f << 670 } << 671 const G4double z13 = G4Pow::GetInstance( << 672 const G4double z23 = z13*z13; << 673 elemData->fZFactor1 = (Fel-fc)+Fine << 674 elemData->fZFactor11 = (Fel-fc); // << 675 elemData->fZFactor2 = (1.+1./zet)/1 << 676 elemData->fVarS1 = z23/(184.15*1 << 677 elemData->fILVarS1Cond = 1./(G4Log(std << 678 elemData->fILVarS1 = 1./G4Log(elem << 679 elemData->fGammaFactor = 100.0*electro << 680 elemData->fEpsilonFactor = 100.0*electro << 681 (*fElementData)[izet] = elemData; << 682 } << 683 } << 684 } 420 } 685 421 686 void G4eBremsstrahlungRelModel::ComputeLPMfunc << 422 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... 687 << 423 688 << 424 G4double G4eBremsstrahlungRelModel::ComputeDXSectionPerAtom(G4double gammaEnergy) 689 << 425 // Relativistic model 690 { << 426 // only valid for high energies (and if LPM suppression does not play a role) 691 static const G4double sqrt2 = std::sqrt(2.); << 427 // * screening according to thomas-fermi-Model (only valid for Z>5) 692 const G4double redegamma = egamma/fPrimar << 428 // * no LPM effect 693 const G4double varSprime = std::sqrt(0.12 << 429 { 694 ((1.0-redegamm << 430 695 const ElementData* elDat = (*fElementData << 431 if(gammaEnergy < 0.0) return 0.0; 696 const G4double varS1 = elDat->fVarS1; << 432 697 const G4double condition = sqrt2*varS1; << 433 G4double y = gammaEnergy/totalEnergy; 698 G4double funcXiSprime = 2.0; << 434 699 if (varSprime > 1.0) { << 435 G4double main=0.,secondTerm=0.; 700 funcXiSprime = 1.0; << 436 701 } else if (varSprime > condition) { << 437 if (use_completescreening|| currentZ<5) { 702 const G4double ilVarS1Cond = elDat->fILVar << 438 // ** form factors complete screening case ** 703 const G4double funcHSprime = G4Log(varSpri << 439 main = (3./4.*y*y - y + 1.) * ( (Fel-fCoulomb) + Finel/currentZ ); 704 funcXiSprime = 1.0 + funcHSprime - 0.08*(1 << 440 secondTerm = (1.-y)/12.*(1.+1./currentZ); 705 *(2.0-fu << 706 } << 707 const G4double varS = varSprime/std::sqrt << 708 // - include dielectric suppression effect i << 709 const G4double varShat = varS*(1.0+fDensityC << 710 funcXiS = 2.0; << 711 if (varShat > 1.0) { << 712 funcXiS = 1.0; << 713 } else if (varShat > varS1) { << 714 funcXiS = 1.0+G4Log(varShat)*elDat->fILVar << 715 } 441 } 716 GetLPMFunctions(funcGS, funcPhiS, varShat); << 442 else { 717 //ComputeLPMGsPhis(funcGS, funcPhiS, varShat << 443 // ** intermediate screening using Thomas-Fermi FF from Tsai only valid for Z>=5** 718 // << 444 G4double dd=100.*electron_mass_c2*y/(totalEnergy-gammaEnergy); 719 //MAKE SURE SUPPRESSION IS SMALLER THAN 1: d << 445 G4double gg=dd*z13; 720 if (funcXiS*funcPhiS > 1. || varShat > 0.57) << 446 G4double eps=dd*z23; 721 funcXiS=1./funcPhiS; << 447 G4double phi1=Phi1(gg,currentZ), phi1m2=Phi1M2(gg,currentZ); >> 448 G4double psi1=Psi1(eps,currentZ), psi1m2=Psi1M2(eps,currentZ); >> 449 >> 450 main = (3./4.*y*y - y + 1.) * ( (0.25*phi1-1./3.*lnZ-fCoulomb) + (0.25*psi1-2./3.*lnZ)/currentZ ); >> 451 secondTerm = (1.-y)/8.*(phi1m2+psi1m2/currentZ); 722 } 452 } >> 453 G4double cross = main+secondTerm; >> 454 return cross; 723 } 455 } 724 456 725 void G4eBremsstrahlungRelModel::ComputeLPMGsPh << 457 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... 726 << 727 << 728 { << 729 if (varShat < 0.01) { << 730 funcPhiS = 6.0*varShat*(1.0-CLHEP::pi*varS << 731 funcGS = 12.0*varShat-2.0*funcPhiS; << 732 } else { << 733 const G4double varShat2 = varShat*varShat; << 734 const G4double varShat3 = varShat*varShat2 << 735 const G4double varShat4 = varShat2*varShat << 736 // use Stanev approximation: for \psi(s) a << 737 if (varShat < 0.415827) { << 738 funcPhiS = 1.0-G4Exp(-6.0*varShat*(1.0+v << 739 + varShat3/(0.623+0.796*varSha << 740 // 1-\exp \left\{-4s-\frac{8s^2}{1+3.936 << 741 const G4double funcPsiS = 1.0 - G4Exp(-4 << 742 - 8.0*varShat2/ << 743 - 0.05*varShat3 << 744 // G(s) = 3 \psi(s) - 2 \phi(s) << 745 funcGS = 3.0*funcPsiS - 2.0*funcPhiS; << 746 } else if (varShat<1.55) { << 747 funcPhiS = 1.0-G4Exp(-6.0*varShat*(1.0+v << 748 + varShat3/(0.623+0.796*varSha << 749 const G4double dum0 = -0.160723 << 750 -1.798138*varShat << 751 -0.120772*varShat << 752 funcGS = std::tanh(dum0); << 753 } else { << 754 funcPhiS = 1.0-0.011905/varShat4; << 755 if (varShat<1.9156) { << 756 const G4double dum0 = -0.160723 << 757 -1.798138*varSha << 758 -0.120772*varSha << 759 funcGS = std::tanh(dum0); << 760 } else { << 761 funcGS = 1.0-0.023065/varShat4; << 762 } << 763 } << 764 } << 765 } << 766 458 767 // s goes up to 2 with ds = 0.01 to be the def << 459 void G4eBremsstrahlungRelModel::SampleSecondaries( 768 void G4eBremsstrahlungRelModel::InitLPMFunctio << 460 std::vector<G4DynamicParticle*>* vdp, >> 461 const G4MaterialCutsCouple* couple, >> 462 const G4DynamicParticle* dp, >> 463 G4double cutEnergy, >> 464 G4double maxEnergy) 769 { 465 { 770 if (!fLPMFuncs->fIsInitialized) { << 466 G4double kineticEnergy = dp->GetKineticEnergy(); 771 const G4int num = fLPMFuncs->fSLimit*fLPMF << 467 if(kineticEnergy < lowKinEnergy) return; 772 fLPMFuncs->fLPMFuncG.resize(num); << 468 G4double cut = std::min(cutEnergy, kineticEnergy); 773 fLPMFuncs->fLPMFuncPhi.resize(num); << 469 G4double emax = std::min(maxEnergy, kineticEnergy); 774 for (G4int i = 0; i < num; ++i) { << 470 if(cut >= emax) return; 775 const G4double sval=i/fLPMFuncs->fISDelt << 471 776 ComputeLPMGsPhis(fLPMFuncs->fLPMFuncG[i] << 472 SetupForMaterial(particle, couple->GetMaterial(),kineticEnergy); >> 473 >> 474 const G4Element* elm = >> 475 SelectRandomAtom(couple,particle,kineticEnergy,cut,emax); >> 476 SetCurrentElement(elm->GetZ()); >> 477 >> 478 kinEnergy = kineticEnergy; >> 479 totalEnergy = kineticEnergy + particleMass; >> 480 densityCorr = densityFactor*totalEnergy*totalEnergy; >> 481 G4ThreeVector direction = dp->GetMomentumDirection(); >> 482 >> 483 // G4double fmax= fMax; >> 484 G4bool highe = true; >> 485 if(totalEnergy < energyThresholdLPM) highe = false; >> 486 >> 487 G4double xmin = log(cut*cut + densityCorr); >> 488 G4double xmax = log(emax*emax + densityCorr); >> 489 G4double gammaEnergy, f, x; >> 490 >> 491 do { >> 492 x = exp(xmin + G4UniformRand()*(xmax - xmin)) - densityCorr; >> 493 if(x < 0.0) x = 0.0; >> 494 gammaEnergy = sqrt(x); >> 495 if(highe) f = ComputeRelDXSectionPerAtom(gammaEnergy); >> 496 else f = ComputeDXSectionPerAtom(gammaEnergy); >> 497 >> 498 if ( f > fMax ) { >> 499 G4cout << "### G4eBremsstrahlungRelModel Warning: Majoranta exceeded! " >> 500 << f << " > " << fMax >> 501 << " Egamma(MeV)= " << gammaEnergy >> 502 << " E(mEV)= " << kineticEnergy >> 503 << G4endl; 777 } 504 } 778 fLPMFuncs->fIsInitialized = true; << 779 } << 780 } << 781 505 782 void G4eBremsstrahlungRelModel::GetLPMFunction << 506 } while (f < fMax*G4UniformRand()); 783 << 507 784 << 508 // 785 { << 509 // angles of the emitted gamma. ( Z - axis along the parent particle) 786 if (sval < fLPMFuncs->fSLimit) { << 510 // 787 G4double val = sval*fLPMFuncs->fISDelt << 511 // universal distribution suggested by L. Urban 788 const G4int ilow = (G4int)val; << 512 // (Geant3 manual (1993) Phys211), 789 val -= ilow; << 513 // derived from Tsai distribution (Rev Mod Phys 49,421(1977)) 790 lpmGs = (fLPMFuncs->fLPMFuncG[ilow+1]-fL << 514 791 + fLPMFuncs->fLPMFuncG[ilow]; << 515 G4double u; 792 lpmPhis = (fLPMFuncs->fLPMFuncPhi[ilow+1]- << 516 const G4double a1 = 0.625 , a2 = 3.*a1 , d = 27. ; 793 + fLPMFuncs->fLPMFuncPhi[ilow]; << 517 >> 518 if (9./(9.+d) > G4UniformRand()) u = - log(G4UniformRand()*G4UniformRand())/a1; >> 519 else u = - log(G4UniformRand()*G4UniformRand())/a2; >> 520 >> 521 G4double theta = u*particleMass/totalEnergy; >> 522 G4double sint = sin(theta); >> 523 G4double phi = twopi * G4UniformRand(); >> 524 G4ThreeVector gammaDirection(sint*cos(phi),sint*sin(phi), cos(theta)); >> 525 gammaDirection.rotateUz(direction); >> 526 >> 527 // create G4DynamicParticle object for the Gamma >> 528 G4DynamicParticle* g = new G4DynamicParticle(theGamma,gammaDirection, >> 529 gammaEnergy); >> 530 vdp->push_back(g); >> 531 >> 532 G4double totMomentum = sqrt(kineticEnergy*(totalEnergy + electron_mass_c2)); >> 533 G4ThreeVector dir = totMomentum*direction - gammaEnergy*gammaDirection; >> 534 direction = dir.unit(); >> 535 >> 536 // energy of primary >> 537 G4double finalE = kineticEnergy - gammaEnergy; >> 538 >> 539 // stop tracking and create new secondary instead of primary >> 540 if(gammaEnergy > SecondaryThreshold()) { >> 541 fParticleChange->ProposeTrackStatus(fStopAndKill); >> 542 fParticleChange->SetProposedKineticEnergy(0.0); >> 543 G4DynamicParticle* el = >> 544 new G4DynamicParticle(const_cast<G4ParticleDefinition*>(particle), >> 545 direction, finalE); >> 546 vdp->push_back(el); >> 547 >> 548 // continue tracking 794 } else { 549 } else { 795 G4double ss = sval*sval; << 550 fParticleChange->SetProposedMomentumDirection(direction); 796 ss *= ss; << 551 fParticleChange->SetProposedKineticEnergy(finalE); 797 lpmPhis = 1.0-0.01190476/ss; << 798 lpmGs = 1.0-0.0230655/ss; << 799 } 552 } 800 } 553 } >> 554 >> 555 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... >> 556 801 557 802 558