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 // Author: Sebastien Incerti << 26 // $Id: G4LivermoreGammaConversionModel.cc,v 1.8 2009/06/11 15:47:08 mantero Exp $ 27 // 22 January 2012 << 27 // GEANT4 tag $Name: geant4-09-03-patch-01 $ 28 // on base of G4LivermoreGammaConversi << 29 // and G4LivermoreRayleighModel (MT ve << 30 // 28 // 31 // Modifications: Zhuxin Li@CENBG << 29 // 32 // 11 March 2020 << 30 // Author: Sebastien Inserti 33 // derives from G4PairProductio << 31 // 30 October 2008 34 // ------------------------------------------- << 32 // >> 33 // History: >> 34 // -------- >> 35 // 12 Apr 2009 V Ivanchenko Cleanup initialisation and generation of secondaries: >> 36 // - apply internal high-energy limit only in constructor >> 37 // - do not apply low-energy limit (default is 0) >> 38 // - use CLHEP electron mass for low-enegry limit >> 39 // - remove MeanFreePath method and table >> 40 35 41 36 #include "G4LivermoreGammaConversionModel.hh" 42 #include "G4LivermoreGammaConversionModel.hh" 37 43 38 #include "G4AutoLock.hh" << 44 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... 39 #include "G4Electron.hh" << 40 #include "G4EmParameters.hh" << 41 #include "G4Exp.hh" << 42 #include "G4ParticleChangeForGamma.hh" << 43 #include "G4PhysicalConstants.hh" << 44 #include "G4PhysicsFreeVector.hh" << 45 #include "G4SystemOfUnits.hh" << 46 45 47 namespace << 46 using namespace std; 48 { << 49 G4Mutex LivermoreGammaConversionModelMutex = G << 50 } << 51 47 52 //....oooOO0OOooo........oooOO0OOooo........oo 48 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... 53 //....oooOO0OOooo........oooOO0OOooo........oo << 54 << 55 G4PhysicsFreeVector* G4LivermoreGammaConversio << 56 G4String G4LivermoreGammaConversionModel::gDat << 57 49 58 G4LivermoreGammaConversionModel::G4LivermoreGa << 50 G4LivermoreGammaConversionModel::G4LivermoreGammaConversionModel(const G4ParticleDefinition*, 59 << 51 const G4String& nam) 60 : G4PairProductionRelModel(p, nam) << 52 :G4VEmModel(nam),smallEnergy(2.*MeV),isInitialised(false), 61 { << 53 crossSectionHandler(0),meanFreePathTable(0) 62 fParticleChange = nullptr; << 54 { 63 lowEnergyLimit = 2. * CLHEP::electron_mass_c << 55 lowEnergyLimit = 2.0*electron_mass_c2; 64 verboseLevel = 0; << 56 highEnergyLimit = 100 * GeV; 65 // Verbosity scale for debugging purposes: << 57 SetHighEnergyLimit(highEnergyLimit); 66 // 0 = nothing << 58 67 // 1 = calculation of cross sections, file o << 59 verboseLevel= 0; 68 // 2 = entering in methods << 60 // Verbosity scale: 69 if (verboseLevel > 0) { << 61 // 0 = nothing 70 G4cout << "G4LivermoreGammaConversionModel << 62 // 1 = warning for energy non-conservation >> 63 // 2 = details of energy budget >> 64 // 3 = calculation of cross sections, file openings, sampling of atoms >> 65 // 4 = entering in methods >> 66 >> 67 if(verboseLevel > 0) { >> 68 G4cout << "Livermore Gamma conversion is constructed " << G4endl >> 69 << "Energy range: " >> 70 << lowEnergyLimit / MeV << " MeV - " >> 71 << highEnergyLimit / GeV << " GeV" >> 72 << G4endl; 71 } 73 } 72 } 74 } 73 75 74 //....oooOO0OOooo........oooOO0OOooo........oo 76 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... 75 77 76 G4LivermoreGammaConversionModel::~G4LivermoreG 78 G4LivermoreGammaConversionModel::~G4LivermoreGammaConversionModel() 77 { << 79 { 78 if (IsMaster()) { << 80 if (crossSectionHandler) delete crossSectionHandler; 79 for (G4int i = 0; i <= maxZ; ++i) { << 80 if (data[i]) { << 81 delete data[i]; << 82 data[i] = nullptr; << 83 } << 84 } << 85 } << 86 } 81 } 87 82 88 //....oooOO0OOooo........oooOO0OOooo........oo 83 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... 89 84 90 void G4LivermoreGammaConversionModel::Initiali << 85 void 91 << 86 G4LivermoreGammaConversionModel::Initialise(const G4ParticleDefinition*, >> 87 const G4DataVector&) 92 { 88 { 93 G4PairProductionRelModel::Initialise(particl << 89 if (verboseLevel > 3) 94 if (verboseLevel > 1) { << 90 G4cout << "Calling G4LivermoreGammaConversionModel::Initialise()" << G4endl; 95 G4cout << "Calling Initialise() of G4Liver << 96 << "Energy range: " << LowEnergyLim << 97 << " GeV isMater: " << IsMaster() < << 98 } << 99 91 100 if (IsMaster()) { << 92 if (crossSectionHandler) 101 // Initialise element selector << 93 { 102 InitialiseElementSelectors(particle, cuts) << 94 crossSectionHandler->Clear(); 103 << 95 delete crossSectionHandler; 104 // Access to elements << 96 } 105 const G4ElementTable* elemTable = G4Elemen << 97 106 std::size_t numElems = (*elemTable).size() << 98 // Read data tables for all materials 107 for (std::size_t ie = 0; ie < numElems; ++ << 99 108 const G4Element* elem = (*elemTable)[ie] << 100 crossSectionHandler = new G4CrossSectionHandler(); 109 const G4int Z = std::min(maxZ, elem->Get << 101 crossSectionHandler->Initialise(0,lowEnergyLimit,100.*GeV,400); 110 if (data[Z] == nullptr) { << 102 G4String crossSectionFile = "pair/pp-cs-"; 111 ReadData(Z); << 103 crossSectionHandler->LoadData(crossSectionFile); 112 } << 104 113 } << 105 // 114 } << 106 115 if (isInitialised) { << 107 if (verboseLevel > 2) 116 return; << 108 G4cout << "Loaded cross section files for PenelopeGammaConversion" << G4endl; >> 109 >> 110 if (verboseLevel > 0) { >> 111 G4cout << "Livermore Gamma Conversion model is initialized " << G4endl >> 112 << "Energy range: " >> 113 << LowEnergyLimit() / MeV << " MeV - " >> 114 << HighEnergyLimit() / GeV << " GeV" >> 115 << G4endl; 117 } 116 } >> 117 >> 118 if(isInitialised) return; 118 fParticleChange = GetParticleChangeForGamma( 119 fParticleChange = GetParticleChangeForGamma(); 119 isInitialised = true; 120 isInitialised = true; 120 } 121 } 121 122 122 //....oooOO0OOooo........oooOO0OOooo........oo 123 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... 123 124 124 const G4String& G4LivermoreGammaConversionMode << 125 G4double >> 126 G4LivermoreGammaConversionModel::ComputeCrossSectionPerAtom(const G4ParticleDefinition*, >> 127 G4double GammaEnergy, >> 128 G4double Z, G4double, >> 129 G4double, G4double) 125 { 130 { 126 // no check in this method - environment var << 131 if (verboseLevel > 3) { 127 if (gDataDirectory.empty()) { << 132 G4cout << "Calling ComputeCrossSectionPerAtom() of G4LivermoreGammaConversionModel" 128 auto param = G4EmParameters::Instance(); << 133 << G4endl; 129 std::ostringstream ost; << 130 if (param->LivermoreDataDir() == "livermor << 131 ost << param->GetDirLEDATA() << "/liverm << 132 useSpline = true; << 133 } << 134 else { << 135 ost << param->GetDirLEDATA() << "/epics2 << 136 } << 137 gDataDirectory = ost.str(); << 138 } 134 } 139 return gDataDirectory; << 135 if (GammaEnergy < lowEnergyLimit || GammaEnergy > highEnergyLimit) return 0; >> 136 >> 137 G4double cs = crossSectionHandler->FindValue(G4int(Z), GammaEnergy); >> 138 return cs; 140 } 139 } 141 140 142 //....oooOO0OOooo........oooOO0OOooo........oo 141 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... 143 142 144 void G4LivermoreGammaConversionModel::ReadData << 143 void G4LivermoreGammaConversionModel::SampleSecondaries(std::vector<G4DynamicParticle*>* fvect, >> 144 const G4MaterialCutsCouple* couple, >> 145 const G4DynamicParticle* aDynamicGamma, >> 146 G4double, >> 147 G4double) 145 { 148 { 146 if (verboseLevel > 1) { << 147 G4cout << "Calling ReadData() of G4Livermo << 148 } << 149 << 150 if (data[Z] != nullptr) { << 151 return; << 152 } << 153 << 154 std::ostringstream ost; << 155 ost << FindDirectoryPath() << "pp-cs-" << Z << 156 149 157 data[Z] = new G4PhysicsFreeVector(useSpline) << 150 // The energies of the e+ e- secondaries are sampled using the Bethe - Heitler 158 << 151 // cross sections with Coulomb correction. A modified version of the random 159 std::ifstream fin(ost.str().c_str()); << 152 // number techniques of Butcher & Messel is used (Nuc Phys 20(1960),15). >> 153 >> 154 // Note 1 : Effects due to the breakdown of the Born approximation at low >> 155 // energy are ignored. >> 156 // Note 2 : The differential cross section implicitly takes account of >> 157 // pair creation in both nuclear and atomic electron fields. However triplet >> 158 // prodution is not generated. >> 159 >> 160 if (verboseLevel > 3) >> 161 G4cout << "Calling SampleSecondaries() of G4LivermoreGammaConversionModel" << G4endl; >> 162 >> 163 G4double photonEnergy = aDynamicGamma->GetKineticEnergy(); >> 164 G4ParticleMomentum photonDirection = aDynamicGamma->GetMomentumDirection(); >> 165 >> 166 G4double epsilon ; >> 167 G4double epsilon0 = electron_mass_c2 / photonEnergy ; >> 168 >> 169 // Do it fast if photon energy < 2. MeV >> 170 if (photonEnergy < smallEnergy ) >> 171 { >> 172 epsilon = epsilon0 + (0.5 - epsilon0) * G4UniformRand(); >> 173 } >> 174 else >> 175 { >> 176 // Select randomly one element in the current material >> 177 //const G4Element* element = crossSectionHandler->SelectRandomElement(couple,photonEnergy); >> 178 const G4ParticleDefinition* particle = aDynamicGamma->GetDefinition(); >> 179 const G4Element* element = SelectRandomAtom(couple,particle,photonEnergy); >> 180 >> 181 if (element == 0) >> 182 { >> 183 G4cout << "G4LivermoreGammaConversionModel::SampleSecondaries - element = 0" >> 184 << G4endl; >> 185 return; >> 186 } >> 187 G4IonisParamElm* ionisation = element->GetIonisation(); >> 188 if (ionisation == 0) >> 189 { >> 190 G4cout << "G4LivermoreGammaConversionModel::SampleSecondaries - ionisation = 0" >> 191 << G4endl; >> 192 return; >> 193 } >> 194 >> 195 // Extract Coulomb factor for this Element >> 196 G4double fZ = 8. * (ionisation->GetlogZ3()); >> 197 if (photonEnergy > 50. * MeV) fZ += 8. * (element->GetfCoulomb()); >> 198 >> 199 // Limits of the screening variable >> 200 G4double screenFactor = 136. * epsilon0 / (element->GetIonisation()->GetZ3()) ; >> 201 G4double screenMax = std::exp ((42.24 - fZ)/8.368) - 0.952 ; >> 202 G4double screenMin = std::min(4.*screenFactor,screenMax) ; >> 203 >> 204 // Limits of the energy sampling >> 205 G4double epsilon1 = 0.5 - 0.5 * std::sqrt(1. - screenMin / screenMax) ; >> 206 G4double epsilonMin = std::max(epsilon0,epsilon1); >> 207 G4double epsilonRange = 0.5 - epsilonMin ; >> 208 >> 209 // Sample the energy rate of the created electron (or positron) >> 210 G4double screen; >> 211 G4double gReject ; >> 212 >> 213 G4double f10 = ScreenFunction1(screenMin) - fZ; >> 214 G4double f20 = ScreenFunction2(screenMin) - fZ; >> 215 G4double normF1 = std::max(f10 * epsilonRange * epsilonRange,0.); >> 216 G4double normF2 = std::max(1.5 * f20,0.); >> 217 >> 218 do { >> 219 if (normF1 / (normF1 + normF2) > G4UniformRand() ) >> 220 { >> 221 epsilon = 0.5 - epsilonRange * std::pow(G4UniformRand(), 0.3333) ; >> 222 screen = screenFactor / (epsilon * (1. - epsilon)); >> 223 gReject = (ScreenFunction1(screen) - fZ) / f10 ; >> 224 } >> 225 else >> 226 { >> 227 epsilon = epsilonMin + epsilonRange * G4UniformRand(); >> 228 screen = screenFactor / (epsilon * (1 - epsilon)); >> 229 gReject = (ScreenFunction2(screen) - fZ) / f20 ; >> 230 } >> 231 } while ( gReject < G4UniformRand() ); >> 232 >> 233 } // End of epsilon sampling >> 234 >> 235 // Fix charges randomly >> 236 >> 237 G4double electronTotEnergy; >> 238 G4double positronTotEnergy; >> 239 >> 240 if (CLHEP::RandBit::shootBit()) >> 241 { >> 242 electronTotEnergy = (1. - epsilon) * photonEnergy; >> 243 positronTotEnergy = epsilon * photonEnergy; >> 244 } >> 245 else >> 246 { >> 247 positronTotEnergy = (1. - epsilon) * photonEnergy; >> 248 electronTotEnergy = epsilon * photonEnergy; >> 249 } 160 250 161 if (!fin.is_open()) { << 251 // Scattered electron (positron) angles. ( Z - axis along the parent photon) 162 G4ExceptionDescription ed; << 252 // Universal distribution suggested by L. Urban (Geant3 manual (1993) Phys211), 163 ed << "G4LivermoreGammaConversionModel dat << 253 // derived from Tsai distribution (Rev. Mod. Phys. 49, 421 (1977) 164 << G4endl; << 254 165 G4Exception("G4LivermoreGammaConversionMod << 255 G4double u; 166 "G4LEDATA version should be G4 << 256 const G4double a1 = 0.625; 167 return; << 257 G4double a2 = 3. * a1; 168 } << 258 // G4double d = 27. ; 169 else { << 259 170 if (verboseLevel > 1) { << 260 // if (9. / (9. + d) > G4UniformRand()) 171 G4cout << "File " << ost.str() << " is o << 261 if (0.25 > G4UniformRand()) >> 262 { >> 263 u = - std::log(G4UniformRand() * G4UniformRand()) / a1 ; >> 264 } >> 265 else >> 266 { >> 267 u = - std::log(G4UniformRand() * G4UniformRand()) / a2 ; 172 } 268 } 173 269 174 data[Z]->Retrieve(fin, true); << 270 G4double thetaEle = u*electron_mass_c2/electronTotEnergy; 175 } << 271 G4double thetaPos = u*electron_mass_c2/positronTotEnergy; 176 // Activation of spline interpolation << 272 G4double phi = twopi * G4UniformRand(); 177 if (useSpline) data[Z]->FillSecondDerivative << 273 >> 274 G4double dxEle= std::sin(thetaEle)*std::cos(phi),dyEle= std::sin(thetaEle)*std::sin(phi),dzEle=std::cos(thetaEle); >> 275 G4double dxPos=-std::sin(thetaPos)*std::cos(phi),dyPos=-std::sin(thetaPos)*std::sin(phi),dzPos=std::cos(thetaPos); >> 276 >> 277 >> 278 // Kinematics of the created pair: >> 279 // the electron and positron are assumed to have a symetric angular >> 280 // distribution with respect to the Z axis along the parent photon >> 281 >> 282 G4double electronKineEnergy = std::max(0.,electronTotEnergy - electron_mass_c2) ; >> 283 >> 284 // SI - The range test has been removed wrt original G4LowEnergyGammaconversion class >> 285 >> 286 G4ThreeVector electronDirection (dxEle, dyEle, dzEle); >> 287 electronDirection.rotateUz(photonDirection); >> 288 >> 289 G4DynamicParticle* particle1 = new G4DynamicParticle (G4Electron::Electron(), >> 290 electronDirection, >> 291 electronKineEnergy); >> 292 >> 293 // The e+ is always created (even with kinetic energy = 0) for further annihilation >> 294 G4double positronKineEnergy = std::max(0.,positronTotEnergy - electron_mass_c2) ; >> 295 >> 296 // SI - The range test has been removed wrt original G4LowEnergyGammaconversion class >> 297 >> 298 G4ThreeVector positronDirection (dxPos, dyPos, dzPos); >> 299 positronDirection.rotateUz(photonDirection); >> 300 >> 301 // Create G4DynamicParticle object for the particle2 >> 302 G4DynamicParticle* particle2 = new G4DynamicParticle(G4Positron::Positron(), >> 303 positronDirection, positronKineEnergy); >> 304 // Fill output vector >> 305 fvect->push_back(particle1); >> 306 fvect->push_back(particle2); >> 307 >> 308 // kill incident photon >> 309 fParticleChange->SetProposedKineticEnergy(0.); >> 310 fParticleChange->ProposeTrackStatus(fStopAndKill); >> 311 178 } 312 } 179 313 180 //....oooOO0OOooo........oooOO0OOooo........oo 314 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... 181 315 182 G4double << 316 G4double G4LivermoreGammaConversionModel::ScreenFunction1(G4double screenVariable) 183 G4LivermoreGammaConversionModel::ComputeCrossS << 184 << 185 << 186 { 317 { 187 if (verboseLevel > 1) { << 318 // Compute the value of the screening function 3*phi1 - phi2 188 G4cout << "G4LivermoreGammaConversionModel << 189 } << 190 << 191 if (GammaEnergy < lowEnergyLimit) { << 192 return 0.0; << 193 } << 194 319 195 G4double xs = 0.0; << 320 G4double value; >> 321 >> 322 if (screenVariable > 1.) >> 323 value = 42.24 - 8.368 * std::log(screenVariable + 0.952); >> 324 else >> 325 value = 42.392 - screenVariable * (7.796 - 1.961 * screenVariable); >> 326 >> 327 return value; >> 328 } 196 329 197 G4int intZ = std::max(1, std::min(G4lrint(Z) << 330 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... 198 << 199 G4PhysicsFreeVector* pv = data[intZ]; << 200 << 201 // if element was not initialised << 202 // do initialisation safely for MT mode << 203 if (pv == nullptr) { << 204 InitialiseForElement(particle, intZ); << 205 pv = data[intZ]; << 206 if (pv == nullptr) { << 207 return xs; << 208 } << 209 } << 210 // x-section is taken from the table << 211 xs = pv->Value(GammaEnergy); << 212 << 213 if (verboseLevel > 0) { << 214 G4cout << "*** Gamma conversion xs for Z=" << 215 << " cs=" << xs / millibarn << " m << 216 } << 217 return xs; << 218 } << 219 << 220 //....oooOO0OOooo........oooOO0OOooo........oo << 221 331 222 void G4LivermoreGammaConversionModel::Initiali << 332 G4double G4LivermoreGammaConversionModel::ScreenFunction2(G4double screenVariable) 223 { 333 { 224 G4AutoLock l(&LivermoreGammaConversionModelM << 334 // Compute the value of the screening function 1.5*phi1 - 0.5*phi2 225 if (data[Z] == nullptr) { << 335 226 ReadData(Z); << 336 G4double value; 227 } << 337 228 l.unlock(); << 338 if (screenVariable > 1.) 229 } << 339 value = 42.24 - 8.368 * std::log(screenVariable + 0.952); >> 340 else >> 341 value = 41.405 - screenVariable * (5.828 - 0.8945 * screenVariable); >> 342 >> 343 return value; >> 344 } 230 345 231 //....oooOO0OOooo........oooOO0OOooo........oo << 232 346