Geant4 11.4.0
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
G4LivermorePhotoElectricModel.cc
Go to the documentation of this file.
1//
2// ********************************************************************
3// * License and Disclaimer *
4// * *
5// * The Geant4 software is copyright of the Copyright Holders of *
6// * the Geant4 Collaboration. It is provided under the terms and *
7// * conditions of the Geant4 Software License, included in the file *
8// * LICENSE and available at http://cern.ch/geant4/license . These *
9// * include a list of copyright holders. *
10// * *
11// * Neither the authors of this software system, nor their employing *
12// * institutes,nor the agencies providing financial support for this *
13// * work make any representation or warranty, express or implied, *
14// * regarding this software system or assume any liability for its *
15// * use. Please see the license in the file LICENSE and URL above *
16// * for the full disclaimer and the limitation of liability. *
17// * *
18// * This code implementation is the result of the scientific and *
19// * technical work of the GEANT4 collaboration. *
20// * By using, copying, modifying or distributing the software (or *
21// * any work based on the software) you agree to acknowledge its *
22// * use in resulting scientific publications, and indicate your *
23// * acceptance of all terms of the Geant4 Software license. *
24// ********************************************************************
25//
26//
27// Author: Sebastien Incerti
28// 30 October 2008
29// on base of G4LowEnergyPhotoElectric developed by A.Forti and M.G.Pia
30//
31// 22 Oct 2012 A & V Ivanchenko Migration data structure to G4PhysicsVector
32// 1 June 2017 M Bandieramonte: New model based on livermore/epics2014
33// evaluated data - parameterization fits in two ranges
34
36
37#include "G4AtomicShell.hh"
38#include "G4AutoLock.hh"
40#include "G4Electron.hh"
41#include "G4Gamma.hh"
42#include "G4LossTableManager.hh"
46#include "G4SystemOfUnits.hh"
48#include "G4EmParameters.hh"
49
50//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
51
52G4ElementData* G4LivermorePhotoElectricModel::fCrossSection = nullptr;
53G4ElementData* G4LivermorePhotoElectricModel::fCrossSectionLE = nullptr;
54std::vector<G4double>* G4LivermorePhotoElectricModel::fParamHigh[] = {nullptr};
55std::vector<G4double>* G4LivermorePhotoElectricModel::fParamLow[] = {nullptr};
56G4int G4LivermorePhotoElectricModel::fNShells[] = {0};
57G4int G4LivermorePhotoElectricModel::fNShellsUsed[] = {0};
58G4Material* G4LivermorePhotoElectricModel::fWater = nullptr;
59G4double G4LivermorePhotoElectricModel::fWaterEnergyLimit = 0.0;
60G4String G4LivermorePhotoElectricModel::fDataDirectory = "";
61
62static std::once_flag applyOnce;
63
64namespace
65{
66 G4Mutex livPhotoeffMutex = G4MUTEX_INITIALIZER;
67}
68
69//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
70
72 : G4VEmModel(nam)
73{
74 verboseLevel = 0;
75 // Verbosity scale:
76 // 0 = nothing
77 // 1 = warning for energy non-conservation
78 // 2 = details of energy budget
79 // 3 = calculation of cross sections, file openings, sampling of atoms
80 // 4 = entering in methods
81
82 theGamma = G4Gamma::Gamma();
83 theElectron = G4Electron::Electron();
84
85 // default generator
87
88 if (verboseLevel > 0) {
89 G4cout << "Livermore PhotoElectric is constructed "
90 << " nShellLimit= " << nShellLimit << G4endl;
91 }
92
93 // Mark this model as "applicable" for atomic deexcitation
95
96 // For water
97 fSandiaCof.resize(4, 0.0);
98
99 FindDirectoryPath();
100
101 if (fCrossSection == nullptr) {
102 fCrossSection = new G4ElementData(ZMAXPE);
103 fCrossSection->SetName("PhotoEffXS");
104 fCrossSectionLE = new G4ElementData(ZMAXPE);
105 fCrossSectionLE->SetName("PhotoEffLowXS");
106 for (G4int i = 0; i < ZMAXPE; ++i) {
107 fParamHigh[i] = nullptr;
108 fParamLow[i] = nullptr;
109 fNShells[i] = 0;
110 fNShellsUsed[i] = 0;
111 }
112 }
113}
114
115//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
116
118{
119 if (isInitializer) {
120 for (G4int i = 0; i < ZMAXPE; ++i) {
121 delete fParamHigh[i];
122 fParamHigh[i] = nullptr;
123 delete fParamLow[i];
124 fParamLow[i] = nullptr;
125 }
126 }
127}
128
129//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
130
132 const G4DataVector&)
133{
134 if (verboseLevel > 1) {
135 G4cout << "Calling G4LivermorePhotoElectricModel::Initialise() " << G4endl;
136 }
137
138 // initialise static tables only once
139 std::call_once(applyOnce, [this]() { isInitializer = true; });
140
141 if (isInitializer) {
142 G4AutoLock l(&livPhotoeffMutex);
143 if (fWater == nullptr) {
144 fWater = G4Material::GetMaterial("G4_WATER", false);
145 if (fWater == nullptr) {
146 fWater = G4Material::GetMaterial("Water", false);
147 }
148 if (fWater != nullptr) {
149 fWaterEnergyLimit = 13.6 * CLHEP::eV;
150 }
151 }
152
153 const G4ElementTable* elemTable = G4Element::GetElementTable();
154 std::size_t numElems = (*elemTable).size();
155 for (std::size_t ie = 0; ie < numElems; ++ie) {
156 const G4Element* elem = (*elemTable)[ie];
157 G4int Z = elem->GetZasInt();
158 if (Z < ZMAXPE) {
159 if (fCrossSection->GetElementData(Z) == nullptr) {
160 ReadData(Z);
161 }
162 }
163 }
164 l.unlock();
165 }
166
167 if (verboseLevel > 1) {
168 G4cout << "Loaded cross section files for new LivermorePhotoElectric model" << G4endl;
169 }
170 if (nullptr == fParticleChange) {
172 fAtomDeexcitation = G4LossTableManager::Instance()->AtomDeexcitation();
173 }
174
175 fDeexcitationActive = false;
176 if (nullptr != fAtomDeexcitation) {
177 fDeexcitationActive = fAtomDeexcitation->IsFluoActive();
178 }
179
180 if (verboseLevel > 1) {
181 G4cout << "LivermorePhotoElectric model is initialized " << G4endl;
182 }
183}
184
185//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
186
189 const G4ParticleDefinition* p,
190 G4double energy,
192{
193 fCurrSection = 0.0;
194 if (nullptr != fWater &&
195 (material == fWater || material->GetBaseMaterial() == fWater)) {
196 if (energy <= fWaterEnergyLimit) {
197 fWater->GetSandiaTable()->GetSandiaCofWater(energy, fSandiaCof);
198
199 G4double energy2 = energy * energy;
200 G4double energy3 = energy * energy2;
201 G4double energy4 = energy2 * energy2;
202
203 fCurrSection = material->GetDensity()
204 * (fSandiaCof[0] / energy + fSandiaCof[1] / energy2 +
205 fSandiaCof[2] / energy3 + fSandiaCof[3] / energy4);
206 }
207 }
208 if (0.0 == fCurrSection) {
209 fCurrSection = G4VEmModel::CrossSectionPerVolume(material, p, energy);
210 }
211 return fCurrSection;
212}
213
214//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
215
218 G4double energy,
219 G4double ZZ, G4double,
221{
222 if (verboseLevel > 3) {
223 G4cout << "\n G4LivermorePhotoElectricModel::ComputeCrossSectionPerAtom():"
224 << " Z= " << ZZ << " R(keV)= " << energy / keV << G4endl;
225 }
226 G4double cs = 0.0;
227 G4int Z = G4lrint(ZZ);
228 if (Z >= ZMAXPE || Z <= 0) {
229 return cs;
230 }
231 // if element was not initialised
232
233 // do initialisation safely for MT mode
234 if (fCrossSection->GetElementData(Z) == nullptr) {
235 InitialiseOnFly(Z);
236 if (fCrossSection->GetElementData(Z) == nullptr) { return cs; }
237 }
238
239 // 7: rows in the parameterization file; 5: number of parameters
240 G4int idx = fNShells[Z] * 7 - 5;
241
242 energy = std::max(energy, (*(fParamHigh[Z]))[idx - 1]);
243
244 G4double x1 = 1.0 / energy;
245 G4double x2 = x1 * x1;
246 G4double x3 = x2 * x1;
247
248 // high energy parameterisation
249 if (energy >= (*(fParamHigh[Z]))[0]) {
250 G4double x4 = x2 * x2;
251 G4double x5 = x4 * x1;
252
253 cs = x1 *
254 ((*(fParamHigh[Z]))[idx] + x1 * (*(fParamHigh[Z]))[idx + 1]
255 + x2 * (*(fParamHigh[Z]))[idx + 2] + x3 * (*(fParamHigh[Z]))[idx + 3]
256 + x4 * (*(fParamHigh[Z]))[idx + 4] + x5 * (*(fParamHigh[Z]))[idx + 5]);
257 }
258 // low energy parameterisation
259 else if (energy >= (*(fParamLow[Z]))[0]) {
260 G4double x4 = x2 * x2;
261 G4double x5 = x4 * x1; // this variable usage can probably be optimized
262 cs = x1 *
263 ((*(fParamLow[Z]))[idx] + x1 * (*(fParamLow[Z]))[idx + 1]
264 + x2 * (*(fParamLow[Z]))[idx + 2] + x3 * (*(fParamLow[Z]))[idx + 3]
265 + x4 * (*(fParamLow[Z]))[idx + 4] + x5 * (*(fParamLow[Z]))[idx + 5]);
266 }
267 // Tabulated values above k-shell ionization energy
268 else if (energy >= (*(fParamHigh[Z]))[1]) {
269 cs = x3 * (fCrossSection->GetElementData(Z))->Value(energy);
270 }
271 // Tabulated values below k-shell ionization energy
272 else {
273 cs = x3 * (fCrossSectionLE->GetElementData(Z))->Value(energy);
274 }
275 if (verboseLevel > 1) {
276 G4cout << "G4LivermorePhotoElectricModel: E(keV)= " << energy / keV << " Z= " << Z
277 << " cross(barn)= " << cs / barn << G4endl;
278 }
279 return cs;
280}
281
282//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
283
284void G4LivermorePhotoElectricModel::SampleSecondaries(std::vector<G4DynamicParticle*>* fvect,
285 const G4MaterialCutsCouple* couple,
286 const G4DynamicParticle* aDynamicGamma,
288{
289 G4double gammaEnergy = aDynamicGamma->GetKineticEnergy();
290 if (verboseLevel > 3) {
291 G4cout << "G4LivermorePhotoElectricModel::SampleSecondaries() Egamma(keV)= "
292 << gammaEnergy / keV << G4endl;
293 }
294
295 // kill incident photon
296 fParticleChange->ProposeTrackStatus(fStopAndKill);
297 fParticleChange->SetProposedKineticEnergy(0.);
298
299 // low-energy photo-effect in water - full absorption
300 const G4Material* material = couple->GetMaterial();
301 if (fWater && (material == fWater || material->GetBaseMaterial() == fWater)) {
302 if (gammaEnergy <= fWaterEnergyLimit) {
303 fParticleChange->ProposeLocalEnergyDeposit(gammaEnergy);
304 return;
305 }
306 }
307
308 // Returns the normalized direction of the momentum
309 G4ThreeVector photonDirection = aDynamicGamma->GetMomentumDirection();
310
311 // Select randomly one element in the current material
312 const G4Element* elm = SelectRandomAtom(material, theGamma, gammaEnergy);
313 G4int Z = elm->GetZasInt();
314
315 // Select the ionised shell in the current atom according to shell
316 // cross sections
317
318 // If element was not initialised gamma should be absorbed
319 if (Z >= ZMAXPE || fCrossSection->GetElementData(Z) == nullptr) {
320 fParticleChange->ProposeLocalEnergyDeposit(gammaEnergy);
321 return;
322 }
323
324 // SAMPLING OF THE SHELL INDEX
325 std::size_t shellIdx = 0;
326 std::size_t nn = fNShellsUsed[Z];
327 if (nn > 1) {
328 if (gammaEnergy >= (*(fParamHigh[Z]))[0]) {
329 G4double x1 = 1.0 / gammaEnergy;
330 G4double x2 = x1 * x1;
331 G4double x3 = x2 * x1;
332 G4double x4 = x3 * x1;
333 G4double x5 = x4 * x1;
334 std::size_t idx = nn * 7 - 5;
335 // when do sampling common factors are not taken into account
336 // so cross section is not real
337
338 G4double rand = G4UniformRand();
339 G4double cs0 = rand *
340 ((*(fParamHigh[Z]))[idx] + x1 * (*(fParamHigh[Z]))[idx + 1]
341 + x2 * (*(fParamHigh[Z]))[idx + 2] + x3 * (*(fParamHigh[Z]))[idx + 3]
342 + x4 * (*(fParamHigh[Z]))[idx + 4] + x5 * (*(fParamHigh[Z]))[idx + 5]);
343
344 for (shellIdx = 0; shellIdx < nn; ++shellIdx) {
345 idx = shellIdx * 7 + 2;
346 if (gammaEnergy > (*(fParamHigh[Z]))[idx - 1]) {
347 G4double cs = (*(fParamHigh[Z]))[idx] + x1 * (*(fParamHigh[Z]))[idx + 1]
348 + x2 * (*(fParamHigh[Z]))[idx + 2] + x3 * (*(fParamHigh[Z]))[idx + 3]
349 + x4 * (*(fParamHigh[Z]))[idx + 4] + x5 * (*(fParamHigh[Z]))[idx + 5];
350
351 if (cs >= cs0) {
352 break;
353 }
354 }
355 }
356 if (shellIdx >= nn) {
357 shellIdx = nn - 1;
358 }
359 }
360 else if (gammaEnergy >= (*(fParamLow[Z]))[0]) {
361 G4double x1 = 1.0 / gammaEnergy;
362 G4double x2 = x1 * x1;
363 G4double x3 = x2 * x1;
364 G4double x4 = x3 * x1;
365 G4double x5 = x4 * x1;
366 std::size_t idx = nn * 7 - 5;
367 // when do sampling common factors are not taken into account
368 // so cross section is not real
369 G4double cs0 = G4UniformRand() *
370 ((*(fParamLow[Z]))[idx] + x1 * (*(fParamLow[Z]))[idx + 1]
371 + x2 * (*(fParamLow[Z]))[idx + 2] + x3 * (*(fParamLow[Z]))[idx + 3]
372 + x4 * (*(fParamLow[Z]))[idx + 4] + x5 * (*(fParamLow[Z]))[idx + 5]);
373 for (shellIdx = 0; shellIdx < nn; ++shellIdx) {
374 idx = shellIdx * 7 + 2;
375 if (gammaEnergy > (*(fParamLow[Z]))[idx - 1]) {
376 G4double cs = (*(fParamLow[Z]))[idx] + x1 * (*(fParamLow[Z]))[idx + 1]
377 + x2 * (*(fParamLow[Z]))[idx + 2] + x3 * (*(fParamLow[Z]))[idx + 3]
378 + x4 * (*(fParamLow[Z]))[idx + 4] + x5 * (*(fParamLow[Z]))[idx + 5];
379 if (cs >= cs0) {
380 break;
381 }
382 }
383 }
384 if (shellIdx >= nn) {
385 shellIdx = nn - 1;
386 }
387 }
388 else {
389 // when do sampling common factors are not taken into account
390 // so cross section is not real
391 G4double cs = G4UniformRand();
392
393 if (gammaEnergy >= (*(fParamHigh[Z]))[1]) {
394 // above K-shell binding energy
395 cs *= fCrossSection->GetElementData(Z)->Value(gammaEnergy);
396 }
397 else {
398 // below K-shell binding energy
399 cs *= fCrossSectionLE->GetElementData(Z)->Value(gammaEnergy);
400 }
401
402 for (G4int j = 0; j < (G4int)nn; ++j) {
403 shellIdx = (std::size_t)fCrossSection->GetComponentID(Z, j);
404 if (gammaEnergy > (*(fParamLow[Z]))[7 * shellIdx + 1]) {
405 cs -= fCrossSection->GetValueForComponent(Z, j, gammaEnergy);
406 }
407 if (cs <= 0.0 || j + 1 == (G4int)nn) {
408 break;
409 }
410 }
411 }
412 }
413 // END: SAMPLING OF THE SHELL
414
415 G4double bindingEnergy = (*(fParamHigh[Z]))[shellIdx * 7 + 1];
416 const G4AtomicShell* shell = nullptr;
417
418 // no de-excitation from the last shell
419 if (fDeexcitationActive && shellIdx + 1 < nn) {
420 auto as = G4AtomicShellEnumerator(shellIdx);
421 shell = fAtomDeexcitation->GetAtomicShell(Z, as);
422 }
423
424 // If binding energy of the selected shell is larger than photon energy
425 // do not generate secondaries
426 if (gammaEnergy < bindingEnergy) {
427 fParticleChange->ProposeLocalEnergyDeposit(gammaEnergy);
428 return;
429 }
430
431 // Primary outcoming electron
432 G4double eKineticEnergy = gammaEnergy - bindingEnergy;
433 G4double edep = bindingEnergy;
434
435 // Calculate direction of the photoelectron
437 aDynamicGamma, eKineticEnergy, (G4int)shellIdx, couple->GetMaterial());
438
439 // The electron is created
440 auto electron =
441 new G4DynamicParticle(theElectron, electronDirection, eKineticEnergy);
442 fvect->push_back(electron);
443
444 // Sample deexcitation
445 if (nullptr != shell) {
446 G4int index = couple->GetIndex();
447 if (fAtomDeexcitation->CheckDeexcitationActiveRegion(index)) {
448 std::size_t nbefore = fvect->size();
449
450 fAtomDeexcitation->GenerateParticles(fvect, shell, Z, index);
451 std::size_t nafter = fvect->size();
452 if (nafter > nbefore) {
453 G4double esec = 0.0;
454 for (std::size_t j = nbefore; j < nafter; ++j) {
455 G4double e = ((*fvect)[j])->GetKineticEnergy();
456 if (esec + e > edep) {
457 // correct energy in order to have energy balance
458 e = edep - esec;
459 ((*fvect)[j])->SetKineticEnergy(e);
460 esec += e;
461 // delete the rest of secondaries (should not happens)
462 for (std::size_t jj = nafter - 1; jj > j; --jj) {
463 delete (*fvect)[jj];
464 fvect->pop_back();
465 }
466 break;
467 }
468 esec += e;
469 }
470 edep -= esec;
471 }
472 }
473 }
474 // energy balance - excitation energy left
475 if (edep > 0.0) {
476 fParticleChange->ProposeLocalEnergyDeposit(edep);
477 }
478}
479
480//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
481
482void G4LivermorePhotoElectricModel::FindDirectoryPath()
483{
484 // no check in this method - environment variable is check by utility
485 if (fDataDirectory.empty()) {
486 auto param = G4EmParameters::Instance();
487 std::ostringstream ost;
488 if (param->LivermoreDataDir() == "livermore") {
489 ost << param->GetDirLEDATA() << "/livermore/phot_epics2014/";
490 }
491 else {
492 ost << param->GetDirLEDATA() << "/epics2017/phot/";
493 }
494 fDataDirectory = ost.str();
495 }
496}
497
498//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
499
500void G4LivermorePhotoElectricModel::ReadData(G4int Z)
501{
502 if (Z <= 0 || Z >= ZMAXPE) {
503 G4cout << "G4LivermorePhotoElectricModel::ReadData() Warning: Z="
504 << Z << " is out of range - request ignored" << G4endl;
505 return;
506 }
507 if (verboseLevel > 1) {
508 G4cout << "G4LivermorePhotoElectricModel::ReadData() for Z=" << Z << G4endl;
509 }
510
511 if (fCrossSection->GetElementData(Z) != nullptr) {
512 return;
513 }
514
515 // spline for photoeffect total x-section above K-shell when using EPDL97
516 // but below the parameterized ones
517
518 auto param = G4EmParameters::Instance();
519 G4bool spline = (param->LivermoreDataDir() == "livermore");
520 G4int number = param->NumberForFreeVector();
521
522 // fDataDirectory will be defined after these lines
523 std::ostringstream ost;
524 ost << fDataDirectory << "pe-cs-" << Z << ".dat";
525 std::ifstream fin(ost.str().c_str());
526 if (!fin.is_open()) {
528 ed << "G4LivermorePhotoElectricModel data file <"
529 << ost.str().c_str() << "> is not opened!" << G4endl;
530 G4Exception("G4LivermorePhotoElectricModel::ReadData()", "em0003", FatalException, ed,
531 "G4LEDATA version should be G4EMLOW8.0 or later.");
532 return;
533 }
534 if (verboseLevel > 3) {
535 G4cout << "File " << ost.str().c_str() << " is opened by G4LivermorePhotoElectricModel"
536 << G4endl;
537 }
538 auto pv = new G4PhysicsFreeVector(spline);
539 pv->Retrieve(fin, true);
540 pv->ScaleVector(MeV, barn);
541 pv->FillSecondDerivatives();
542 pv->EnableLogBinSearch(number);
543 fCrossSection->InitialiseForElement(Z, pv);
544 fin.close();
545
546 // read high-energy fit parameters
547 G4int n1 = 0;
548 G4int n2 = 0;
549 G4double x;
550 std::ostringstream ost1;
551 ost1 << fDataDirectory << "pe-high-" << Z << ".dat";
552 std::ifstream fin1(ost1.str().c_str());
553 if (!fin1.is_open()) {
555 ed << "G4LivermorePhotoElectricModel data file <"
556 << ost1.str().c_str() << "> is not opened!" << G4endl;
557 G4Exception("G4LivermorePhotoElectricModel::ReadData()", "em0003", FatalException, ed,
558 "G4LEDATA version should be G4EMLOW7.2 or later.");
559 return;
560 }
561 if (verboseLevel > 3) {
562 G4cout << "File " << ost1.str().c_str() << " is opened by G4LivermorePhotoElectricModel"
563 << G4endl;
564 }
565 fin1 >> n1;
566 if (fin1.fail()) {
567 return;
568 }
569 if (0 > n1 || n1 >= INT_MAX) {
570 n1 = 0;
571 }
572
573 fin1 >> n2;
574 if (fin1.fail()) {
575 return;
576 }
577 if (0 > n2 || n2 >= INT_MAX) {
578 n2 = 0;
579 }
580
581 fin1 >> x;
582 if (fin1.fail()) {
583 return;
584 }
585
586 fNShells[Z] = n1;
587 fParamHigh[Z] = new std::vector<G4double>;
588 fParamHigh[Z]->reserve(7 * n1 + 1);
589 fParamHigh[Z]->push_back(x * MeV);
590 for (G4int i = 0; i < n1; ++i) {
591 for (G4int j = 0; j < 7; ++j) {
592 fin1 >> x;
593 if (0 == j) {
594 x *= MeV;
595 }
596 else {
597 x *= barn;
598 }
599 fParamHigh[Z]->push_back(x);
600 }
601 }
602 fin1.close();
603
604 // read low-energy fit parameters
605 G4int n1_low = 0;
606 G4int n2_low = 0;
607 G4double x_low;
608 std::ostringstream ost1_low;
609 ost1_low << fDataDirectory << "pe-low-" << Z << ".dat";
610 std::ifstream fin1_low(ost1_low.str().c_str());
611 if (!fin1_low.is_open()) {
613 ed << "G4LivermorePhotoElectricModel data file <" << ost1_low.str().c_str()
614 << "> is not opened!" << G4endl;
615 G4Exception("G4LivermorePhotoElectricModel::ReadData()", "em0003", FatalException, ed,
616 "G4LEDATA version should be G4EMLOW8.0 or later.");
617 return;
618 }
619 if (verboseLevel > 3) {
620 G4cout << "File " << ost1_low.str().c_str() << " is opened by G4LivermorePhotoElectricModel"
621 << G4endl;
622 }
623 fin1_low >> n1_low;
624 if (fin1_low.fail()) {
625 return;
626 }
627 if (0 > n1_low || n1_low >= INT_MAX) {
628 n1_low = 0;
629 }
630
631 fin1_low >> n2_low;
632 if (fin1_low.fail()) {
633 return;
634 }
635 if (0 > n2_low || n2_low >= INT_MAX) {
636 n2_low = 0;
637 }
638
639 fin1_low >> x_low;
640 if (fin1_low.fail()) {
641 return;
642 }
643
644 fNShells[Z] = n1_low;
645 fParamLow[Z] = new std::vector<G4double>;
646 fParamLow[Z]->reserve(7 * n1_low + 1);
647 fParamLow[Z]->push_back(x_low * MeV);
648 for (G4int i = 0; i < n1_low; ++i) {
649 for (G4int j = 0; j < 7; ++j) {
650 fin1_low >> x_low;
651 if (0 == j) {
652 x_low *= MeV;
653 }
654 else {
655 x_low *= barn;
656 }
657 fParamLow[Z]->push_back(x_low);
658 }
659 }
660 fin1_low.close();
661
662 // there is a possibility to use only main shells
663 if (nShellLimit < n2) {
664 n2 = nShellLimit;
665 }
666 fCrossSection->InitialiseForComponent(Z, n2); // number of shells
667 fNShellsUsed[Z] = n2;
668
669 if (1 < n2) {
670 std::ostringstream ost2;
671 ost2 << fDataDirectory << "pe-ss-cs-" << Z << ".dat";
672 std::ifstream fin2(ost2.str().c_str());
673 if (!fin2.is_open()) {
675 ed << "G4LivermorePhotoElectricModel data file <" << ost2.str().c_str() << "> is not opened!"
676 << G4endl;
677 G4Exception("G4LivermorePhotoElectricModel::ReadData()", "em0003", FatalException, ed,
678 "G4LEDATA version should be G4EMLOW7.2 or later.");
679 return;
680 }
681 if (verboseLevel > 3) {
682 G4cout << "File " << ost2.str().c_str() << " is opened by G4LivermorePhotoElectricModel"
683 << G4endl;
684 }
685
686 G4int n3, n4;
687 G4double y;
688 for (G4int i = 0; i < n2; ++i) {
689 fin2 >> x >> y >> n3 >> n4;
690 auto v = new G4PhysicsFreeVector(n3, x, y);
691 for (G4int j = 0; j < n3; ++j) {
692 fin2 >> x >> y;
693 v->PutValues(j, x * CLHEP::MeV, y * CLHEP::barn);
694 }
695 v->EnableLogBinSearch(number);
696 fCrossSection->AddComponent(Z, n4, v);
697 }
698 fin2.close();
699 }
700
701 // no spline for photoeffect total x-section below K-shell
702 if (1 < fNShells[Z]) {
703 auto pv1 = new G4PhysicsFreeVector(false);
704 std::ostringstream ost3;
705 ost3 << fDataDirectory << "pe-le-cs-" << Z << ".dat";
706 std::ifstream fin3(ost3.str().c_str());
707 if (!fin3.is_open()) {
709 ed << "G4LivermorePhotoElectricModel data file <" << ost3.str().c_str() << "> is not opened!"
710 << G4endl;
711 G4Exception("G4LivermorePhotoElectricModel::ReadData()", "em0003", FatalException, ed,
712 "G4LEDATA version should be G4EMLOW8.0 or later.");
713 delete pv1;
714 return;
715 }
716 if (verboseLevel > 3) {
717 G4cout << "File " << ost3.str().c_str() << " is opened by G4LivermorePhotoElectricModel"
718 << G4endl;
719 }
720 pv1->Retrieve(fin3, true);
721 pv1->ScaleVector(CLHEP::MeV, CLHEP::barn);
722 pv1->EnableLogBinSearch(number);
723 fCrossSectionLE->InitialiseForElement(Z, pv1);
724 fin3.close();
725 }
726}
727
728//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
729
731{
732 if (Z < 1 || Z >= ZMAXPE) {
733 return -1;
734 } // If Z is out of the supported return 0
735
736 InitialiseOnFly(Z);
737 if (fCrossSection->GetElementData(Z) == nullptr ||
738 shell < 0 || shell >= fNShellsUsed[Z]) {
739 return -1;
740 }
741
742 if (Z > 2) {
743 return fCrossSection->GetComponentDataByIndex(Z, shell)->Energy(0);
744 }
745 else {
746 return fCrossSection->GetElementData(Z)->Energy(0);
747 }
748}
749
750//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
751
752void G4LivermorePhotoElectricModel::InitialiseOnFly(G4int Z)
753{
754 if (fCrossSection->GetElementData(Z) == nullptr && Z > 0 && Z < ZMAXPE) {
755 G4AutoLock l(&livPhotoeffMutex);
756 if (fCrossSection->GetElementData(Z) == nullptr) {
757 ReadData(Z);
758 }
759 l.unlock();
760 }
761}
762
763//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4TemplateAutoLock< G4Mutex > G4AutoLock
std::vector< G4Element * > G4ElementTable
@ FatalException
void G4Exception(const char *originOfException, const char *exceptionCode, G4ExceptionSeverity severity, const char *description)
std::ostringstream G4ExceptionDescription
#define elem(i, j)
#define G4MUTEX_INITIALIZER
std::mutex G4Mutex
CLHEP::Hep3Vector G4ThreeVector
@ fStopAndKill
double G4double
Definition G4Types.hh:83
bool G4bool
Definition G4Types.hh:86
int G4int
Definition G4Types.hh:85
#define G4endl
Definition G4ios.hh:67
G4GLOB_DLL std::ostream G4cout
#define G4UniformRand()
Definition Randomize.hh:52
const G4ThreeVector & GetMomentumDirection() const
G4double GetKineticEnergy() const
static G4Electron * Electron()
Definition G4Electron.cc:91
G4PhysicsVector * GetElementData(G4int Z) const
static const G4ElementTable * GetElementTable()
Definition G4Element.cc:401
G4int GetZasInt() const
Definition G4Element.hh:120
static G4EmParameters * Instance()
static G4Gamma * Gamma()
Definition G4Gamma.cc:81
G4double ComputeCrossSectionPerAtom(const G4ParticleDefinition *, G4double energy, G4double Z, G4double A=0, G4double cut=0, G4double emax=DBL_MAX) override
G4double GetBindingEnergy(G4int Z, G4int shell)
void SampleSecondaries(std::vector< G4DynamicParticle * > *, const G4MaterialCutsCouple *, const G4DynamicParticle *, G4double tmin, G4double maxEnergy) override
void Initialise(const G4ParticleDefinition *, const G4DataVector &) override
G4LivermorePhotoElectricModel(const G4String &nam="LivermorePhElectric")
G4double CrossSectionPerVolume(const G4Material *, const G4ParticleDefinition *, G4double energy, G4double cutEnergy=0.0, G4double maxEnergy=DBL_MAX) override
static G4LossTableManager * Instance()
G4VAtomDeexcitation * AtomDeexcitation()
const G4Material * GetMaterial() const
G4double GetDensity() const
const G4Material * GetBaseMaterial() const
static G4Material * GetMaterial(const G4String &name, G4bool warning=true)
virtual G4ThreeVector & SampleDirection(const G4DynamicParticle *dp, G4double finalTotalEnergy, G4int Z, const G4Material *)=0
G4VEmAngularDistribution * GetAngularDistribution()
G4ParticleChangeForGamma * GetParticleChangeForGamma()
virtual G4double CrossSectionPerVolume(const G4Material *, const G4ParticleDefinition *, G4double kineticEnergy, G4double cutEnergy=0.0, G4double maxEnergy=DBL_MAX)
const G4Element * SelectRandomAtom(const G4MaterialCutsCouple *, const G4ParticleDefinition *, G4double kineticEnergy, G4double cutEnergy=0.0, G4double maxEnergy=DBL_MAX)
void SetDeexcitationFlag(G4bool val)
G4VEmModel(const G4String &nam)
Definition G4VEmModel.cc:67
void SetAngularDistribution(G4VEmAngularDistribution *)
int G4lrint(double ad)
Definition templates.hh:134
#define INT_MAX
Definition templates.hh:90