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.12 2008/11/13 23:28:27 schaelic Exp $ >> 27 // GEANT4 tag $Name: geant4-09-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 << 187 // init static element data and precompute L << 188 std::call_once(applyOnce, [this]() { fIsInit << 189 << 190 // for all treads and derived classes << 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 122 201 // element selectors are initialized in the << 123 void G4eBremsstrahlungRelModel::SetParticle(const G4ParticleDefinition* p) 202 if (IsMaster()) { << 124 { 203 InitialiseElementSelectors(p, cuts); << 125 particle = p; 204 } << 126 particleMass = p->GetPDGMass(); 205 // initialisation in all threads << 127 if(p == G4Electron::Electron()) isElectron = true; 206 if (nullptr == fParticleChange) { << 128 else isElectron = false; 207 fParticleChange = GetParticleChangeForLoss << 208 } << 209 if (GetTripletModel()) { << 210 GetTripletModel()->Initialise(p, cuts); << 211 fIsScatOffElectron = true; << 212 } << 213 } 129 } 214 130 215 void G4eBremsstrahlungRelModel::InitialiseLoca << 131 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... 216 << 132 >> 133 G4double G4eBremsstrahlungRelModel::MinEnergyCut(const G4ParticleDefinition*, >> 134 const G4MaterialCutsCouple*) 217 { 135 { 218 SetElementSelectors(masterModel->GetElementS << 136 return minThreshold; 219 } 137 } 220 138 221 void G4eBremsstrahlungRelModel::SetParticle(co << 139 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... >> 140 >> 141 void G4eBremsstrahlungRelModel::SetupForMaterial(const G4ParticleDefinition*, >> 142 const G4Material* mat, G4double kineticEnergy) 222 { 143 { 223 fPrimaryParticle = p; << 144 densityFactor = mat->GetElectronDensity()*fMigdalConstant; 224 fPrimaryParticleMass = p->GetPDGMass(); << 145 lpmEnergy = mat->GetRadlen()*fLPMconstant; 225 fIsElectron = (p==G4Electron::Elect << 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 226 } 162 } 227 163 228 // Sets kinematical variables like E_kin, E_t << 164 229 // variables like LPM energy and characteristi << 165 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... 230 // k_p^2) for the Ter-Mikaelian suppression ef << 166 231 void G4eBremsstrahlungRelModel::SetupForMateri << 167 void G4eBremsstrahlungRelModel::Initialise(const G4ParticleDefinition* p, 232 << 168 const G4DataVector& cuts) 233 << 234 { 169 { 235 fDensityFactor = gMigdalConstant*mat->GetEle << 170 if(p) SetParticle(p); 236 fLPMEnergy = gLPMconstant*mat->GetRadlen << 171 237 // threshold for LPM effect (i.e. below whic << 172 highKinEnergy = HighEnergyLimit(); 238 if (fUseLPM) { << 173 lowKinEnergy = LowEnergyLimit(); 239 fLPMEnergyThreshold = std::sqrt(fDensityFa << 174 >> 175 currentZ = 0.; >> 176 >> 177 InitialiseElementSelectors(p, cuts); >> 178 >> 179 if(isInitialised) return; >> 180 >> 181 if(pParticleChange) { >> 182 fParticleChange = reinterpret_cast<G4ParticleChangeForLoss*>(pParticleChange); 240 } else { 183 } else { 241 fLPMEnergyThreshold = 1.e+39; // i.e. do << 184 fParticleChange = new G4ParticleChangeForLoss(); 242 } 185 } 243 // calculate threshold for density effect: k << 186 isInitialised = true; 244 fPrimaryKinEnergy = kineticEnergy; << 187 } 245 fPrimaryTotalEnergy = kineticEnergy+fPrimary << 188 246 fDensityCorr = fDensityFactor*fPrimar << 189 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... 247 // set activation flag for LPM effects in th << 190 248 fIsLPMActive = (fPrimaryTotalEnergy>fLPMEner << 191 G4double G4eBremsstrahlungRelModel::ComputeDEDXPerVolume( 249 } << 192 const G4Material* material, 250 << 193 const G4ParticleDefinition* p, 251 // minimum primary (e-/e+) energy at which dis << 194 G4double kineticEnergy, 252 G4double G4eBremsstrahlungRelModel::MinPrimary << 195 G4double cutEnergy) 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 { 196 { >> 197 if(!particle) SetParticle(p); >> 198 if(kineticEnergy < lowKinEnergy) return 0.0; >> 199 G4double cut = std::min(cutEnergy, kineticEnergy); >> 200 if(cut == 0.0) return 0.0; >> 201 >> 202 SetupForMaterial(particle, material,kineticEnergy); >> 203 >> 204 const G4ElementVector* theElementVector = material->GetElementVector(); >> 205 const G4double* theAtomicNumDensityVector = material->GetAtomicNumDensityVector(); >> 206 267 G4double dedx = 0.0; 207 G4double dedx = 0.0; 268 if (nullptr == fPrimaryParticle) { << 208 269 SetParticle(p); << 209 // loop for elements in the material 270 } << 210 for (size_t i=0; i<material->GetNumberOfElements(); i++) { 271 if (kineticEnergy < LowEnergyLimit()) { << 211 272 return dedx; << 212 G4VEmModel::SetCurrentElement((*theElementVector)[i]); 273 } << 213 SetCurrentElement((*theElementVector)[i]->GetZ()); 274 // maximum value of the dE/dx integral (the << 214 275 G4double tmax = std::min(cutEnergy, kineticE << 215 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 } << 293 // apply the constant factor C/Z = 16\alpha << 294 dedx *= gBremFactor; << 295 return std::max(dedx,0.); << 296 } << 297 << 298 // Computes the integral part of the restricte << 299 // element (Z) by numerically integrating the << 300 // k_min=0 and k_max = tmax = min[gamma-cut, e << 301 // The numerical integration is done by dividi << 302 // subintervals and an 8 pint GL integral (on << 303 // inteval by tranforming k to alpha=k/E_t (E_ << 304 // and each sub-interavl is transformed to [0, << 305 // in xi(alpha) = xi(k) = [k/E_t-alpha_i]/delt << 306 // the i = 1,2,..,n-th sub-interval so xi(k) i << 307 // This transformation from 'k' to 'xi(k)' res << 308 // of E_t*delta at each step. << 309 // The restricted dE/dx = N int_{0}^{k_max} k* << 310 // one with LPM and one without LPM effects (s << 311 // the ds/dk(Z,k) but ds/dk(Z,k)*[F*k/C] is co << 312 // (i) what we need here is ds/dk*k and not << 313 // (ii) the Ter-Mikaelian suppression i.e. F << 314 // (iii) the constant factor C (includes Z^2 << 315 G4double G4eBremsstrahlungRelModel::ComputeBre << 316 { << 317 // number of intervals and integration step << 318 const G4double alphaMax = tmax/fPrimaryTotal << 319 const G4int nSub = (G4int)(20*alphaMa << 320 const G4double delta = alphaMax/((G4doubl << 321 // set minimum value of the first sub-inteva << 322 G4double alpha_i = 0.0; << 323 G4double dedxInteg = 0.0; << 324 for (G4int l = 0; l < nSub; ++l) { << 325 for (G4int igl = 0; igl < 8; ++igl) { << 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 } << 335 // update sub-interval minimum value << 336 alpha_i += delta; << 337 } 216 } 338 // apply corrections due to variable transfo << 217 dedx *= bremFactor; 339 dedxInteg *= delta*fPrimaryTotalEnergy; << 218 340 return std::max(dedxInteg,0.); << 219 >> 220 return dedx; 341 } 221 } 342 222 343 // Computes restrected atomic cross section by << 223 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... 344 // DCS between the proper kinematical limits a << 224 345 G4double G4eBremsstrahlungRelModel::ComputeCro << 225 G4double G4eBremsstrahlungRelModel::ComputeBremLoss(G4double cut) 346 << 226 { 347 << 227 G4double loss = 0.0; 348 << 228 349 << 229 // number of intervals and integration step 350 << 230 G4double vcut = cut/totalEnergy; 351 << 231 G4int n = (G4int)(20*vcut) + 3; 352 { << 232 G4double delta = vcut/G4double(n); 353 G4double crossSection = 0.0; << 233 354 if (nullptr == fPrimaryParticle) { << 234 G4double e0 = 0.0; 355 SetParticle(p); << 235 G4double xs; 356 } << 236 357 if (kineticEnergy < LowEnergyLimit()) { << 237 // integration 358 return crossSection; << 238 for(G4int l=0; l<n; l++) { 359 } << 239 360 // min/max kinetic energy limits of the DCS << 240 for(G4int i=0; i<8; i++) { 361 const G4double tmin = std::min(cut, kineticE << 241 362 const G4double tmax = std::min(maxEnergy, ki << 242 G4double eg = (e0 + xgi[i]*delta)*totalEnergy; 363 // zero restricted x-section if e- kinetic e << 243 364 if (tmin >= tmax) { << 244 if(totalEnergy > energyThresholdLPM) { 365 return crossSection; << 245 xs = ComputeRelDXSectionPerAtom(eg); 366 } << 246 } else { 367 fCurrentIZ = std::min(G4lrint(Z), gMaxZet); << 247 xs = ComputeDXSectionPerAtom(eg); 368 // integrate numerically (dependent part of) << 248 } 369 // a. integrate between tmin and kineticEner << 249 loss += wgi[i]*xs/(1.0 + densityCorr/(eg*eg)); 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 } << 476 << 477 // DCS WITHOUT LPM EFFECT: DCS with sceening ( << 478 // ds/dk(Z,k)=C/[F*k]*{(1-y+3*y^2/4)*[(0.25*ph << 479 // -2*ln(Z)/3)/Z]+ (1-y)*[(phi1(g)-phi2(g))+(p << 480 // where f_c(Z) is the Coulomb correction fact << 481 // psi2(e) are coherent and incoherent screeni << 482 // model of the atom, the screening functions << 483 // depend on Z (not explicitly). These numeric << 484 // approximated as Tsai Eqs. [3.38-3.41] with << 485 // e=epsilon given by Tsai Eqs. [3.30 and 3.31 << 486 // ComputeScreeningFunctions()). Note, that in << 487 // g = e = 0 => 0.25*phi1(0)-ln(Z)/3 = ln(184. << 488 // 0.25*psi1(0)-2*ln(Z)/3=ln(1193.923/Z^(2/3)) << 489 // psi1(0)-psi2(0) = 2/3 so the DCS in complet << 490 // COMPLETE SCREENING: << 491 // ds/dk(Z,k)=C/k*{(1-y+3*y^2/4)*[L_el-f_c+L_i << 492 // used in case of DCS with LPM above (if all << 493 // absent i.e. their value = 1). << 494 // Since the Thomas-Fermi model of the atom is << 495 // complete screening is used here at low Z(<5 << 496 // computed by using the Dirac-Fock model of t << 497 // NOTE: that the Ter-Mikaelian suppression is << 498 // 1/F factor but it is included in the caller << 499 // HERE, ds/dk(Z,k)*[F*k/C] is computed exactl << 500 G4double << 501 G4eBremsstrahlungRelModel::ComputeDXSectionPer << 502 { << 503 G4double dxsec = 0.0; << 504 if (gammaEnergy < 0.) { << 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 } 250 } >> 251 e0 += delta; 537 } 252 } 538 return std::max(dxsec,0.0); << 253 >> 254 loss *= delta*totalEnergy; >> 255 >> 256 return loss; 539 } 257 } 540 258 541 // Coherent and incoherent screening function << 259 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... 542 // Eqs.[3.38-3.41]). Tsai's analytical approxi << 260 543 // functions computed by using the Thomas-Ferm << 261 G4double G4eBremsstrahlungRelModel::ComputeCrossSectionPerAtom( 544 // ximation to the numerical TF screening func << 262 const G4ParticleDefinition* p, 545 // screening functions can be expressed in a ' << 263 G4double kineticEnergy, 546 // pendent variable (see Tsai Eqs. Eqs. [3.30 << 264 G4double Z, G4double, 547 void G4eBremsstrahlungRelModel::ComputeScreeni << 265 G4double cutEnergy, 548 << 266 G4double maxEnergy) 549 << 267 { 550 << 268 if(!particle) SetParticle(p); 551 << 269 if(kineticEnergy < lowKinEnergy) return 0.0; 552 << 270 G4double cut = std::min(cutEnergy, kineticEnergy); 553 { << 271 G4double tmax = std::min(maxEnergy, kineticEnergy); 554 const G4double gam2 = gam*gam; << 272 555 phi1 = 16.863-2.0*G4Log(1.0+0.311877*gam2) << 273 if(cut >= tmax) return 0.0; 556 +1.6*G4Exp(-1.5*gam); << 274 557 phi1m2 = 2.0/(3.0+19.5*gam+18.0*gam2); // << 275 SetCurrentElement(Z); 558 const G4double eps2 = eps*eps; << 276 559 psi1 = 24.34-2.0*G4Log(1.0+13.111641*eps2) << 277 G4double cross = ComputeXSectionPerAtom(cut); 560 +1.2*G4Exp(-29.2*eps); << 278 561 psi1m2 = 2.0/(3.0+120.0*eps+1200.0*eps2); // << 279 // allow partial integration 562 } << 280 if(tmax < kinEnergy) cross -= ComputeXSectionPerAtom(tmax); 563 << 281 564 void << 282 cross *= Z*Z*bremFactor; 565 G4eBremsstrahlungRelModel::SampleSecondaries(s << 283 566 c << 284 return cross; 567 c << 568 G << 569 G << 570 { << 571 const G4double kineticEnergy = dp->GetKin << 572 if (kineticEnergy < LowEnergyLimit()) { << 573 return; << 574 } << 575 // min, max kinetic energy limits << 576 const G4double tmin = std::min(cutEnergy, ki << 577 const G4double tmax = std::min(maxEnergy, ki << 578 if (tmin >= tmax) { << 579 return; << 580 } << 581 // << 582 SetupForMaterial(fPrimaryParticle, couple->G << 583 const G4Element* elm = SelectTargetAtom(coup << 584 dp-> << 585 // << 586 fCurrentIZ = elm->GetZasInt(); << 587 const ElementData* elDat = (*fElementData)[f << 588 const G4double funcMax = elDat->fZFactor1+el << 589 // get the random engine << 590 G4double rndm[2]; << 591 CLHEP::HepRandomEngine* rndmEngine = G4Rando << 592 // min max of the transformed variable: x(k) << 593 const G4double xmin = G4Log(tmin*tmin+fDen << 594 const G4double xrange = G4Log(tmax*tmax+fDen << 595 G4double gammaEnergy, funcVal; << 596 do { << 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 } << 619 // << 620 // angles of the emitted gamma. ( Z - axis a << 621 // use general interface << 622 G4ThreeVector gamDir = << 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 } << 648 } 285 } >> 286 >> 287 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... >> 288 649 289 650 void G4eBremsstrahlungRelModel::InitialiseElem << 290 G4double G4eBremsstrahlungRelModel::ComputeXSectionPerAtom(G4double cut) 651 { 291 { 652 // create for all elements that are in the d << 292 G4double cross = 0.0; 653 auto elemTable = G4Element::GetElementTable( << 293 654 for (auto const & elem : *elemTable) { << 294 // number of intervals and integration step 655 const G4double zet = elem->GetZ(); << 295 G4double vcut = log(cut/totalEnergy); 656 const G4int izet = std::min(elem->GetZasIn << 296 G4double vmax = log(kinEnergy/totalEnergy); 657 if (nullptr == (*fElementData)[izet]) { << 297 G4int n = (G4int)(0.45*(vmax - vcut)) + 4; 658 auto elemData = new ElementData(); << 298 // n=1; // integration test 659 const G4double fc = elem->GetfCoulomb(); << 299 G4double delta = (vmax - vcut)/G4double(n); 660 G4double Fel = 1.; << 300 661 G4double Finel = 1.; << 301 G4double e0 = vcut; 662 elemData->fLogZ = G4Log(zet); << 302 G4double xs; 663 elemData->fFz = elemData->fLogZ/3.+f << 303 664 if (izet < 5) { << 304 // integration 665 Fel = gFelLowZet[izet]; << 305 for(G4int l=0; l<n; l++) { 666 Finel = gFinelLowZet[izet]; << 306 >> 307 for(G4int i=0; i<8; i++) { >> 308 >> 309 G4double eg = exp(e0 + xgi[i]*delta)*totalEnergy; >> 310 >> 311 if(totalEnergy > energyThresholdLPM) { >> 312 xs = ComputeRelDXSectionPerAtom(eg); 667 } else { 313 } else { 668 Fel = G4Log(184.15) - elemData->f << 314 xs = ComputeDXSectionPerAtom(eg); 669 Finel = G4Log(1194) - 2.*elemData->f << 670 } 315 } 671 const G4double z13 = G4Pow::GetInstance( << 316 cross += wgi[i]*xs/(1.0 + densityCorr/(eg*eg)); 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 } 317 } >> 318 e0 += delta; 683 } 319 } >> 320 >> 321 cross *= delta; >> 322 >> 323 return cross; 684 } 324 } 685 325 686 void G4eBremsstrahlungRelModel::ComputeLPMfunc << 326 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... 687 << 327 void G4eBremsstrahlungRelModel::CalcLPMFunctions(G4double k) 688 << 328 { 689 << 329 // *** calculate lpm variable s & sprime *** 690 { << 330 // Klein eqs. (78) & (79) 691 static const G4double sqrt2 = std::sqrt(2.); << 331 G4double sprime = sqrt(0.125*k*lpmEnergy/(totalEnergy*(totalEnergy-k))); 692 const G4double redegamma = egamma/fPrimar << 332 693 const G4double varSprime = std::sqrt(0.12 << 333 G4double s1 = preS1*z23; 694 ((1.0-redegamm << 334 G4double logS1 = 2./3.*lnZ-2.*facFel; 695 const ElementData* elDat = (*fElementData << 335 G4double logTS1 = logTwo+logS1; 696 const G4double varS1 = elDat->fVarS1; << 336 697 const G4double condition = sqrt2*varS1; << 337 xiLPM = 2.; 698 G4double funcXiSprime = 2.0; << 338 699 if (varSprime > 1.0) { << 339 if (sprime>1) 700 funcXiSprime = 1.0; << 340 xiLPM = 1.; 701 } else if (varSprime > condition) { << 341 else if (sprime>sqrt(2.)*s1) { 702 const G4double ilVarS1Cond = elDat->fILVar << 342 G4double h = log(sprime)/logTS1; 703 const G4double funcHSprime = G4Log(varSpri << 343 xiLPM = 1+h-0.08*(1-h)*(1-sqr(1-h))/logTS1; 704 funcXiSprime = 1.0 + funcHSprime - 0.08*(1 << 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 } 344 } 716 GetLPMFunctions(funcGS, funcPhiS, varShat); << 345 717 //ComputeLPMGsPhis(funcGS, funcPhiS, varShat << 346 G4double s = sprime/sqrt(xiLPM); 718 // << 347 719 //MAKE SURE SUPPRESSION IS SMALLER THAN 1: d << 348 // *** merging with density effect*** should be only necessary in region "close to" kp, e.g. k<100*kp 720 if (funcXiS*funcPhiS > 1. || varShat > 0.57) << 349 // using Ter-Mikaelian eq. (20.9) 721 funcXiS=1./funcPhiS; << 350 G4double k2 = k*k; >> 351 s = s * (1 + (densityCorr/k2) ); >> 352 >> 353 // recalculate Xi using modified s above >> 354 // Klein eq. (75) >> 355 xiLPM = 1.; >> 356 if (s<=s1) xiLPM = 2.; >> 357 else if ( (s1<s) && (s<=1) ) xiLPM = 1. + log(s)/logS1; >> 358 >> 359 >> 360 // *** calculate supression functions phi and G *** >> 361 // Klein eqs. (77) >> 362 G4double s2=s*s; >> 363 G4double s3=s*s2; >> 364 G4double s4=s2*s2; >> 365 >> 366 if (s<0.1) { >> 367 // high suppression limit >> 368 phiLPM = 6.*s - 18.84955592153876*s2 + 39.47841760435743*s3 >> 369 - 57.69873135166053*s4; >> 370 gLPM = 37.69911184307752*s2 - 236.8705056261446*s3 + 807.7822389*s4; >> 371 } >> 372 else if (s<1.9516) { >> 373 // intermediate suppression >> 374 // using eq.77 approxim. valid s<2. >> 375 phiLPM = 1.-exp(-6.*s*(1.+(3.-pi)*s) >> 376 +s3/(0.623+0.795*s+0.658*s2)); >> 377 if (s<0.415827397755) { >> 378 // using eq.77 approxim. valid 0.07<s<2 >> 379 G4double psiLPM = 1-exp(-4*s-8*s2/(1+3.936*s+4.97*s2-0.05*s3+7.50*s4)); >> 380 gLPM = 3*psiLPM-2*phiLPM; >> 381 } >> 382 else { >> 383 // using alternative parametrisiation >> 384 G4double pre = -0.16072300849123999 + s*3.7550300067531581 + s2*-1.7981383069010097 >> 385 + s3*0.67282686077812381 + s4*-0.1207722909879257; >> 386 gLPM = tanh(pre); >> 387 } >> 388 } >> 389 else { >> 390 // low suppression limit valid s>2. >> 391 phiLPM = 1. - 0.0119048/s4; >> 392 gLPM = 1. - 0.0230655/s4; 722 } 393 } >> 394 >> 395 // *** make sure suppression is smaller than 1 *** >> 396 // *** caused by Migdal approximation in xi *** >> 397 if (xiLPM*phiLPM>1. || s>0.57) xiLPM=1./phiLPM; >> 398 } >> 399 >> 400 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... >> 401 >> 402 >> 403 G4double G4eBremsstrahlungRelModel::ComputeRelDXSectionPerAtom(G4double gammaEnergy) >> 404 // Ultra relativistic model >> 405 // only valid for very high energies, but includes LPM suppression >> 406 // * complete screening >> 407 { >> 408 if(gammaEnergy < 0.0) return 0.0; >> 409 >> 410 G4double y = gammaEnergy/totalEnergy; >> 411 G4double y2 = y*y*.25; >> 412 G4double yone2 = (1.-y+2.*y2); >> 413 >> 414 // ** form factors complete screening case ** >> 415 >> 416 // ** calc LPM functions -- include ter-mikaelian merging with density effect ** >> 417 // G4double xiLPM, gLPM, phiLPM; // to be made member variables !!! >> 418 CalcLPMFunctions(gammaEnergy); >> 419 >> 420 G4double mainLPM = xiLPM*(y2 * gLPM + yone2*phiLPM) * ( (Fel-fCoulomb) + Finel/currentZ ); >> 421 G4double secondTerm = (1.-y)/12.*(1.+1./currentZ); >> 422 >> 423 G4double cross = mainLPM+secondTerm; >> 424 return cross; 723 } 425 } 724 426 725 void G4eBremsstrahlungRelModel::ComputeLPMGsPh << 427 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... 726 << 428 727 << 429 G4double G4eBremsstrahlungRelModel::ComputeDXSectionPerAtom(G4double gammaEnergy) >> 430 // Relativistic model >> 431 // only valid for high energies (and if LPM suppression does not play a role) >> 432 // * screening according to thomas-fermi-Model (only valid for Z>5) >> 433 // * no LPM effect 728 { 434 { 729 if (varShat < 0.01) { << 435 730 funcPhiS = 6.0*varShat*(1.0-CLHEP::pi*varS << 436 if(gammaEnergy < 0.0) return 0.0; 731 funcGS = 12.0*varShat-2.0*funcPhiS; << 437 732 } else { << 438 G4double y = gammaEnergy/totalEnergy; 733 const G4double varShat2 = varShat*varShat; << 439 734 const G4double varShat3 = varShat*varShat2 << 440 G4double main=0.,secondTerm=0.; 735 const G4double varShat4 = varShat2*varShat << 441 736 // use Stanev approximation: for \psi(s) a << 442 if (use_completescreening|| currentZ<5) { 737 if (varShat < 0.415827) { << 443 // ** form factors complete screening case ** 738 funcPhiS = 1.0-G4Exp(-6.0*varShat*(1.0+v << 444 main = (3./4.*y*y - y + 1.) * ( (Fel-fCoulomb) + Finel/currentZ ); 739 + varShat3/(0.623+0.796*varSha << 445 secondTerm = (1.-y)/12.*(1.+1./currentZ); 740 // 1-\exp \left\{-4s-\frac{8s^2}{1+3.936 << 446 } 741 const G4double funcPsiS = 1.0 - G4Exp(-4 << 447 else { 742 - 8.0*varShat2/ << 448 // ** intermediate screening using Thomas-Fermi FF from Tsai only valid for Z>=5** 743 - 0.05*varShat3 << 449 G4double dd=100.*electron_mass_c2*y/(totalEnergy-gammaEnergy); 744 // G(s) = 3 \psi(s) - 2 \phi(s) << 450 G4double gg=dd*z13; 745 funcGS = 3.0*funcPsiS - 2.0*funcPhiS; << 451 G4double eps=dd*z23; 746 } else if (varShat<1.55) { << 452 G4double phi1=Phi1(gg,currentZ), phi1m2=Phi1M2(gg,currentZ); 747 funcPhiS = 1.0-G4Exp(-6.0*varShat*(1.0+v << 453 G4double psi1=Psi1(eps,currentZ), psi1m2=Psi1M2(eps,currentZ); 748 + varShat3/(0.623+0.796*varSha << 454 749 const G4double dum0 = -0.160723 << 455 main = (3./4.*y*y - y + 1.) * ( (0.25*phi1-1./3.*lnZ-fCoulomb) + (0.25*psi1-2./3.*lnZ)/currentZ ); 750 -1.798138*varShat << 456 secondTerm = (1.-y)/8.*(phi1m2+psi1m2/currentZ); 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 } 457 } >> 458 G4double cross = main+secondTerm; >> 459 return cross; 765 } 460 } 766 461 767 // s goes up to 2 with ds = 0.01 to be the def << 462 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... 768 void G4eBremsstrahlungRelModel::InitLPMFunctio << 463 >> 464 void G4eBremsstrahlungRelModel::SampleSecondaries( >> 465 std::vector<G4DynamicParticle*>* vdp, >> 466 const G4MaterialCutsCouple* couple, >> 467 const G4DynamicParticle* dp, >> 468 G4double cutEnergy, >> 469 G4double maxEnergy) 769 { 470 { 770 if (!fLPMFuncs->fIsInitialized) { << 471 G4double kineticEnergy = dp->GetKineticEnergy(); 771 const G4int num = fLPMFuncs->fSLimit*fLPMF << 472 if(kineticEnergy < lowKinEnergy) return; 772 fLPMFuncs->fLPMFuncG.resize(num); << 473 G4double cut = std::min(cutEnergy, kineticEnergy); 773 fLPMFuncs->fLPMFuncPhi.resize(num); << 474 G4double emax = std::min(maxEnergy, kineticEnergy); 774 for (G4int i = 0; i < num; ++i) { << 475 if(cut >= emax) return; 775 const G4double sval=i/fLPMFuncs->fISDelt << 476 776 ComputeLPMGsPhis(fLPMFuncs->fLPMFuncG[i] << 477 SetupForMaterial(particle, couple->GetMaterial(),kineticEnergy); >> 478 >> 479 const G4Element* elm = >> 480 SelectRandomAtom(couple,particle,kineticEnergy,cut,emax); >> 481 SetCurrentElement(elm->GetZ()); >> 482 >> 483 kinEnergy = kineticEnergy; >> 484 totalEnergy = kineticEnergy + particleMass; >> 485 densityCorr = densityFactor*totalEnergy*totalEnergy; >> 486 G4ThreeVector direction = dp->GetMomentumDirection(); >> 487 >> 488 // G4double fmax= fMax; >> 489 G4bool highe = true; >> 490 if(totalEnergy < energyThresholdLPM) highe = false; >> 491 >> 492 G4double xmin = log(cut*cut + densityCorr); >> 493 G4double xmax = log(emax*emax + densityCorr); >> 494 G4double gammaEnergy, f, x; >> 495 >> 496 do { >> 497 x = exp(xmin + G4UniformRand()*(xmax - xmin)) - densityCorr; >> 498 if(x < 0.0) x = 0.0; >> 499 gammaEnergy = sqrt(x); >> 500 if(highe) f = ComputeRelDXSectionPerAtom(gammaEnergy); >> 501 else f = ComputeDXSectionPerAtom(gammaEnergy); >> 502 >> 503 if ( f > fMax ) { >> 504 G4cout << "### G4eBremsstrahlungRelModel Warning: Majoranta exceeded! " >> 505 << f << " > " << fMax >> 506 << " Egamma(MeV)= " << gammaEnergy >> 507 << " E(mEV)= " << kineticEnergy >> 508 << G4endl; 777 } 509 } 778 fLPMFuncs->fIsInitialized = true; << 779 } << 780 } << 781 510 782 void G4eBremsstrahlungRelModel::GetLPMFunction << 511 } while (f < fMax*G4UniformRand()); 783 << 512 784 << 513 // 785 { << 514 // angles of the emitted gamma. ( Z - axis along the parent particle) 786 if (sval < fLPMFuncs->fSLimit) { << 515 // 787 G4double val = sval*fLPMFuncs->fISDelt << 516 // universal distribution suggested by L. Urban 788 const G4int ilow = (G4int)val; << 517 // (Geant3 manual (1993) Phys211), 789 val -= ilow; << 518 // derived from Tsai distribution (Rev Mod Phys 49,421(1977)) 790 lpmGs = (fLPMFuncs->fLPMFuncG[ilow+1]-fL << 519 791 + fLPMFuncs->fLPMFuncG[ilow]; << 520 G4double u; 792 lpmPhis = (fLPMFuncs->fLPMFuncPhi[ilow+1]- << 521 const G4double a1 = 0.625 , a2 = 3.*a1 , d = 27. ; 793 + fLPMFuncs->fLPMFuncPhi[ilow]; << 522 >> 523 if (9./(9.+d) > G4UniformRand()) u = - log(G4UniformRand()*G4UniformRand())/a1; >> 524 else u = - log(G4UniformRand()*G4UniformRand())/a2; >> 525 >> 526 G4double theta = u*particleMass/totalEnergy; >> 527 G4double sint = sin(theta); >> 528 G4double phi = twopi * G4UniformRand(); >> 529 G4ThreeVector gammaDirection(sint*cos(phi),sint*sin(phi), cos(theta)); >> 530 gammaDirection.rotateUz(direction); >> 531 >> 532 // create G4DynamicParticle object for the Gamma >> 533 G4DynamicParticle* g = new G4DynamicParticle(theGamma,gammaDirection, >> 534 gammaEnergy); >> 535 vdp->push_back(g); >> 536 >> 537 G4double totMomentum = sqrt(kineticEnergy*(totalEnergy + electron_mass_c2)); >> 538 G4ThreeVector dir = totMomentum*direction - gammaEnergy*gammaDirection; >> 539 direction = dir.unit(); >> 540 >> 541 // energy of primary >> 542 G4double finalE = kineticEnergy - gammaEnergy; >> 543 >> 544 // stop tracking and create new secondary instead of primary >> 545 if(gammaEnergy > SecondaryThreshold()) { >> 546 fParticleChange->ProposeTrackStatus(fStopAndKill); >> 547 fParticleChange->SetProposedKineticEnergy(0.0); >> 548 G4DynamicParticle* el = >> 549 new G4DynamicParticle(const_cast<G4ParticleDefinition*>(particle), >> 550 direction, finalE); >> 551 vdp->push_back(el); >> 552 >> 553 // continue tracking 794 } else { 554 } else { 795 G4double ss = sval*sval; << 555 fParticleChange->SetProposedMomentumDirection(direction); 796 ss *= ss; << 556 fParticleChange->SetProposedKineticEnergy(finalE); 797 lpmPhis = 1.0-0.01190476/ss; << 798 lpmGs = 1.0-0.0230655/ss; << 799 } 557 } 800 } 558 } >> 559 >> 560 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... >> 561 801 562 802 563