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: G4LivermorePhotoElectricModel.cc,v 1.9 2009/10/23 09:31:03 pandola Exp $ >> 27 // GEANT4 tag $Name: geant4-09-03-patch-01 $ 26 // 28 // 27 // Author: Sebastien Incerti << 29 // >> 30 // Author: Sebastien Inserti 28 // 30 October 2008 31 // 30 October 2008 29 // on base of G4LowEnergyPhotoElectric << 30 // 32 // 31 // 22 Oct 2012 A & V Ivanchenko Migration da << 33 // History: 32 // 1 June 2017 M Bandieramonte: New model ba << 34 // -------- 33 // evaluated data - parameteriza << 35 // 15 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 // - remove GetMeanFreePath method and table >> 39 // - simplify sampling of deexcitation by using cut in energy >> 40 // - added protection against numerical problem in energy sampling >> 41 // - use G4ElementSelector >> 42 // 23 Oct 2009 L Pandola >> 43 // - atomic deexcitation managed via G4VEmModel::DeexcitationFlag() is >> 44 // set as "true" (default would be false) >> 45 // 34 46 35 #include "G4LivermorePhotoElectricModel.hh" 47 #include "G4LivermorePhotoElectricModel.hh" 36 48 37 #include "G4AtomicShell.hh" << 38 #include "G4AutoLock.hh" << 39 #include "G4CrossSectionHandler.hh" << 40 #include "G4Electron.hh" << 41 #include "G4Gamma.hh" << 42 #include "G4LossTableManager.hh" << 43 #include "G4ParticleChangeForGamma.hh" << 44 #include "G4PhysicsFreeVector.hh" << 45 #include "G4SauterGavrilaAngularDistribution.h << 46 #include "G4SystemOfUnits.hh" << 47 #include "G4VAtomDeexcitation.hh" << 48 #include "G4EmParameters.hh" << 49 #include <thread> << 50 << 51 //....oooOO0OOooo........oooOO0OOooo........oo 49 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... 52 50 53 G4ElementData* G4LivermorePhotoElectricModel:: << 51 using namespace std; 54 G4ElementData* G4LivermorePhotoElectricModel:: << 55 std::vector<G4double>* G4LivermorePhotoElectri << 56 std::vector<G4double>* G4LivermorePhotoElectri << 57 G4int G4LivermorePhotoElectricModel::fNShells[ << 58 G4int G4LivermorePhotoElectricModel::fNShellsU << 59 G4Material* G4LivermorePhotoElectricModel::fWa << 60 G4double G4LivermorePhotoElectricModel::fWater << 61 G4String G4LivermorePhotoElectricModel::fDataD << 62 << 63 static std::once_flag applyOnce; << 64 << 65 namespace << 66 { << 67 G4Mutex livPhotoeffMutex = G4MUTEX_INITIALIZ << 68 } << 69 52 70 //....oooOO0OOooo........oooOO0OOooo........oo 53 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... 71 54 72 G4LivermorePhotoElectricModel::G4LivermorePhot << 55 G4LivermorePhotoElectricModel::G4LivermorePhotoElectricModel(const G4ParticleDefinition*, >> 56 const G4String& nam) >> 57 :G4VEmModel(nam),isInitialised(false),meanFreePathTable(0), >> 58 crossSectionHandler(0),shellCrossSectionHandler(0),ElectronAngularGenerator(0) 73 { 59 { 74 verboseLevel = 0; << 60 lowEnergyLimit = 250 * eV; >> 61 highEnergyLimit = 100 * GeV; >> 62 // SetLowEnergyLimit(lowEnergyLimit); >> 63 SetHighEnergyLimit(highEnergyLimit); >> 64 >> 65 //Set atomic deexcitation by default >> 66 SetDeexcitationFlag(true); >> 67 ActivateAuger(false); >> 68 >> 69 verboseLevel= 0; 75 // Verbosity scale: 70 // Verbosity scale: 76 // 0 = nothing << 71 // 0 = nothing 77 // 1 = warning for energy non-conservation << 72 // 1 = warning for energy non-conservation 78 // 2 = details of energy budget 73 // 2 = details of energy budget 79 // 3 = calculation of cross sections, file o 74 // 3 = calculation of cross sections, file openings, sampling of atoms 80 // 4 = entering in methods 75 // 4 = entering in methods 81 << 76 if(verboseLevel>0) { 82 theGamma = G4Gamma::Gamma(); << 77 G4cout << "Livermore PhotoElectric is constructed " << G4endl 83 theElectron = G4Electron::Electron(); << 78 << "Energy range: " 84 << 79 << lowEnergyLimit / eV << " eV - " 85 // default generator << 80 << highEnergyLimit / GeV << " GeV" 86 SetAngularDistribution(new G4SauterGavrilaAn << 81 << G4endl; 87 << 88 if (verboseLevel > 0) { << 89 G4cout << "Livermore PhotoElectric is cons << 90 << " nShellLimit= " << nShellLimit << 91 } 82 } 92 << 93 // Mark this model as "applicable" for atomi << 94 SetDeexcitationFlag(true); << 95 << 96 // For water << 97 fSandiaCof.resize(4, 0.0); << 98 } 83 } 99 84 100 //....oooOO0OOooo........oooOO0OOooo........oo 85 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... 101 86 102 G4LivermorePhotoElectricModel::~G4LivermorePho 87 G4LivermorePhotoElectricModel::~G4LivermorePhotoElectricModel() 103 { << 88 { 104 if (isInitializer) { << 89 if (crossSectionHandler) delete crossSectionHandler; 105 for (G4int i = 0; i < ZMAXPE; ++i) { << 90 if (shellCrossSectionHandler) delete shellCrossSectionHandler; 106 if (fParamHigh[i]) { << 91 if (ElectronAngularGenerator) delete ElectronAngularGenerator; 107 delete fParamHigh[i]; << 108 fParamHigh[i] = nullptr; << 109 } << 110 if (fParamLow[i]) { << 111 delete fParamLow[i]; << 112 fParamLow[i] = nullptr; << 113 } << 114 } << 115 } << 116 } 92 } 117 93 118 //....oooOO0OOooo........oooOO0OOooo........oo 94 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... 119 95 120 void G4LivermorePhotoElectricModel::Initialise << 96 void 121 const G4DataVector&) << 97 G4LivermorePhotoElectricModel::Initialise(const G4ParticleDefinition*, >> 98 const G4DataVector&) 122 { 99 { 123 if (verboseLevel > 1) { << 100 if (verboseLevel > 3) 124 G4cout << "Calling G4LivermorePhotoElectri << 101 G4cout << "Calling G4LivermorePhotoElectricModel::Initialise()" << G4endl; 125 } << 126 102 127 // initialise static tables only once << 103 if (crossSectionHandler) 128 std::call_once(applyOnce, [this]() { isIniti << 104 { 129 << 105 crossSectionHandler->Clear(); 130 if (isInitializer) { << 106 delete crossSectionHandler; 131 G4AutoLock l(&livPhotoeffMutex); << 132 FindDirectoryPath(); << 133 if (fWater == nullptr) { << 134 fWater = G4Material::GetMaterial("G4_WAT << 135 if (fWater == nullptr) { << 136 fWater = G4Material::GetMaterial("Wate << 137 } << 138 if (fWater != nullptr) { << 139 fWaterEnergyLimit = 13.6 * CLHEP::eV; << 140 } << 141 } << 142 << 143 if (fCrossSection == nullptr) { << 144 fCrossSection = new G4ElementData(ZMAXPE << 145 fCrossSection->SetName("PhotoEffXS"); << 146 fCrossSectionLE = new G4ElementData(ZMAX << 147 fCrossSectionLE->SetName("PhotoEffLowXS" << 148 } << 149 << 150 const G4ElementTable* elemTable = G4Elemen << 151 std::size_t numElems = (*elemTable).size() << 152 for (std::size_t ie = 0; ie < numElems; ++ << 153 const G4Element* elem = (*elemTable)[ie] << 154 G4int Z = elem->GetZasInt(); << 155 if (Z < ZMAXPE) { << 156 if (fCrossSection->GetElementData(Z) == null << 157 ReadData(Z); << 158 } << 159 } << 160 } << 161 l.unlock(); << 162 } << 163 << 164 if (verboseLevel > 1) { << 165 G4cout << "Loaded cross section files for << 166 } 107 } 167 if (nullptr == fParticleChange) { << 108 168 fParticleChange = GetParticleChangeForGamm << 109 if (shellCrossSectionHandler) 169 fAtomDeexcitation = G4LossTableManager::In << 110 { >> 111 shellCrossSectionHandler->Clear(); >> 112 delete shellCrossSectionHandler; 170 } 113 } >> 114 >> 115 // Read data tables for all materials >> 116 >> 117 crossSectionHandler = new G4CrossSectionHandler(); >> 118 crossSectionHandler->Clear(); >> 119 G4String crossSectionFile = "phot/pe-cs-"; >> 120 crossSectionHandler->LoadData(crossSectionFile); 171 121 172 fDeexcitationActive = false; << 122 shellCrossSectionHandler = new G4CrossSectionHandler(); 173 if (nullptr != fAtomDeexcitation) { << 123 shellCrossSectionHandler->Clear(); 174 fDeexcitationActive = fAtomDeexcitation->I << 124 G4String shellCrossSectionFile = "phot/pe-ss-cs-"; 175 } << 125 shellCrossSectionHandler->LoadShellData(shellCrossSectionFile); >> 126 >> 127 // SI - Simple generator is buggy >> 128 //generatorName = "geant4.6.2"; >> 129 //ElectronAngularGenerator = new G4PhotoElectricAngularGeneratorSimple("GEANTSimpleGenerator"); // default generator >> 130 ElectronAngularGenerator = >> 131 new G4PhotoElectricAngularGeneratorSauterGavrila("GEANTSauterGavrilaGenerator"); 176 132 177 if (verboseLevel > 1) { << 133 // 178 G4cout << "LivermorePhotoElectric model is << 134 if (verboseLevel > 2) 179 } << 135 G4cout << "Loaded cross section files for Livermore PhotoElectric model" << G4endl; 180 } << 181 136 182 //....oooOO0OOooo........oooOO0OOooo........oo << 137 // InitialiseElementSelectors(particle,cuts); 183 138 184 G4double << 139 if (verboseLevel > 0) { 185 G4LivermorePhotoElectricModel::CrossSectionPer << 140 G4cout << "Livermore PhotoElectric model is initialized " << G4endl 186 << 141 << "Energy range: " 187 << 142 << LowEnergyLimit() / eV << " eV - " 188 G4double, G4double) << 143 << HighEnergyLimit() / GeV << " GeV" 189 { << 144 << G4endl; 190 fCurrSection = 0.0; << 191 if (fWater && (material == fWater || materia << 192 if (energy <= fWaterEnergyLimit) { << 193 fWater->GetSandiaTable()->GetSandiaCofWa << 194 << 195 G4double energy2 = energy * energy; << 196 G4double energy3 = energy * energy2; << 197 G4double energy4 = energy2 * energy2; << 198 << 199 fCurrSection = material->GetDensity() << 200 * (fSandiaCof[0] / energy << 201 fSandiaCof[2] / energy3 + fSandiaCof[3] << 202 } << 203 } 145 } 204 if (0.0 == fCurrSection) { << 146 205 fCurrSection = G4VEmModel::CrossSectionPer << 147 if(isInitialised) return; 206 } << 148 fParticleChange = GetParticleChangeForGamma(); 207 return fCurrSection; << 149 isInitialised = true; 208 } 150 } 209 151 210 //....oooOO0OOooo........oooOO0OOooo........oo 152 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... 211 153 212 G4double << 154 G4double G4LivermorePhotoElectricModel::ComputeCrossSectionPerAtom( 213 G4LivermorePhotoElectricModel::ComputeCrossSec << 155 const G4ParticleDefinition*, 214 << 156 G4double GammaEnergy, 215 G4double ZZ, G4double, << 157 G4double Z, G4double, 216 G4double, G4double) << 158 G4double, G4double) 217 { 159 { 218 if (verboseLevel > 3) { << 160 if (verboseLevel > 3) 219 G4cout << "\n G4LivermorePhotoElectricMode << 161 G4cout << "Calling ComputeCrossSectionPerAtom() of G4LivermorePhotoElectricModel" 220 << " Z= " << ZZ << " R(keV)= " << << 162 << G4endl; 221 } << 222 G4double cs = 0.0; << 223 G4int Z = G4lrint(ZZ); << 224 if (Z >= ZMAXPE || Z <= 0) { << 225 return cs; << 226 } << 227 // if element was not initialised << 228 << 229 // do initialisation safely for MT mode << 230 if (fCrossSection->GetElementData(Z) == null << 231 InitialiseOnFly(Z); << 232 if (fCrossSection->GetElementData(Z) == nu << 233 } << 234 163 235 // 7: rows in the parameterization file; 5: << 164 if (GammaEnergy < lowEnergyLimit || GammaEnergy > highEnergyLimit) 236 G4int idx = fNShells[Z] * 7 - 5; << 165 return 0; 237 166 238 energy = std::max(energy, (*(fParamHigh[Z])) << 167 G4double cs = crossSectionHandler->FindValue(G4int(Z), GammaEnergy); 239 << 240 G4double x1 = 1.0 / energy; << 241 G4double x2 = x1 * x1; << 242 G4double x3 = x2 * x1; << 243 << 244 // high energy parameterisation << 245 if (energy >= (*(fParamHigh[Z]))[0]) { << 246 G4double x4 = x2 * x2; << 247 G4double x5 = x4 * x1; << 248 << 249 cs = x1 * << 250 ((*(fParamHigh[Z]))[idx] + x1 * (*(fPara << 251 + x2 * (*(fParamHigh[Z]))[idx + 2] + x3 << 252 + x4 * (*(fParamHigh[Z]))[idx + 4] + x5 << 253 } << 254 // low energy parameterisation << 255 else if (energy >= (*(fParamLow[Z]))[0]) { << 256 G4double x4 = x2 * x2; << 257 G4double x5 = x4 * x1; // this variable u << 258 cs = x1 * << 259 ((*(fParamLow[Z]))[idx] + x1 * (*(fParam << 260 + x2 * (*(fParamLow[Z]))[idx + 2] + x3 << 261 + x4 * (*(fParamLow[Z]))[idx + 4] + x5 << 262 } << 263 // Tabulated values above k-shell ionization << 264 else if (energy >= (*(fParamHigh[Z]))[1]) { << 265 cs = x3 * (fCrossSection->GetElementData(Z << 266 } << 267 // Tabulated values below k-shell ionization << 268 else { << 269 cs = x3 * (fCrossSectionLE->GetElementData << 270 } << 271 if (verboseLevel > 1) { << 272 G4cout << "G4LivermorePhotoElectricModel: << 273 << " cross(barn)= " << cs / barn << << 274 } << 275 return cs; 168 return cs; 276 } 169 } 277 170 278 //....oooOO0OOooo........oooOO0OOooo........oo 171 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... 279 172 280 void G4LivermorePhotoElectricModel::SampleSeco << 173 void 281 << 174 G4LivermorePhotoElectricModel::SampleSecondaries(std::vector<G4DynamicParticle*>* fvect, 282 << 175 const G4MaterialCutsCouple* couple, 283 << 176 const G4DynamicParticle* aDynamicGamma, 284 { << 177 G4double, 285 G4double gammaEnergy = aDynamicGamma->GetKin << 178 G4double) 286 if (verboseLevel > 3) { << 179 { 287 G4cout << "G4LivermorePhotoElectricModel:: << 180 288 << gammaEnergy / keV << G4endl; << 181 // Fluorescence generated according to: 289 } << 182 // J. Stepanek ,"A program to determine the radiation spectra due to a single atomic >> 183 // subshell ionisation by a particle or due to deexcitation or decay of radionuclides", >> 184 // Comp. Phys. Comm. 1206 pp 1-1-9 (1997) >> 185 >> 186 if (verboseLevel > 3) >> 187 G4cout << "Calling SampleSecondaries() of G4LivermorePhotoElectricModel" << G4endl; 290 188 >> 189 G4double photonEnergy = aDynamicGamma->GetKineticEnergy(); >> 190 291 // kill incident photon 191 // kill incident photon 292 fParticleChange->ProposeTrackStatus(fStopAnd << 293 fParticleChange->SetProposedKineticEnergy(0. 192 fParticleChange->SetProposedKineticEnergy(0.); >> 193 fParticleChange->ProposeTrackStatus(fStopAndKill); 294 194 295 // low-energy photo-effect in water - full a << 195 // low-energy gamma is absorpted by this process 296 const G4Material* material = couple->GetMate << 196 if (photonEnergy <= lowEnergyLimit) 297 if (fWater && (material == fWater || materia << 197 { 298 if (gammaEnergy <= fWaterEnergyLimit) { << 198 fParticleChange->ProposeLocalEnergyDeposit(photonEnergy); 299 fParticleChange->ProposeLocalEnergyDepos << 300 return; 199 return; 301 } 200 } 302 } << 201 303 << 304 // Returns the normalized direction of the m 202 // Returns the normalized direction of the momentum 305 G4ThreeVector photonDirection = aDynamicGamm << 203 G4ThreeVector photonDirection = aDynamicGamma->GetMomentumDirection(); 306 204 307 // Select randomly one element in the curren 205 // Select randomly one element in the current material 308 const G4Element* elm = SelectRandomAtom(mate << 206 // G4int Z = crossSectionHandler->SelectRandomAtom(couple,photonEnergy); 309 G4int Z = elm->GetZasInt(); << 207 const G4ParticleDefinition* particle = aDynamicGamma->GetDefinition(); >> 208 const G4Element* elm = SelectRandomAtom(couple->GetMaterial(),particle,photonEnergy); >> 209 G4int Z = (G4int)elm->GetZ(); >> 210 >> 211 // Select the ionised shell in the current atom according to shell cross sections >> 212 size_t shellIndex = shellCrossSectionHandler->SelectRandomShell(Z,photonEnergy); >> 213 >> 214 // Retrieve the corresponding identifier and binding energy of the selected shell >> 215 const G4AtomicTransitionManager* transitionManager = G4AtomicTransitionManager::Instance(); >> 216 const G4AtomicShell* shell = transitionManager->Shell(Z,shellIndex); >> 217 G4double bindingEnergy = shell->BindingEnergy(); >> 218 G4int shellId = shell->ShellId(); 310 219 311 // Select the ionised shell in the current a << 220 // Primary outcoming electron 312 // cross sections << 221 G4double eKineticEnergy = photonEnergy - bindingEnergy; 313 222 314 // If element was not initialised gamma shou << 223 // There may be cases where the binding energy of the selected shell is > photon energy 315 if (Z >= ZMAXPE || fCrossSection->GetElement << 224 // In such cases do not generate secondaries 316 fParticleChange->ProposeLocalEnergyDeposit << 225 if (eKineticEnergy > 0.) 317 return; << 226 { 318 } << 227 // Calculate direction of the photoelectron >> 228 G4ThreeVector gammaPolarization = aDynamicGamma->GetPolarization(); >> 229 G4ThreeVector electronDirection = >> 230 ElectronAngularGenerator->GetPhotoElectronDirection(photonDirection, >> 231 eKineticEnergy, >> 232 gammaPolarization, >> 233 shellId); 319 234 320 // SAMPLING OF THE SHELL INDEX << 235 // The electron is created ... 321 std::size_t shellIdx = 0; << 236 G4DynamicParticle* electron = new G4DynamicParticle (G4Electron::Electron(), 322 std::size_t nn = fNShellsUsed[Z]; << 237 electronDirection, 323 if (nn > 1) { << 238 eKineticEnergy); 324 if (gammaEnergy >= (*(fParamHigh[Z]))[0]) << 239 fvect->push_back(electron); 325 G4double x1 = 1.0 / gammaEnergy; << 326 G4double x2 = x1 * x1; << 327 G4double x3 = x2 * x1; << 328 G4double x4 = x3 * x1; << 329 G4double x5 = x4 * x1; << 330 std::size_t idx = nn * 7 - 5; << 331 // when do sampling common factors are n << 332 // so cross section is not real << 333 << 334 G4double rand = G4UniformRand(); << 335 G4double cs0 = rand * << 336 ((*(fParamHigh[Z]))[idx] + x1 * (*(fPa << 337 + x2 * (*(fParamHigh[Z]))[idx + 2] + x << 338 + x4 * (*(fParamHigh[Z]))[idx + 4] + x << 339 << 340 for (shellIdx = 0; shellIdx < nn; ++shel << 341 idx = shellIdx * 7 + 2; << 342 if (gammaEnergy > (*(fParamHigh[Z]))[i << 343 G4double cs = (*(fParamHigh[Z]))[idx << 344 + x2 * (*(fParamHigh[Z]))[idx + 2] << 345 + x4 * (*(fParamHigh[Z]))[idx + 4] << 346 << 347 if (cs >= cs0) { << 348 break; << 349 } << 350 } << 351 } << 352 if (shellIdx >= nn) { << 353 shellIdx = nn - 1; << 354 } << 355 } 240 } 356 else if (gammaEnergy >= (*(fParamLow[Z]))[ << 241 else 357 G4double x1 = 1.0 / gammaEnergy; << 242 { 358 G4double x2 = x1 * x1; << 243 bindingEnergy = photonEnergy; 359 G4double x3 = x2 * x1; << 360 G4double x4 = x3 * x1; << 361 G4double x5 = x4 * x1; << 362 std::size_t idx = nn * 7 - 5; << 363 // when do sampling common factors are n << 364 // so cross section is not real << 365 G4double cs0 = G4UniformRand() * << 366 ((*(fParamLow[Z]))[idx] + x1 * (*(fPar << 367 + x2 * (*(fParamLow[Z]))[idx + 2] + x3 << 368 + x4 * (*(fParamLow[Z]))[idx + 4] + x5 << 369 for (shellIdx = 0; shellIdx < nn; ++shel << 370 idx = shellIdx * 7 + 2; << 371 if (gammaEnergy > (*(fParamLow[Z]))[id << 372 G4double cs = (*(fParamLow[Z]))[idx] << 373 + x2 * (*(fParamLow[Z]))[idx + 2] << 374 + x4 * (*(fParamLow[Z]))[idx + 4] << 375 if (cs >= cs0) { << 376 break; << 377 } << 378 } << 379 } << 380 if (shellIdx >= nn) { << 381 shellIdx = nn - 1; << 382 } << 383 } 244 } 384 else { << 385 // when do sampling common factors are n << 386 // so cross section is not real << 387 G4double cs = G4UniformRand(); << 388 << 389 if (gammaEnergy >= (*(fParamHigh[Z]))[1] << 390 // above K-shell binding energy << 391 cs *= fCrossSection->GetElementData(Z) << 392 } << 393 else { << 394 // below K-shell binding energy << 395 cs *= fCrossSectionLE->GetElementData( << 396 } << 397 245 398 for (G4int j = 0; j < (G4int)nn; ++j) { << 246 // deexcitation 399 shellIdx = (std::size_t)fCrossSection- << 247 if(DeexcitationFlag() && Z > 5) { 400 if (gammaEnergy > (*(fParamLow[Z]))[7 << 401 cs -= fCrossSection->GetValueForComp << 402 } << 403 if (cs <= 0.0 || j + 1 == (G4int)nn) { << 404 break; << 405 } << 406 } << 407 } << 408 } << 409 // END: SAMPLING OF THE SHELL << 410 << 411 G4double bindingEnergy = (*(fParamHigh[Z]))[ << 412 const G4AtomicShell* shell = nullptr; << 413 248 414 // no de-excitation from the last shell << 249 const G4ProductionCutsTable* theCoupleTable= 415 if (fDeexcitationActive && shellIdx + 1 < nn << 250 G4ProductionCutsTable::GetProductionCutsTable(); 416 auto as = G4AtomicShellEnumerator(shellIdx << 417 shell = fAtomDeexcitation->GetAtomicShell( << 418 } << 419 << 420 // If binding energy of the selected shell i << 421 // do not generate secondaries << 422 if (gammaEnergy < bindingEnergy) { << 423 fParticleChange->ProposeLocalEnergyDeposit << 424 return; << 425 } << 426 251 427 // Primary outcoming electron << 252 size_t index = couple->GetIndex(); 428 G4double eKineticEnergy = gammaEnergy - bind << 253 G4double cutg = (*(theCoupleTable->GetEnergyCutsVector(0)))[index]; 429 G4double edep = bindingEnergy; << 254 G4double cute = (*(theCoupleTable->GetEnergyCutsVector(1)))[index]; 430 255 431 // Calculate direction of the photoelectron << 256 // Generation of fluorescence 432 G4ThreeVector electronDirection = GetAngular << 257 // Data in EADL are available only for Z > 5 433 aDynamicGamma, eKineticEnergy, (G4int)shel << 258 // Protection to avoid generating photons in the unphysical case of 434 << 259 // shell binding energy > photon energy 435 // The electron is created << 260 if (bindingEnergy > cutg || bindingEnergy > cute) 436 auto electron = << 261 { 437 new G4DynamicParticle(theElectron, electro << 262 G4DynamicParticle* aPhoton; 438 fvect->push_back(electron); << 263 deexcitationManager.SetCutForSecondaryPhotons(cutg); 439 << 264 deexcitationManager.SetCutForAugerElectrons(cute); 440 // Sample deexcitation << 265 441 if (nullptr != shell) { << 266 std::vector<G4DynamicParticle*>* photonVector = 442 G4int index = couple->GetIndex(); << 267 deexcitationManager.GenerateParticles(Z,shellId); 443 if (fAtomDeexcitation->CheckDeexcitationAc << 268 size_t nTotPhotons = photonVector->size(); 444 std::size_t nbefore = fvect->size(); << 269 for (size_t k=0; k<nTotPhotons; k++) 445 << 270 { 446 fAtomDeexcitation->GenerateParticles(fve << 271 aPhoton = (*photonVector)[k]; 447 std::size_t nafter = fvect->size(); << 272 if (aPhoton) 448 if (nafter > nbefore) { << 273 { 449 G4double esec = 0.0; << 274 G4double itsEnergy = aPhoton->GetKineticEnergy(); 450 for (std::size_t j = nbefore; j < naft << 275 if (itsEnergy <= bindingEnergy) 451 G4double e = ((*fvect)[j])->GetKinet << 276 { 452 if (esec + e > edep) { << 277 // Local energy deposit is given as the sum of the 453 // correct energy in order to have << 278 // energies of incident photons minus the energies 454 e = edep - esec; << 279 // of the outcoming fluorescence photons 455 ((*fvect)[j])->SetKineticEnergy(e) << 280 bindingEnergy -= itsEnergy; 456 esec += e; << 281 fvect->push_back(aPhoton); 457 // delete the rest of secondaries << 282 } 458 for (std::size_t jj = nafter - 1; << 283 else 459 delete (*fvect)[jj]; << 284 { 460 fvect->pop_back(); << 285 // abnormal case of energy non-conservation 461 } << 286 delete aPhoton; 462 break; << 287 (*photonVector)[k] = 0; 463 } << 288 } 464 esec += e; << 289 } 465 } << 290 } 466 edep -= esec; << 291 delete photonVector; 467 } 292 } 468 } << 469 } << 470 // energy balance - excitation energy left << 471 if (edep > 0.0) { << 472 fParticleChange->ProposeLocalEnergyDeposit << 473 } 293 } >> 294 // excitation energy left >> 295 fParticleChange->ProposeLocalEnergyDeposit(bindingEnergy); 474 } 296 } 475 297 476 //....oooOO0OOooo........oooOO0OOooo........oo 298 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... 477 299 478 const G4String& G4LivermorePhotoElectricModel: << 300 void G4LivermorePhotoElectricModel::SetCutForLowEnSecPhotons(G4double cut) 479 { 301 { 480 // no check in this method - environment var << 302 cutForLowEnergySecondaryPhotons = cut; 481 if (fDataDirectory.empty()) { << 303 deexcitationManager.SetCutForSecondaryPhotons(cut); 482 auto param = G4EmParameters::Instance(); << 483 std::ostringstream ost; << 484 if (param->LivermoreDataDir() == "livermor << 485 ost << param->GetDirLEDATA() << "/liverm << 486 } << 487 else { << 488 ost << param->GetDirLEDATA() << "/epics2 << 489 } << 490 fDataDirectory = ost.str(); << 491 } << 492 return fDataDirectory; << 493 } 304 } 494 305 495 //....oooOO0OOooo........oooOO0OOooo........oo 306 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... 496 307 497 void G4LivermorePhotoElectricModel::ReadData(G << 308 void G4LivermorePhotoElectricModel::SetCutForLowEnSecElectrons(G4double cut) 498 { 309 { 499 if (Z <= 0 || Z >= ZMAXPE) { << 310 cutForLowEnergySecondaryElectrons = cut; 500 G4cout << "G4LivermorePhotoElectricModel:: << 311 deexcitationManager.SetCutForAugerElectrons(cut); 501 << Z << " is out of range - request ignor << 502 return; << 503 } << 504 if (verboseLevel > 1) { << 505 G4cout << "G4LivermorePhotoElectricModel:: << 506 } << 507 << 508 if (fCrossSection->GetElementData(Z) != null << 509 return; << 510 } << 511 << 512 // spline for photoeffect total x-section ab << 513 // but below the parameterized ones << 514 << 515 G4bool spline = (G4EmParameters::Instance()- << 516 G4int number = G4EmParameters::Instance()->N << 517 auto pv = new G4PhysicsFreeVector(spline); << 518 << 519 // fDataDirectory will be defined after thes << 520 std::ostringstream ost; << 521 ost << FindDirectoryPath() << "pe-cs-" << Z << 522 std::ifstream fin(ost.str().c_str()); << 523 if (!fin.is_open()) { << 524 G4ExceptionDescription ed; << 525 ed << "G4LivermorePhotoElectricModel data << 526 << ost.str().c_str() << "> is not opene << 527 G4Exception("G4LivermorePhotoElectricModel << 528 "G4LEDATA version should be G4 << 529 return; << 530 } << 531 if (verboseLevel > 3) { << 532 G4cout << "File " << ost.str().c_str() << << 533 << G4endl; << 534 } << 535 pv->Retrieve(fin, true); << 536 pv->ScaleVector(MeV, barn); << 537 pv->FillSecondDerivatives(); << 538 pv->EnableLogBinSearch(number); << 539 fCrossSection->InitialiseForElement(Z, pv); << 540 fin.close(); << 541 << 542 // read high-energy fit parameters << 543 fParamHigh[Z] = new std::vector<G4double>; << 544 G4int n1 = 0; << 545 G4int n2 = 0; << 546 G4double x; << 547 std::ostringstream ost1; << 548 ost1 << fDataDirectory << "pe-high-" << Z << << 549 std::ifstream fin1(ost1.str().c_str()); << 550 if (!fin1.is_open()) { << 551 G4ExceptionDescription ed; << 552 ed << "G4LivermorePhotoElectricModel data << 553 << ost1.str().c_str() << "> is not open << 554 G4Exception("G4LivermorePhotoElectricModel << 555 "G4LEDATA version should be G4 << 556 return; << 557 } << 558 if (verboseLevel > 3) { << 559 G4cout << "File " << ost1.str().c_str() << << 560 << G4endl; << 561 } << 562 fin1 >> n1; << 563 if (fin1.fail()) { << 564 return; << 565 } << 566 if (0 > n1 || n1 >= INT_MAX) { << 567 n1 = 0; << 568 } << 569 << 570 fin1 >> n2; << 571 if (fin1.fail()) { << 572 return; << 573 } << 574 if (0 > n2 || n2 >= INT_MAX) { << 575 n2 = 0; << 576 } << 577 << 578 fin1 >> x; << 579 if (fin1.fail()) { << 580 return; << 581 } << 582 << 583 fNShells[Z] = n1; << 584 fParamHigh[Z]->reserve(7 * n1 + 1); << 585 fParamHigh[Z]->push_back(x * MeV); << 586 for (G4int i = 0; i < n1; ++i) { << 587 for (G4int j = 0; j < 7; ++j) { << 588 fin1 >> x; << 589 if (0 == j) { << 590 x *= MeV; << 591 } << 592 else { << 593 x *= barn; << 594 } << 595 fParamHigh[Z]->push_back(x); << 596 } << 597 } << 598 fin1.close(); << 599 << 600 // read low-energy fit parameters << 601 fParamLow[Z] = new std::vector<G4double>; << 602 G4int n1_low = 0; << 603 G4int n2_low = 0; << 604 G4double x_low; << 605 std::ostringstream ost1_low; << 606 ost1_low << fDataDirectory << "pe-low-" << Z << 607 std::ifstream fin1_low(ost1_low.str().c_str( << 608 if (!fin1_low.is_open()) { << 609 G4ExceptionDescription ed; << 610 ed << "G4LivermorePhotoElectricModel data << 611 << "> is not opened!" << G4endl; << 612 G4Exception("G4LivermorePhotoElectricModel << 613 "G4LEDATA version should be G4 << 614 return; << 615 } << 616 if (verboseLevel > 3) { << 617 G4cout << "File " << ost1_low.str().c_str( << 618 << G4endl; << 619 } << 620 fin1_low >> n1_low; << 621 if (fin1_low.fail()) { << 622 return; << 623 } << 624 if (0 > n1_low || n1_low >= INT_MAX) { << 625 n1_low = 0; << 626 } << 627 << 628 fin1_low >> n2_low; << 629 if (fin1_low.fail()) { << 630 return; << 631 } << 632 if (0 > n2_low || n2_low >= INT_MAX) { << 633 n2_low = 0; << 634 } << 635 << 636 fin1_low >> x_low; << 637 if (fin1_low.fail()) { << 638 return; << 639 } << 640 << 641 fNShells[Z] = n1_low; << 642 fParamLow[Z]->reserve(7 * n1_low + 1); << 643 fParamLow[Z]->push_back(x_low * MeV); << 644 for (G4int i = 0; i < n1_low; ++i) { << 645 for (G4int j = 0; j < 7; ++j) { << 646 fin1_low >> x_low; << 647 if (0 == j) { << 648 x_low *= MeV; << 649 } << 650 else { << 651 x_low *= barn; << 652 } << 653 fParamLow[Z]->push_back(x_low); << 654 } << 655 } << 656 fin1_low.close(); << 657 << 658 // there is a possibility to use only main s << 659 if (nShellLimit < n2) { << 660 n2 = nShellLimit; << 661 } << 662 fCrossSection->InitialiseForComponent(Z, n2) << 663 fNShellsUsed[Z] = n2; << 664 << 665 if (1 < n2) { << 666 std::ostringstream ost2; << 667 ost2 << fDataDirectory << "pe-ss-cs-" << Z << 668 std::ifstream fin2(ost2.str().c_str()); << 669 if (!fin2.is_open()) { << 670 G4ExceptionDescription ed; << 671 ed << "G4LivermorePhotoElectricModel dat << 672 << G4endl; << 673 G4Exception("G4LivermorePhotoElectricMod << 674 "G4LEDATA version should be << 675 return; << 676 } << 677 if (verboseLevel > 3) { << 678 G4cout << "File " << ost2.str().c_str() << 679 << G4endl; << 680 } << 681 << 682 G4int n3, n4; << 683 G4double y; << 684 for (G4int i = 0; i < n2; ++i) { << 685 fin2 >> x >> y >> n3 >> n4; << 686 auto v = new G4PhysicsFreeVector(n3, x, << 687 for (G4int j = 0; j < n3; ++j) { << 688 fin2 >> x >> y; << 689 v->PutValues(j, x * CLHEP::MeV, y * CL << 690 } << 691 v->EnableLogBinSearch(number); << 692 fCrossSection->AddComponent(Z, n4, v); << 693 } << 694 fin2.close(); << 695 } << 696 << 697 // no spline for photoeffect total x-section << 698 if (1 < fNShells[Z]) { << 699 auto pv1 = new G4PhysicsFreeVector(false); << 700 std::ostringstream ost3; << 701 ost3 << fDataDirectory << "pe-le-cs-" << Z << 702 std::ifstream fin3(ost3.str().c_str()); << 703 if (!fin3.is_open()) { << 704 G4ExceptionDescription ed; << 705 ed << "G4LivermorePhotoElectricModel dat << 706 << G4endl; << 707 G4Exception("G4LivermorePhotoElectricMod << 708 "G4LEDATA version should be << 709 return; << 710 } << 711 if (verboseLevel > 3) { << 712 G4cout << "File " << ost3.str().c_str() << 713 << G4endl; << 714 } << 715 pv1->Retrieve(fin3, true); << 716 pv1->ScaleVector(CLHEP::MeV, CLHEP::barn); << 717 pv1->EnableLogBinSearch(number); << 718 fCrossSectionLE->InitialiseForElement(Z, p << 719 fin3.close(); << 720 } << 721 } 312 } 722 313 723 //....oooOO0OOooo........oooOO0OOooo........oo 314 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... 724 315 725 G4double G4LivermorePhotoElectricModel::GetBin << 316 void G4LivermorePhotoElectricModel::ActivateAuger(G4bool val) 726 { 317 { 727 if (Z < 1 || Z >= ZMAXPE) { << 318 deexcitationManager.ActivateAugerElectronProduction(val); 728 return -1; << 729 } // If Z is out of the supported return 0 << 730 << 731 InitialiseOnFly(Z); << 732 if (fCrossSection->GetElementData(Z) == null << 733 shell < 0 || shell >= fNShellsUsed[Z]) { << 734 return -1; << 735 } << 736 << 737 if (Z > 2) { << 738 return fCrossSection->GetComponentDataByIn << 739 } << 740 else { << 741 return fCrossSection->GetElementData(Z)->E << 742 } << 743 } 319 } 744 320 745 //....oooOO0OOooo........oooOO0OOooo........oo << 321 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... 746 322 747 void << 323 void 748 G4LivermorePhotoElectricModel::InitialiseForEl << 324 G4LivermorePhotoElectricModel::SetAngularGenerator(G4VPhotoElectricAngularDistribution* dist) 749 { 325 { 750 if (fCrossSection == nullptr) { << 326 ElectronAngularGenerator = dist; 751 fCrossSection = new G4ElementData(ZMAXPE); << 327 ElectronAngularGenerator->PrintGeneratorInformation(); 752 fCrossSection->SetName("PhotoEffXS"); << 753 fCrossSectionLE = new G4ElementData(ZMAXPE << 754 fCrossSectionLE->SetName("PhotoEffLowXS"); << 755 } << 756 ReadData(Z); << 757 } 328 } 758 329 759 //....oooOO0OOooo........oooOO0OOooo........oo << 330 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... 760 331 761 void G4LivermorePhotoElectricModel::Initialise << 332 void G4LivermorePhotoElectricModel::SetAngularGenerator(const G4String& name) 762 { 333 { 763 if (fCrossSection->GetElementData(Z) == null << 334 if (name == "default") 764 G4AutoLock l(&livPhotoeffMutex); << 335 { 765 if (fCrossSection->GetElementData(Z) == nu << 336 delete ElectronAngularGenerator; 766 ReadData(Z); << 337 ElectronAngularGenerator = >> 338 new G4PhotoElectricAngularGeneratorSimple("GEANT4LowEnergySimpleGenerator"); >> 339 generatorName = name; 767 } 340 } 768 l.unlock(); << 341 else if (name == "standard") 769 } << 342 { >> 343 delete ElectronAngularGenerator; >> 344 ElectronAngularGenerator = >> 345 new G4PhotoElectricAngularGeneratorSauterGavrila("GEANT4SauterGavrilaGenerator"); >> 346 generatorName = name; >> 347 } >> 348 else if (name == "polarized") >> 349 { >> 350 delete ElectronAngularGenerator; >> 351 ElectronAngularGenerator = >> 352 new G4PhotoElectricAngularGeneratorPolarized("GEANT4LowEnergyPolarizedGenerator"); >> 353 generatorName = name; >> 354 } >> 355 else >> 356 { >> 357 G4Exception("G4LowEnergyPhotoElectric::SetAngularGenerator - generator does not exist"); >> 358 } >> 359 >> 360 ElectronAngularGenerator->PrintGeneratorInformation(); 770 } 361 } 771 362 772 //....oooOO0OOooo........oooOO0OOooo........oo << 773 363