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 =
"";
62static std::once_flag applyOnce;
88 if (verboseLevel > 0) {
89 G4cout <<
"Livermore PhotoElectric is constructed "
90 <<
" nShellLimit= " << nShellLimit <<
G4endl;
97 fSandiaCof.resize(4, 0.0);
101 if (fCrossSection ==
nullptr) {
103 fCrossSection->SetName(
"PhotoEffXS");
105 fCrossSectionLE->SetName(
"PhotoEffLowXS");
106 for (
G4int i = 0; i < ZMAXPE; ++i) {
107 fParamHigh[i] =
nullptr;
108 fParamLow[i] =
nullptr;
120 for (
G4int i = 0; i < ZMAXPE; ++i) {
121 delete fParamHigh[i];
122 fParamHigh[i] =
nullptr;
124 fParamLow[i] =
nullptr;
134 if (verboseLevel > 1) {
135 G4cout <<
"Calling G4LivermorePhotoElectricModel::Initialise() " <<
G4endl;
139 std::call_once(applyOnce, [
this]() { isInitializer =
true; });
143 if (fWater ==
nullptr) {
145 if (fWater ==
nullptr) {
148 if (fWater !=
nullptr) {
149 fWaterEnergyLimit = 13.6 * CLHEP::eV;
154 std::size_t numElems = (*elemTable).size();
155 for (std::size_t ie = 0; ie < numElems; ++ie) {
159 if (fCrossSection->GetElementData(Z) ==
nullptr) {
167 if (verboseLevel > 1) {
168 G4cout <<
"Loaded cross section files for new LivermorePhotoElectric model" <<
G4endl;
175 fDeexcitationActive =
false;
176 if (
nullptr != fAtomDeexcitation) {
177 fDeexcitationActive = fAtomDeexcitation->IsFluoActive();
180 if (verboseLevel > 1) {
181 G4cout <<
"LivermorePhotoElectric model is initialized " <<
G4endl;
194 if (
nullptr != fWater &&
196 if (energy <= fWaterEnergyLimit) {
197 fWater->GetSandiaTable()->GetSandiaCofWater(energy, fSandiaCof);
200 G4double energy3 = energy * energy2;
201 G4double energy4 = energy2 * energy2;
204 * (fSandiaCof[0] / energy + fSandiaCof[1] / energy2 +
205 fSandiaCof[2] / energy3 + fSandiaCof[3] / energy4);
208 if (0.0 == fCurrSection) {
222 if (verboseLevel > 3) {
223 G4cout <<
"\n G4LivermorePhotoElectricModel::ComputeCrossSectionPerAtom():"
224 <<
" Z= " << ZZ <<
" R(keV)= " << energy / keV <<
G4endl;
228 if (Z >= ZMAXPE || Z <= 0) {
234 if (fCrossSection->GetElementData(Z) ==
nullptr) {
236 if (fCrossSection->GetElementData(Z) ==
nullptr) {
return cs; }
240 G4int idx = fNShells[Z] * 7 - 5;
242 energy = std::max(energy, (*(fParamHigh[Z]))[idx - 1]);
249 if (energy >= (*(fParamHigh[Z]))[0]) {
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]);
259 else if (energy >= (*(fParamLow[Z]))[0]) {
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]);
268 else if (energy >= (*(fParamHigh[Z]))[1]) {
269 cs = x3 * (fCrossSection->GetElementData(Z))->Value(energy);
273 cs = x3 * (fCrossSectionLE->GetElementData(Z))->Value(energy);
275 if (verboseLevel > 1) {
276 G4cout <<
"G4LivermorePhotoElectricModel: E(keV)= " << energy / keV <<
" Z= " << Z
277 <<
" cross(barn)= " << cs / barn <<
G4endl;
290 if (verboseLevel > 3) {
291 G4cout <<
"G4LivermorePhotoElectricModel::SampleSecondaries() Egamma(keV)= "
292 << gammaEnergy / keV <<
G4endl;
301 if (fWater && (material == fWater || material->
GetBaseMaterial() == fWater)) {
302 if (gammaEnergy <= fWaterEnergyLimit) {
319 if (Z >= ZMAXPE || fCrossSection->GetElementData(Z) ==
nullptr) {
325 std::size_t shellIdx = 0;
326 std::size_t nn = fNShellsUsed[Z];
328 if (gammaEnergy >= (*(fParamHigh[Z]))[0]) {
334 std::size_t idx = nn * 7 - 5;
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]);
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];
356 if (shellIdx >= nn) {
360 else if (gammaEnergy >= (*(fParamLow[Z]))[0]) {
366 std::size_t idx = nn * 7 - 5;
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];
384 if (shellIdx >= nn) {
393 if (gammaEnergy >= (*(fParamHigh[Z]))[1]) {
395 cs *= fCrossSection->GetElementData(Z)->Value(gammaEnergy);
399 cs *= fCrossSectionLE->GetElementData(Z)->Value(gammaEnergy);
403 shellIdx = (std::size_t)fCrossSection->GetComponentID(Z, j);
404 if (gammaEnergy > (*(fParamLow[Z]))[7 * shellIdx + 1]) {
405 cs -= fCrossSection->GetValueForComponent(Z, j, gammaEnergy);
407 if (cs <= 0.0 || j + 1 == (
G4int)nn) {
415 G4double bindingEnergy = (*(fParamHigh[Z]))[shellIdx * 7 + 1];
419 if (fDeexcitationActive && shellIdx + 1 < nn) {
421 shell = fAtomDeexcitation->GetAtomicShell(Z, as);
426 if (gammaEnergy < bindingEnergy) {
432 G4double eKineticEnergy = gammaEnergy - bindingEnergy;
442 fvect->push_back(electron);
445 if (
nullptr != shell) {
447 if (fAtomDeexcitation->CheckDeexcitationActiveRegion(index)) {
448 std::size_t nbefore = fvect->size();
450 fAtomDeexcitation->GenerateParticles(fvect, shell, Z, index);
451 std::size_t nafter = fvect->size();
452 if (nafter > nbefore) {
454 for (std::size_t j = nbefore; j < nafter; ++j) {
455 G4double e = ((*fvect)[j])->GetKineticEnergy();
456 if (esec + e > edep) {
459 ((*fvect)[j])->SetKineticEnergy(e);
462 for (std::size_t jj = nafter - 1; jj > j; --jj) {
482void G4LivermorePhotoElectricModel::FindDirectoryPath()
485 if (fDataDirectory.empty()) {
487 std::ostringstream ost;
488 if (param->LivermoreDataDir() ==
"livermore") {
489 ost << param->GetDirLEDATA() <<
"/livermore/phot_epics2014/";
492 ost << param->GetDirLEDATA() <<
"/epics2017/phot/";
494 fDataDirectory = ost.str();
500void G4LivermorePhotoElectricModel::ReadData(
G4int Z)
502 if (Z <= 0 || Z >= ZMAXPE) {
503 G4cout <<
"G4LivermorePhotoElectricModel::ReadData() Warning: Z="
504 << Z <<
" is out of range - request ignored" <<
G4endl;
507 if (verboseLevel > 1) {
508 G4cout <<
"G4LivermorePhotoElectricModel::ReadData() for Z=" << Z <<
G4endl;
511 if (fCrossSection->GetElementData(Z) !=
nullptr) {
519 G4bool spline = (param->LivermoreDataDir() ==
"livermore");
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;
531 "G4LEDATA version should be G4EMLOW8.0 or later.");
534 if (verboseLevel > 3) {
535 G4cout <<
"File " << ost.str().c_str() <<
" is opened by G4LivermorePhotoElectricModel"
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);
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;
558 "G4LEDATA version should be G4EMLOW7.2 or later.");
561 if (verboseLevel > 3) {
562 G4cout <<
"File " << ost1.str().c_str() <<
" is opened by G4LivermorePhotoElectricModel"
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) {
599 fParamHigh[Z]->push_back(x);
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;
616 "G4LEDATA version should be G4EMLOW8.0 or later.");
619 if (verboseLevel > 3) {
620 G4cout <<
"File " << ost1_low.str().c_str() <<
" is opened by G4LivermorePhotoElectricModel"
624 if (fin1_low.fail()) {
627 if (0 > n1_low || n1_low >=
INT_MAX) {
632 if (fin1_low.fail()) {
635 if (0 > n2_low || n2_low >=
INT_MAX) {
640 if (fin1_low.fail()) {
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) {
657 fParamLow[Z]->push_back(x_low);
663 if (nShellLimit < n2) {
666 fCrossSection->InitialiseForComponent(Z, n2);
667 fNShellsUsed[Z] = 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!"
678 "G4LEDATA version should be G4EMLOW7.2 or later.");
681 if (verboseLevel > 3) {
682 G4cout <<
"File " << ost2.str().c_str() <<
" is opened by G4LivermorePhotoElectricModel"
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) {
693 v->PutValues(j, x * CLHEP::MeV, y * CLHEP::barn);
695 v->EnableLogBinSearch(number);
696 fCrossSection->AddComponent(Z, n4, v);
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!"
712 "G4LEDATA version should be G4EMLOW8.0 or later.");
716 if (verboseLevel > 3) {
717 G4cout <<
"File " << ost3.str().c_str() <<
" is opened by G4LivermorePhotoElectricModel"
720 pv1->Retrieve(fin3,
true);
721 pv1->ScaleVector(CLHEP::MeV, CLHEP::barn);
722 pv1->EnableLogBinSearch(number);
723 fCrossSectionLE->InitialiseForElement(Z, pv1);
732 if (Z < 1 || Z >= ZMAXPE) {
737 if (fCrossSection->GetElementData(Z) ==
nullptr ||
738 shell < 0 || shell >= fNShellsUsed[Z]) {
743 return fCrossSection->GetComponentDataByIndex(Z, shell)->Energy(0);
746 return fCrossSection->GetElementData(Z)->Energy(0);
752void G4LivermorePhotoElectricModel::InitialiseOnFly(
G4int Z)
754 if (fCrossSection->
GetElementData(Z) ==
nullptr && Z > 0 && Z < ZMAXPE) {
G4TemplateAutoLock< G4Mutex > G4AutoLock
std::vector< G4Element * > G4ElementTable
void G4Exception(const char *originOfException, const char *exceptionCode, G4ExceptionSeverity severity, const char *description)
std::ostringstream G4ExceptionDescription
#define G4MUTEX_INITIALIZER
CLHEP::Hep3Vector G4ThreeVector
G4GLOB_DLL std::ostream G4cout
const G4ThreeVector & GetMomentumDirection() const
G4double GetKineticEnergy() const
static G4Electron * Electron()
G4PhysicsVector * GetElementData(G4int Z) const
static const G4ElementTable * GetElementTable()
static G4EmParameters * Instance()
G4double ComputeCrossSectionPerAtom(const G4ParticleDefinition *, G4double energy, G4double Z, G4double A=0, G4double cut=0, G4double emax=DBL_MAX) override
G4ParticleChangeForGamma * fParticleChange
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() 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)
void SetAngularDistribution(G4VEmAngularDistribution *)