Import Geant4 11.3.0 source tree

This commit is contained in:
Gabriele Cosmo
2024-12-06 11:11:40 +01:00
parent e58e650b32
commit 32390e802b
1984 changed files with 98713 additions and 83996 deletions
@@ -6,6 +6,57 @@ It must **not** be used as a substitute for writing good git commit messages!
-------------------------------------------------------------------------------
## 2024-11-15 Vladimir Ivanchenko (hadr-cross-V11-02-18)
- G4ChargeExchangeXS - handle special case of positive meson scattering off
Hydrogen, the cross section is propotional to the percent of deuterons
## 2024-11-07 Vladimir Ivanchenko (hadr-cross-V11-02-17)
- G4ChargeExchangeXS - switch computations from level of isotopes to level of
elements, code become several times faster, accuracy is not lost; added
protections against negative components of cross section and potential
division by zero, which may be only at extreme high energy.
## 2024-11-03 Vladimir Ivanchenko (hadr-cross-V11-02-16)
- G4ChargeExchangeXS - fixed problem in pion x-sections according
to prescription of original paper.
## 2024-10-21 Vladimir Ivanchenko (hadr-cross-V11-02-15)
- G4HadronXSDataTable - used const pointers, fixed data structure, and
provide propery deletion of objects at exit
## 2024-09-22 Vladimir Ivanchenko (hadr-cross-V11-02-14)
- G4ChargeExchangeXS - improve comments to the code, minor clean-up of the code
## 2024-09-09 Vladimir Ivanchenko (hadr-cross-V11-02-13)
- G4InterfaceToXS - new class renamed from G4XSectionXS
- G4ParticleInelasticXS, G4NeutronInelasticXS - clean-up and fix Coverity warnings
## 2024-08-20 Vladimir Ivanchenko (hadr-cross-V11-02-12)
- G4ParticleInelasticXS - perform initialisation of data only for given ion,
not for all 5 ions
## 2024-08-15 Vladimir Ivanchenko (hadr-cross-V11-02-11)
- G4ParticleInelasticXS, G4NeutronElasticXS - access to G4PARTICLEXSDATA
in class constructor, optimized usage of mutex lock, do not use isInitializer
flag anymore.
## 2024-07-23 Vladimir Ivanchenko (hadr-cross-V11-02-10)
- G4GammaNuclearXS - fixed problem 2609 by usage of CHIPS parameterisation for
Zr and W at all energies, for Cr and Y above 25 MeV, for Sn and Gd above 16 MeV.
The default transition energy 130 - 150 MeV remains for other targets.
## 2024-07-18 Vladimir Ivanchenko (hadr-cross-V11-02-09)
- G4EMDissociationCrossSection - fixed Coverity warning
## 2024-07-16 Vladimir Ivanchenko (hadr-cross-V11-02-08)
- G4GammaNuclearXS, G4PhotoNuclearCrossSection, G4ParticleInelasticXS,
G4NeutronInelasticXS - make possibility of reuse of static data when several
instances of cross section classes are used
## 2024-07-03 Vladimir Ivanchenko (hadr-cross-V11-02-07)
- Fixed Coverity warnings in CHIPS inelastic x-sections and inside
G4EMDissociationCrossSection
## 2024-06-18 Vladimir Ivanchenko (hadr-cross-V11-02-06)
- G4BGGNucleonInelasticXS - fixed proton x-section below 14 MeV
@@ -70,15 +70,13 @@ public:
~G4ChargeExchangeXS() override = default;
G4bool IsIsoApplicable(const G4DynamicParticle*, G4int Z, G4int A,
const G4Element*, const G4Material*) override;
G4bool IsElementApplicable(const G4DynamicParticle*, G4int Z,
const G4Material*) final;
G4double GetIsoCrossSection(const G4DynamicParticle*, G4int Z, G4int A,
const G4Isotope* iso,
const G4Element* elm,
const G4Material* mat) override;
G4double GetElementCrossSection(const G4DynamicParticle*, G4int Z,
const G4Material*) final;
void CrossSectionDescription(std::ostream&) const override;
void CrossSectionDescription(std::ostream&) const final;
const G4ParticleDefinition*
SampleSecondaryType(const G4ParticleDefinition*,
@@ -88,11 +86,15 @@ public:
void SetCrossSectionFactor(G4double val) { fFactor = val; };
G4double GetCrossSectionFactor() const { return fFactor; };
G4ChargeExchangeXS & operator=(const G4ChargeExchangeXS &right) = delete;
G4ChargeExchangeXS(const G4ChargeExchangeXS&) = delete;
private:
G4double ComputeDeuteronFraction(const G4Material*);
G4Pow* g4calc;
const G4ParticleDefinition* fPionSecPD[5];
G4double fXSecPion[5] = {0.0, 0.0, 0.0, 0.0, 0.0};
@@ -80,13 +80,11 @@ class G4EMDissociationCrossSection : public G4VCrossSectionDataSet
{
public:
G4EMDissociationCrossSection ();
~G4EMDissociationCrossSection ();
~G4EMDissociationCrossSection () override;
virtual G4bool IsElementApplicable (const G4DynamicParticle*, G4int Z,
const G4Material*);
G4bool IsElementApplicable (const G4DynamicParticle*, G4int Z, const G4Material*) override;
virtual G4double GetElementCrossSection (const G4DynamicParticle *,
G4int Z, const G4Material *);
G4double GetElementCrossSection (const G4DynamicParticle*, G4int Z, const G4Material*) override;
G4PhysicsFreeVector * GetCrossSectionForProjectile
(G4double, G4double, G4double, G4double, G4double, G4double);
@@ -55,6 +55,7 @@ class G4ParticleDefinition;
class G4Element;
class G4ElementData;
class G4PhysicsVector;
class G4PhotoNuclearCrossSection;
class G4GammaNuclearXS final : public G4VCrossSectionDataSet
{
@@ -86,9 +87,9 @@ public:
void BuildPhysicsTable(const G4ParticleDefinition&) final;
G4double IsoCrossSection(G4double ekin, G4int Z, G4int A);
G4double IsoCrossSection(const G4double ekin, const G4int Z, const G4int A);
G4double ElementCrossSection(G4double ekin, G4int Z);
G4double ElementCrossSection(const G4double ekin, const G4int Z);
G4double LowEnergyCrossSection(G4double ekin, G4int Z);
@@ -105,7 +106,7 @@ private:
G4PhysicsVector* RetrieveVector(std::ostringstream& in, G4bool warn, G4int Z);
G4VCrossSectionDataSet* ggXsection = nullptr;
G4PhotoNuclearCrossSection* ggXsection = nullptr;
const G4ParticleDefinition* gamma;
// Cache
@@ -116,8 +117,6 @@ private:
static const G4int MAXZGAMMAXS = 95;
static const G4int MAXNFREE = 11;
static G4ElementData* data;
// Upper limit of the linear transition between IAEA database and CHIPS model
static const G4double eTransitionBound;
// The list of elements with non-linear parametrisation for better precision
static const G4int freeVectorException[MAXNFREE];
// CHIPS photonuclear model had a problem with high energy parametrisation
@@ -74,7 +74,7 @@ private:
static G4HadronXSDataTable* sInstance;
std::vector<G4PiData*> fPiData;
std::vector<std::vector<G4PiData*>* > fPiData;
std::vector<G4PhysicsTable*> fTable;
};
@@ -0,0 +1,73 @@
//
// ********************************************************************
// * License and Disclaimer *
// * *
// * The Geant4 software is copyright of the Copyright Holders of *
// * the Geant4 Collaboration. It is provided under the terms and *
// * conditions of the Geant4 Software License, included in the file *
// * LICENSE and available at http://cern.ch/geant4/license . These *
// * include a list of copyright holders. *
// * *
// * Neither the authors of this software system, nor their employing *
// * institutes,nor the agencies providing financial support for this *
// * work make any representation or warranty, express or implied, *
// * regarding this software system or assume any liability for its *
// * use. Please see the license in the file LICENSE and URL above *
// * for the full disclaimer and the limitation of liability. *
// * *
// * This code implementation is the result of the scientific and *
// * technical work of the GEANT4 collaboration. *
// * By using, copying, modifying or distributing the software (or *
// * any work based on the software) you agree to acknowledge its *
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
// GEANT4 Class header file
//
// File name: G4InterfaceToXS
//
// Author V.Ivantchenko, 12 July 2024
//
//
// Class description:
// Interface to G4PARTICLEXS cross sections for the de_excitation module
//
#ifndef G4InterfaceToXS_h
#define G4InterfaceToXS_h 1
#include "globals.hh"
class G4GammaNuclearXS;
class G4NeutronInelasticXS;
class G4ParticleInelasticXS;
class G4ParticleDefinition;
class G4InterfaceToXS
{
public:
G4InterfaceToXS(const G4ParticleDefinition*, G4int index);
~G4InterfaceToXS() = default;
void Initialise();
G4double GetElementCrossSection(const G4double ekin, const G4int Z);
G4double GetIsoCrossSection(const G4double ekin, const G4int Z, const G4int A);
G4InterfaceToXS(const G4InterfaceToXS& right) = delete;
const G4InterfaceToXS& operator = (const G4InterfaceToXS& right) = delete;
private:
G4int index;
const G4ParticleDefinition* fParticle;
G4GammaNuclearXS* fGammaNuclear{nullptr};
G4NeutronInelasticXS* fNeutronNuclear{nullptr};
G4ParticleInelasticXS* fParticleNuclear{nullptr};
};
#endif
@@ -129,6 +129,7 @@ private:
static const G4int MAXZINEL = 93;
static G4ElementData* data;
static G4double coeff[MAXZINEL];
static G4double lowcoeff[MAXZINEL];
static G4String gDataDirectory;
};
@@ -105,11 +105,7 @@ public:
private:
void Initialise(G4int Z, G4int idx);
void InitialiseOnFly(G4int Z);
void FindDirectoryPath();
void Initialise(G4int Z);
inline const G4PhysicsVector* GetPhysicsVector(G4int Z);
@@ -122,20 +118,19 @@ private:
G4double elimit;
G4int index{0};
G4bool isInitializer{false};
static const G4int MAXZINELP = 93;
static G4ElementData* data[5];
static G4double coeff[MAXZINELP][5];
static G4String gDataDirectory[5];
static G4String gDataDirectory;
};
inline
const G4PhysicsVector* G4ParticleInelasticXS::GetPhysicsVector(G4int Z)
{
const G4PhysicsVector* pv = data[index]->GetElementData(Z);
if (pv == nullptr) {
InitialiseOnFly(Z);
if (pv == nullptr) {
Initialise(Z);
pv = data[index]->GetElementData(Z);
}
return pv;
@@ -44,31 +44,36 @@ class G4PhotoNuclearCrossSection : public G4VCrossSectionDataSet
public:
G4PhotoNuclearCrossSection();
virtual ~G4PhotoNuclearCrossSection();
~G4PhotoNuclearCrossSection() override;
static const char* Default_Name() {return "PhotoNuclearXS";}
virtual void CrossSectionDescription(std::ostream&) const;
void CrossSectionDescription(std::ostream&) const override;
virtual G4bool
IsIsoApplicable(const G4DynamicParticle* particle, G4int Z, G4int A,
const G4Element* elm = 0, const G4Material* mat = 0);
G4bool IsIsoApplicable(const G4DynamicParticle*, G4int Z, G4int A,
const G4Element* elm = nullptr,
const G4Material* mat = nullptr) override;
virtual G4bool
IsElementApplicable(const G4DynamicParticle* particle, G4int Z,
const G4Material*);
G4bool IsElementApplicable(const G4DynamicParticle*, G4int Z,
const G4Material* mat = nullptr) override;
virtual G4double
GetIsoCrossSection(const G4DynamicParticle* dynPart,
G4int Z, G4int A,
const G4Isotope*,
const G4Element* elm,
const G4Material* mat);
virtual G4double
GetElementCrossSection(const G4DynamicParticle*, G4int Z,
const G4Material*);
G4double GetIsoCrossSection(const G4DynamicParticle*,
G4int Z, G4int A,
const G4Isotope* iso = nullptr,
const G4Element* elm = nullptr,
const G4Material* mat = nullptr) override;
G4double GetElementCrossSection(const G4DynamicParticle*, G4int Z,
const G4Material*) override;
G4double ComputeElementXSection(G4double energy, G4int Z);
G4double ComputeIsoXSection(G4double energy, G4int Z, G4int A);
G4PhotoNuclearCrossSection& operator=
(const G4PhotoNuclearCrossSection& right) = delete;
G4PhotoNuclearCrossSection(const G4PhotoNuclearCrossSection&) = delete;
private:
G4int GetFunctions(G4double a, G4double* y, G4double* z);
@@ -76,9 +81,6 @@ private:
const G4double XD, const G4double* Y);
G4double ThresholdEnergy(G4int Z, G4int N);
// Body
private:
G4int lastZ = 0; // The last Z of calculated nucleus
G4double lastSig = 0.0; // Last value of the Cross Section
G4double* lastGDR = nullptr; // Pointer to the last array of GDR cross sections
@@ -47,6 +47,7 @@ geant4_add_module(G4hadronic_xsect
G4GammaNuclearXS.hh
G4HadronNucleonXsc.hh
G4HadronXSDataTable.hh
G4InterfaceToXS.hh
G4IonsShenCrossSection.hh
G4KokoulinMuonNuclearXS.hh
G4MuNeutrinoNucleusTotXsc.hh
@@ -111,6 +112,7 @@ geant4_add_module(G4hadronic_xsect
G4GammaNuclearXS.cc
G4HadronNucleonXsc.cc
G4HadronXSDataTable.cc
G4InterfaceToXS.cc
G4IonsShenCrossSection.cc
G4KokoulinMuonNuclearXS.cc
G4MuNeutrinoNucleusTotXsc.cc
@@ -36,7 +36,7 @@
#include "G4ElementTable.hh"
#include "G4Material.hh"
#include "G4Element.hh"
#include "G4Isotope.hh"
#include "G4IsotopeList.hh"
#include "G4HadronicParameters.hh"
#include "Randomize.hh"
#include "G4SystemOfUnits.hh"
@@ -60,13 +60,9 @@ namespace {
const G4double pG0[5] = {2.55, 4.6, 3.7, 5.5, 4.6}; // g0
const G4double pG1[5] = {-0.23, -0.5, 0., 0., -2.}; // g1
// beta_prime value for calculation of cross section of pi0 and eta
// absorption inside different nuclei
const G4double beta_prime_pi = 0.0410;
const G4double beta_prime_eta = 0.0402;
}
G4ChargeExchangeXS::G4ChargeExchangeXS()
{
if (verboseLevel > 1) {
@@ -93,106 +89,119 @@ void G4ChargeExchangeXS::CrossSectionDescription(std::ostream& outFile) const
<< "pi+, pi-, K+, K-, KL\n";
}
G4bool G4ChargeExchangeXS::IsIsoApplicable(const G4DynamicParticle*,
G4int, G4int,
const G4Element*, const G4Material*)
G4bool G4ChargeExchangeXS::IsElementApplicable(const G4DynamicParticle*,
G4int, const G4Material*)
{
return true;
}
G4double
G4ChargeExchangeXS::GetIsoCrossSection(const G4DynamicParticle* aParticle,
G4int Z, G4int A,
const G4Isotope*, const G4Element*,
const G4Material*)
G4ChargeExchangeXS::GetElementCrossSection(const G4DynamicParticle* aParticle,
G4int ZZ, const G4Material* mat)
{
G4double result = 0.0;
const G4double pE = aParticle->GetTotalEnergy();
if (pE <= fEnergyLimit) { return result; }
if (pE <= fEnergyLimit) { return result; }
auto part = aParticle->GetDefinition();
G4int pdg = part->GetPDGEncoding();
// Get or calculate the nucleus mass, particle mass,particle kinetic energy
// and particle total energy
G4double tM = G4NucleiProperties::GetNuclearMass(A, Z);
G4double pM = part->GetPDGMass();
// Calculate s(lorentz invariant)
// Get or calculate the proton mass, particle mass, and s(Lorentz invariant)
G4double tM = CLHEP::proton_mass_c2;
G4double pM = part->GetPDGMass();
G4double lorentz_s = tM*tM + 2*tM*pE + pM*pM;
if (lorentz_s <= (tM + pM)*(tM + pM)) { return result; }
const G4int Z = std::min(ZZ, ZMAXNUCLEARDATA);
const G4int A = G4lrint(aeff[Z]);
if (verboseLevel > 1) {
G4cout << "### G4ChargeExchangeXS: " << part->GetParticleName()
<< " Z=" << Z << " A=" << A << " Etot(GeV)=" << pE/CLHEP::GeV
<< " s(GeV^2)=" << lorentz_s/(CLHEP::GeV*CLHEP::GeV) << G4endl;
}
// For unit conversion
const G4double inv1e7 = 1e-7;
const G4double inv1e7 = 0.1/(CLHEP::GeV*CLHEP::GeV);
const G4double fact = 1e-30*CLHEP::cm2;
const G4double pfact = 0.1/CLHEP::GeV;
const G4double kfact = 56.3*fact;
G4double logA = g4calc->logZ(A);
const G4double csmax = 1e-16;
// The approximation of Glauber-Gribov formula -> extend it from interaction with
// proton to nuclei Z^(2/3). The factor g4calc->powA(A,-beta_prime_pi*G4Log(A))
// proton to nuclei Z^(2/3). The factor g4calc->powA(A,-beta_prime_pi*G4Log(A))
// takes into account absorption of pi0 and eta
// pi- + p -> sum of (pi0 + eta) + n
// pi- + p -> n + meson (0- pi0, 1- eta, 2- eta', 3- omega, 4- f2(1270))
if (pdg == -211) {
const G4double z23 = g4calc->Z23(Z);
const G4int z = A/2;
const G4double a23 = g4calc->Z23(z);
const G4double x = lorentz_s*inv1e7;
G4double sum = 122.*z23*g4calc->powA(x, -1.23)*g4calc->powZ(A,-beta_prime_pi*logA);
fXSecPion[0] = sum;
sum += 31.*z23*g4calc->powA(x, -1.53)*g4calc->powZ(A,-beta_prime_eta*logA);
fXSecPion[1] = sum;
const G4double logX = G4Log(x);
for (G4int i=2; i<5; ++i) {
sum += piA[i]*z23*g4calc->powA(x, -pAP[i])*(1.0 + pG0[i] + pG1[i]*logX)
*g4calc->powA(z23, -0.15*a23)/(pC0[i] + pC1[i]*logX);
fXSecPion[i] = sum;
G4double z23 = g4calc->Z23(Z);
G4double x = lorentz_s*inv1e7;
G4double logX = G4Log(x);
G4double logA = g4calc->logZ(A);
G4double xf = g4calc->powZ(A, -beta_prime_pi*logA);
G4double sum = 0.0;
for (G4int i=0; i<5; ++i) {
G4double xg = std::max(1.0 + pG0[i] + pG1[i]*logX, 0.0);
G4double xc = std::max(pC0[i] + pC1[i]*logX, csmax);
G4double xs = z23*piA[i]*g4calc->powA(x, -pAP[i])*xf*xg/xc;
sum += xs;
fXSecPion[i] = sum;
}
result = sum*fact;
}
// pi+ + n -> sum of (pi0 + eta) + p
// pi+ + n -> p + meson (0- pi0, 1- eta, 2- eta', 3- omega, 4- f2(1270))
else if (pdg == 211) {
const G4double n23 = g4calc->Z23(A - Z);
const G4int z = A/2;
const G4double a23 = g4calc->Z23(z);
const G4double x = lorentz_s*inv1e7;
G4double sum = 122.*n23*g4calc->powA(x, -1.23)*g4calc->powZ(A,-beta_prime_pi*logA);
fXSecPion[0] = sum;
sum += 31.*n23*g4calc->powA(x, -1.53)*g4calc->powZ(A,-beta_prime_eta*logA);
fXSecPion[1] = sum;
const G4double logX = G4Log(x);
for (G4int i=2; i<5; ++i) {
sum += piA[i]*n23*g4calc->powA(x, -pAP[i])*(1.0 + pG0[i] + pG1[i]*logX)
*g4calc->powA(n23, -0.15*a23)/(pC0[i] + pC1[i]*logX);
fXSecPion[i] = sum;
G4double n23 = g4calc->Z23(A - Z);
G4double x = lorentz_s*inv1e7;
G4double logX = G4Log(x);
G4double logA = g4calc->logZ(A);
G4double xf = g4calc->powZ(A, -beta_prime_pi*logA);
// hydrogen target case Z = A = 1
// the cross section is defined by fraction of deuteron and tritium
if (1 == Z) { n23 = ComputeDeuteronFraction(mat); }
G4double sum = 0.0;
for (G4int i=0; i<5; ++i) {
G4double xg = std::max(1.0 + pG0[i] + pG1[i]*logX, 0.0);
G4double xc = std::max(pC0[i] + pC1[i]*logX, csmax);
G4double xs = n23*piA[i]*g4calc->powA(x, -pAP[i])*xf*xg/xc;
sum += xs;
fXSecPion[i] = sum;
}
result = sum*fact;
}
// Kaon x-sections depend on the primary particles momentum
// K- + p -> Kbar + n
else if (pdg == -321){
// Calculate the momentum of the bombarding particles and convert
// it to GeV/c^2 unit
const G4double p_momentum = std::sqrt(pE*pE - pM*pM)*pfact;
else if (pdg == -321) {
G4double p_momentum = std::sqrt(pE*pE - pM*pM)*pfact;
result = g4calc->Z23(Z)*g4calc->powA(p_momentum, -1.60)*kfact;
}
// K+ + n -> Kbar + p
else if (pdg == 321) {
const G4double p_momentum = std::sqrt(pE*pE - pM*pM)*pfact;
result = g4calc->Z23(A-Z)*g4calc->powA(p_momentum, -1.60)*kfact;
G4double p_momentum = std::sqrt(pE*pE - pM*pM)*pfact;
G4double n23 = g4calc->Z23(A-Z);
// hydrogen target case Z = A = 1
// the cross section is defined by fraction of deuteron and tritium
if (1 == Z) { n23 = ComputeDeuteronFraction(mat); }
result = n23*g4calc->powA(p_momentum, -1.60)*kfact;
}
// KL
else if (pdg == 130) {
// Cross section of K-long = 0.5*(Cross section of K+ + Cross section of K-)
// Cross section of KL = 0.5*(Cross section of K+ + Cross section of K-)
const G4double p_momentum = std::sqrt(pE*pE - pM*pM)*pfact;
result = 0.5*(g4calc->Z23(Z) + g4calc->Z23(A-Z))*
g4calc->powA(p_momentum, -1.60)*kfact;
}
return result*fFactor;
result *= fFactor;
if (verboseLevel > 1) {
G4cout << " Done for " << part->GetParticleName() << " Etot(GeV)=" << pE/CLHEP::GeV
<< " res(mb)=" << result/CLHEP::millibarn << G4endl;
}
return result;
}
const G4ParticleDefinition*
@@ -200,33 +209,35 @@ G4ChargeExchangeXS::SampleSecondaryType(const G4ParticleDefinition* part,
const G4int Z, const G4int A)
{
const G4ParticleDefinition* pd = nullptr;
G4int pdg = part->GetPDGEncoding();
G4int pdg = std::abs(part->GetPDGEncoding());
// pi- + p / pi+ + n
if (std::abs(pdg) == 211) {
const G4double x = fXSecPion[4]*G4UniformRand();
if (pdg == 211) {
pd = fPionSecPD[0];
G4double x = fXSecPion[4]*G4UniformRand();
for (G4int i=0; i<5; ++i) {
if (x <= fXSecPion[i]) {
return fPionSecPD[i];
pd = fPionSecPD[i];
break;
}
}
}
// K- + p / K+ + n
// Equal opportunity of producing k-short and k-long
else if (std::abs(pdg) == 321) {
if (G4UniformRand() > 0.5) {
pd = G4KaonZeroLong::KaonZeroLong();
else if (pdg == 321) {
if (G4UniformRand() >= 0.5) {
pd = G4KaonZeroLong::KaonZeroLong();
}
else {
pd = G4KaonZeroShort::KaonZeroShort();
}
}
// KL + atom
else if (std::abs(pdg) == 130) {
// KL + nucleus
else if (pdg == 130) {
G4double prob = (G4double)Z/(G4double)A;
if (G4UniformRand() > prob) {
if (G4UniformRand() >= prob) {
pd = G4KaonMinus::KaonMinus();
}
else {
@@ -236,3 +247,21 @@ G4ChargeExchangeXS::SampleSecondaryType(const G4ParticleDefinition* part,
return pd;
}
G4double
G4ChargeExchangeXS::ComputeDeuteronFraction(const G4Material* mat)
{
for (auto const & elm : *mat->GetElementVector()) {
if (1 == elm->GetZasInt()) {
G4double ab = 0.0;
const G4int nIso = (G4int)elm->GetNumberOfIsotopes();
const G4double* abu = elm->GetRelativeAbundanceVector();
for (G4int j = 0; j < nIso; ++j) {
auto const iso = elm->GetIsotope(j);
ab += (iso->GetN() - iso->GetZ())*abu[j];
}
return ab;
}
}
return 0.0;
}
@@ -239,9 +239,6 @@ G4double G4ChipsAntiBaryonInelasticXS::CalculateCrossSection(G4int F, G4int I,
static const G4double malP=G4Log(Pmax);// High logarithm energy (each 2.75 percent)
static const G4double dlP=(malP-milP)/(nH-1); // Step in log energy in the HEN part
static const G4double milPG=G4Log(.001*Pmin);// Low logarithmEnergy for HEN part GeV/c
G4double sigma=0.;
if(F&&I) sigma=0.; // @@ *!* Fake line *!* to use F & I !!!Temporary!!!
//G4double A=targN+targZ; // A of the target
if(F<=0) // This isotope was not the last used isotop
{
if(F<0) // This isotope was found in DAMDB =-----=> RETRIEVE
@@ -282,6 +279,7 @@ G4double G4ChipsAntiBaryonInelasticXS::CalculateCrossSection(G4int F, G4int I,
} // End of creation of the new set of parameters
} // End of parameters udate
// =-------------------= NOW the Magic Formula =--------------------=
G4double sigma;
if (Momentum<lastTH) return 0.; // It must be already checked in the interface class
else if (Momentum<Pmin) // High Energy region
{
@@ -89,37 +89,6 @@ G4bool G4ChipsHyperonInelasticXS::IsIsoApplicable(const G4DynamicParticle*, G4in
const G4Element*,
const G4Material*)
{
/*
const G4ParticleDefinition* particle = Pt->GetDefinition();
if (particle == G4Lambda::Lambda())
{
return true;
}
else if(particle == G4SigmaPlus::SigmaPlus())
{
return true;
}
else if(particle == G4SigmaMinus::SigmaMinus())
{
return true;
}
else if(particle == G4SigmaZero::SigmaZero())
{
return true;
}
else if(particle == G4XiMinus::XiMinus())
{
return true;
}
else if(particle == G4XiZero::XiZero())
{
return true;
}
else if(particle == G4OmegaMinus::OmegaMinus())
{
return true;
}
*/
return true;
}
@@ -180,8 +149,6 @@ G4double G4ChipsHyperonInelasticXS::GetChipsCrossSection(G4double pMom, G4int tg
{
//!!The slave functions must provide cross-sections in millibarns (mb) !! (not in IU)
lastCS=CalculateCrossSection(0,j,PDG,lastZ,lastN,pMom); //calculate & create
//if(lastCS>0.) // It means that the AMBD was initialized
//{
lastTH = 0; //ThresholdEnergy(tgZ, tgN); // The Threshold Energy which is now the last
colN.push_back(tgN);
@@ -226,9 +193,7 @@ G4double G4ChipsHyperonInelasticXS::CalculateCrossSection(G4int F, G4int I,
static const G4double malP=G4Log(Pmax);// High logarithm energy (each 2.75 percent)
static const G4double dlP=(malP-milP)/(nH-1); // Step in log energy in the HEN part
static const G4double milPG=G4Log(.001*Pmin);// Low logarithmEnergy for HEN part GeV/c
G4double sigma=0.;
if(F&&I) sigma=0.; // @@ *!* Fake line *!* to use F & I !!!Temporary!!!
//G4double A=targN+targZ; // A of the target
if(F<=0) // This isotope was not the last used isotop
{
if(F<0) // This isotope was found in DAMDB =-----=> RETRIEVE
@@ -269,6 +234,7 @@ G4double G4ChipsHyperonInelasticXS::CalculateCrossSection(G4int F, G4int I,
} // End of creation of the new set of parameters
} // End of parameters udate
// =--------------------------= NOW the Magic Formula =------------------------------=
G4double sigma;
if (Momentum<lastTH) return 0.; // It must be already checked in the interface class
else if (Momentum<Pmin) // High Energy region
{
@@ -284,7 +250,7 @@ G4double G4ChipsHyperonInelasticXS::CalculateCrossSection(G4int F, G4int I,
G4double P=0.001*Momentum; // Approximation formula is for P in GeV/c
sigma=CrossSectionFormula(targZ, targN, P, G4Log(P));
}
if(sigma<0.) return 0.;
if (sigma<0.) return 0.;
return sigma;
}
@@ -193,9 +193,6 @@ G4double G4ChipsKaonMinusInelasticXS::GetChipsCrossSection(G4double pMom, G4int
G4double G4ChipsKaonMinusInelasticXS::CalculateCrossSection(G4int F, G4int I,
G4int, G4int targZ, G4int targN, G4double Momentum)
{
G4double sigma=0.;
if(F&&I) sigma=0.; // @@ *!* Fake line *!* to use F & I !!!Temporary!!!
//G4double A=targN+targZ; // A of the target
if(F<=0) // This isotope was not the last used isotop
{
if(F<0) // This isotope was found in DAMDB =-----=> RETRIEVE
@@ -234,8 +231,9 @@ G4double G4ChipsKaonMinusInelasticXS::CalculateCrossSection(G4int F, G4int I,
LEN->push_back(lastLEN); // remember the Low Energy Table
HEN->push_back(lastHEN); // remember the High Energy Table
} // End of creation of the new set of parameters
} // End of parameters udate
} // End of parameters update
// =------------------= NOW the Magic Formula =--------------------------=
G4double sigma;
if (Momentum<lastTH) return 0.; // It must be already checked in the interface class
else if (Momentum<Pmin) // High Energy region
{
@@ -212,8 +212,6 @@ G4double G4ChipsKaonPlusInelasticXS::GetChipsCrossSection(G4double pMom, G4int t
G4double G4ChipsKaonPlusInelasticXS::CalculateCrossSection(G4int F, G4int I,
G4int, G4int targZ, G4int targN, G4double Momentum)
{
G4double sigma=0.;
if(F&&I) sigma=0.; // @@ *!* Fake line *!* to use F & I !!!Temporary!!!
G4double A=targN+targZ; // A of the target
if(F<=0) // This isotope was not the last used isotop
@@ -257,6 +255,7 @@ G4double G4ChipsKaonPlusInelasticXS::CalculateCrossSection(G4int F, G4int I,
} // End of parameters udate
// =--------------------------= NOW the Magic Formula =---------------------------------=
G4double sigma;
if (Momentum<lastTH) return 0.; // It must be already checked in the interface class
else if (Momentum<Pmin) // Low Energy region
{
@@ -195,11 +195,6 @@ G4double G4ChipsNeutronInelasticXS::CalculateCrossSection(G4int F, G4int I,
static const G4double dlP=(malP-milP)/(nH-1); // Step in log energy in the HEN part
static const G4double milPG=G4Log(.001*Pmin);// Low logarithmEnergy for HEN part GeV/c
//
// Associative memory for acceleration
//static std::vector <G4double> spA; // shadowing coefficients (A-dependent)
G4double sigma=0.;
if(F&&I) sigma=0.; // @@ *!* Fake line *!* to use F & I !!!Temporary!!!
//G4double A=targN+targZ; // A of the target
if(F<=0) // This isotope was not the last used isotop
{
if(F<0) // This isotope was found in DAMDB =-----=> RETRIEVE
@@ -240,6 +235,7 @@ G4double G4ChipsNeutronInelasticXS::CalculateCrossSection(G4int F, G4int I,
} // End of creation of the new set of parameters
} // End of parameters udate
// =------------------= NOW the Magic Formula =---------------------------=
G4double sigma;
if (Momentum<lastTH) return 0.; // It must be already checked in the interface class
else if (Momentum<Pmin) // High Energy region
{
@@ -192,9 +192,6 @@ G4double G4ChipsPionMinusInelasticXS::CalculateCrossSection(G4int F, G4int I,
static const G4double malP=G4Log(Pmax);// High logarithm energy (each 2.75 percent)
static const G4double dlP=(malP-milP)/(nH-1); // Step in log energy in the HEN part
static const G4double milPG=G4Log(.001*Pmin);// Low logarithmEnergy for HEN part GeV/c
G4double sigma=0.;
if(F&&I) sigma=0.; // @@ *!* Fake line *!* to use F & I !!!Temporary!!!
//G4double A=targN+targZ; // A of the target
if(F<=0) // This isotope was not the last used isotop
{
if(F<0) // This isotope was found in DAMDB =-----=> RETRIEVE
@@ -235,6 +232,7 @@ G4double G4ChipsPionMinusInelasticXS::CalculateCrossSection(G4int F, G4int I,
} // End of creation of the new set of parameters
} // End of parameters udate
// =---------------------= NOW the Magic Formula =---------------------------=
G4double sigma;
if (Momentum<lastTH) return 0.; // It must be already checked in the interface class
else if (Momentum<Pmin) // High Energy region
{
@@ -194,9 +194,7 @@ G4double G4ChipsPionPlusInelasticXS::CalculateCrossSection(G4int F, G4int I,
static const G4double malP=G4Log(Pmax);// High logarithm energy (each 2.75 percent)
static const G4double dlP=(malP-milP)/(nH-1); // Step in log energy in the HEN part
static const G4double milPG=G4Log(.001*Pmin);// Low logarithmEnergy for HEN part GeV/c
G4double sigma=0.;
if(F&&I) sigma=0.; // @@ *!* Fake line *!* to use F & I !!!Temporary!!!
//G4double A=targN+targZ; // A of the target
if(F<=0) // This isotope was not the last used isotop
{
if(F<0) // This isotope was found in DAMDB =-----=> RETRIEVE
@@ -237,6 +235,7 @@ G4double G4ChipsPionPlusInelasticXS::CalculateCrossSection(G4int F, G4int I,
} // End of creation of the new set of parameters
} // End of parameters udate
// =-----------------= NOW the Magic Formula =-------------------------=
G4double sigma;
if (Momentum<lastTH) return 0.; // It must be already checked in the interface class
else if (Momentum<Pmin) // High Energy region
{
@@ -252,7 +251,7 @@ G4double G4ChipsPionPlusInelasticXS::CalculateCrossSection(G4int F, G4int I,
G4double P=0.001*Momentum; // Approximation formula is for P in GeV/c
sigma=CrossSectionFormula(targZ, targN, P, G4Log(P));
}
if(sigma<0.) return 0.;
if (sigma<0.) return 0.;
return sigma;
}
@@ -196,9 +196,6 @@ G4double G4ChipsProtonInelasticXS::CalculateCrossSection(G4int F, G4int I,
static const G4double malP=G4Log(Pmax);// High logarithm energy (each 2.75 percent)
static const G4double dlP=(malP-milP)/(nH-1); // Step in log energy in the HEN part
static const G4double milPG=G4Log(.001*Pmin);// Low logarithmEnergy for HEN part GeV/c
G4double sigma=0.;
if(F&&I) sigma=0.; // @@ *!* Fake line *!* to use F & I !!!Temporary!!!
//G4double A=targN+targZ; // A of the target
if(F<=0) // This isotope was not the last used isotop
{
if(F<0) // This isotope was found in DAMDB =-----=> RETRIEVE
@@ -239,6 +236,7 @@ G4double G4ChipsProtonInelasticXS::CalculateCrossSection(G4int F, G4int I,
} // End of creation of the new set of parameters
} // End of parameters udate
// =------------------= NOW the Magic Formula =-----------------------=
G4double sigma;
if (Momentum<lastTH) return 0.; // It must be already checked in the interface class
else if (Momentum<Pmin) // High Energy region
{
@@ -139,7 +139,8 @@ G4double G4EMDissociationCrossSection::GetElementCrossSection
const G4ParticleDefinition *definitionP = theDynamicParticle->GetDefinition();
G4double AP = definitionP->GetBaryonNumber();
G4double ZP = definitionP->GetPDGCharge();
G4double b = theDynamicParticle->Get4Momentum().beta();
G4double b = theDynamicParticle->GetBeta();
if (b <= 0.0 && b >= 1.0) { return 0.0; }
G4double AT = G4NistManager::Instance()->GetAtomicMassAmu(Z);
G4double ZT = (G4double)Z;
@@ -179,7 +180,7 @@ G4EMDissociationCrossSection::GetCrossSectionForProjectile (G4double AP,
//
// Initialise variables and calculate the energies for the GDR and GQR.
//
G4double AProot3 = G4Pow::GetInstance()->powA(AP,1.0/3.0);
G4double AProot3 = G4Pow::GetInstance()->A13(AP);
G4double u = 3.0 * J / Qprime / AProot3;
G4double R0 = r0 * AProot3;
G4double E_GDR = hbarc / std::sqrt(0.7*amu_c2*R0*R0/8.0/J*
@@ -63,11 +63,18 @@ G4ElementData* G4GammaNuclearXS::data = nullptr;
G4double G4GammaNuclearXS::coeff[3][3];
G4double G4GammaNuclearXS::xs150[] = {0.0};
const G4double G4GammaNuclearXS::eTransitionBound = 150.*CLHEP::MeV;
const G4int G4GammaNuclearXS::freeVectorException[] = {
4, 6, 7, 8, 27, 39, 45, 65, 67, 69, 73};
G4String G4GammaNuclearXS::gDataDirectory = "";
namespace
{
// Upper limit of the linear transition between IAEA database and CHIPS model
const G4double eTransitionBound = 150.*CLHEP::MeV;
// A limit energy to correct CHIPS parameterisation for light isotopes
const G4double ehigh = 10*CLHEP::GeV;
}
G4GammaNuclearXS::G4GammaNuclearXS()
: G4VCrossSectionDataSet(Default_Name()), gamma(G4Gamma::Gamma())
{
@@ -76,10 +83,11 @@ G4GammaNuclearXS::G4GammaNuclearXS()
G4cout << "G4GammaNuclearXS::G4GammaNuclearXS Initialise for Z < "
<< MAXZGAMMAXS << G4endl;
}
ggXsection =
G4CrossSectionDataSetRegistry::Instance()->GetCrossSectionDataSet("PhotoNuclearXS");
if (ggXsection == nullptr)
ggXsection = dynamic_cast<G4PhotoNuclearCrossSection*>
(G4CrossSectionDataSetRegistry::Instance()->GetCrossSectionDataSet("PhotoNuclearXS"));
if (ggXsection == nullptr) {
ggXsection = new G4PhotoNuclearCrossSection();
}
SetForAllAtomsAndEnergies(true);
// full data set is uploaded once
@@ -117,18 +125,30 @@ G4bool G4GammaNuclearXS::IsIsoApplicable(const G4DynamicParticle*,
G4double
G4GammaNuclearXS::GetElementCrossSection(const G4DynamicParticle* aParticle,
G4int ZZ, const G4Material* mat)
G4int Z, const G4Material*)
{
return ElementCrossSection(aParticle->GetKineticEnergy(), Z);
}
G4double
G4GammaNuclearXS::ElementCrossSection(const G4double ekin, const G4int ZZ)
{
// check cache
const G4int Z = (ZZ < MAXZGAMMAXS) ? ZZ : MAXZGAMMAXS - 1;
const G4double ekin = aParticle->GetKineticEnergy();
if(Z == fZ && ekin == fEkin) { return fXS; }
fZ = Z;
fEkin = ekin;
auto pv = data->GetElementData(Z);
if(pv == nullptr || 1 == Z) {
fXS = ggXsection->GetElementCrossSection(aParticle, Z, mat);
const G4double limCHIPS1 = 25*CLHEP::MeV;
const G4double limCHIPS2 = 16*CLHEP::MeV;
if (pv == nullptr || 1 == Z || Z == 40 || Z == 74 ||
(Z == 24 && ekin >= limCHIPS1) ||
(Z == 39 && ekin >= limCHIPS1) ||
(Z == 50 && ekin >= limCHIPS2) ||
(Z == 64 && ekin >= limCHIPS2)
) {
fXS = ggXsection->ComputeElementXSection(ekin, Z);
return fXS;
}
const G4double emax = pv->GetMaxEnergy();
@@ -138,7 +158,7 @@ G4GammaNuclearXS::GetElementCrossSection(const G4DynamicParticle* aParticle,
fXS = pv->Value(ekin);
// high energy CHIPS parameterisation
} else if(ekin >= eTransitionBound) {
fXS = ggXsection->GetElementCrossSection(aParticle, Z, mat);
fXS = ggXsection->ComputeElementXSection(ekin, Z);
// linear interpolation
} else {
const G4double rxs = xs150[Z];
@@ -156,12 +176,6 @@ G4GammaNuclearXS::GetElementCrossSection(const G4DynamicParticle* aParticle,
return fXS;
}
G4double G4GammaNuclearXS::ElementCrossSection(G4double ekin, G4int ZZ)
{
G4DynamicParticle theGamma(gamma, G4ThreeVector(1,0,0), ekin);
return GetElementCrossSection(&theGamma, ZZ);
}
G4double G4GammaNuclearXS::LowEnergyCrossSection(G4double ekin, G4int ZZ)
{
const G4int Z = (ZZ < MAXZGAMMAXS) ? ZZ : MAXZGAMMAXS - 1;
@@ -169,31 +183,29 @@ G4double G4GammaNuclearXS::LowEnergyCrossSection(G4double ekin, G4int ZZ)
return pv->Value(ekin);
}
G4double
G4GammaNuclearXS::IsoCrossSection(G4double ekin, G4int Z, G4int A)
{
G4DynamicParticle theGamma(gamma, G4ThreeVector(1,0,0), ekin);
return GetIsoCrossSection(&theGamma, Z, A);
}
G4double G4GammaNuclearXS::GetIsoCrossSection(
const G4DynamicParticle* aParticle,
G4int ZZ, G4int A,
const G4Isotope*, const G4Element*, const G4Material* mat)
G4int Z, G4int A,
const G4Isotope*, const G4Element*, const G4Material*)
{
return IsoCrossSection(aParticle->GetKineticEnergy(), Z, A);
}
G4double
G4GammaNuclearXS::IsoCrossSection(const G4double ekin, const G4int ZZ, const G4int A)
{
const G4int Z = (ZZ < MAXZGAMMAXS) ? ZZ : MAXZGAMMAXS - 1;
// cross section per element
G4double xs = GetElementCrossSection(aParticle, Z, mat);
const G4double ekin = aParticle->GetKineticEnergy();
G4double xs = ElementCrossSection(ekin, Z);
if (Z > 2) {
xs *= A/aeff[Z];
} else {
G4int AA = A - amin[Z];
if(ekin >= 10.*CLHEP::GeV && AA >=0 && AA <=2) {
if(ekin >= ehigh && AA >=0 && AA <=2) {
xs *= coeff[Z][AA];
} else {
xs = ggXsection->GetIsoCrossSection(aParticle, Z, A);
xs = ggXsection->ComputeIsoXSection(ekin, Z, A);
}
}
@@ -258,7 +270,7 @@ void G4GammaNuclearXS::BuildPhysicsTable(const G4ParticleDefinition& p)
// prepare isotope selection
const G4ElementTable* table = G4Element::GetElementTable();
std::size_t nIso = temp.size();
for ( auto & elm : *table ) {
for (auto const & elm : *table ) {
std::size_t n = elm->GetNumberOfIsotopes();
if (n > nIso) { nIso = n; }
}
@@ -289,18 +301,16 @@ void G4GammaNuclearXS::Initialise(G4int Z)
<< " A= " << Amean << " Amin= " << amin[Z]
<< " Amax= " << amax[Z] << G4endl;
*/
G4DynamicParticle theGamma(gamma, G4ThreeVector(1,0,0), eTransitionBound);
xs150[Z] = ggXsection->GetElementCrossSection(&theGamma, Z, 0);
xs150[Z] = ggXsection->ComputeElementXSection(eTransitionBound, Z);
// compute corrections for low Z data
if(Z <= 2){
theGamma.SetKineticEnergy(10*CLHEP::GeV);
if(amax[Z] > amin[Z]) {
for(G4int A=amin[Z]; A<=amax[Z]; ++A) {
G4int AA = A - amin[Z];
if(AA >= 0 && AA <= 2) {
G4double sig1 = ggXsection->GetIsoCrossSection(&theGamma, Z, A);
G4double sig2 = ggXsection->GetElementCrossSection(&theGamma, Z, 0);
G4double sig1 = ggXsection->ComputeIsoXSection(ehigh, Z, A);
G4double sig2 = ggXsection->ComputeElementXSection(ehigh, Z);
if(sig2 > 0.) { coeff[Z][AA] = (sig1/sig2); }
else { coeff[Z][AA] = 1.; }
}
@@ -62,13 +62,27 @@ G4HadronXSDataTable::G4HadronXSDataTable()
G4HadronXSDataTable::~G4HadronXSDataTable()
{
for (auto & ptr : fPiData) {
for (std::size_t i = 0; i < fPiData.size(); ++i) {
auto ptr = fPiData[i];
for (std::size_t j = 0; j < ptr->size(); ++j) {
auto p = (*ptr)[j];
for (std::size_t k = i + 1; k < fPiData.size(); ++k) {
auto qtr = fPiData[k];
for (std::size_t l = 0; l < qtr->size(); ++l) {
if ((*qtr)[l] == p) { (*qtr)[l] = nullptr; }
}
}
delete p;
(*ptr)[j] = nullptr;
}
delete ptr;
}
for (auto & ptr : fTable) {
fPiData.clear();
for (auto const & ptr : fTable) {
ptr->clearAndDestroy();
delete ptr;
}
fTable.clear();
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
@@ -76,16 +90,10 @@ G4HadronXSDataTable::~G4HadronXSDataTable()
void G4HadronXSDataTable::AddPiData(std::vector<G4PiData*>* ptr)
{
if (nullptr == ptr || ptr->empty()) { return; }
for (auto & p : *ptr) {
G4bool ok = true;
for (auto & d : fPiData) {
if (p == d) {
ok = false;
break;
}
}
if (ok) { fPiData.push_back(p); }
for (auto & d : fPiData) {
if (ptr == d) { return; }
}
fPiData.push_back(ptr);
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
@@ -0,0 +1,95 @@
//
// ********************************************************************
// * License and Disclaimer *
// * *
// * The Geant4 software is copyright of the Copyright Holders of *
// * the Geant4 Collaboration. It is provided under the terms and *
// * conditions of the Geant4 Software License, included in the file *
// * LICENSE and available at http://cern.ch/geant4/license . These *
// * include a list of copyright holders. *
// * *
// * Neither the authors of this software system, nor their employing *
// * institutes,nor the agencies providing financial support for this *
// * work make any representation or warranty, express or implied, *
// * regarding this software system or assume any liability for its *
// * use. Please see the license in the file LICENSE and URL above *
// * for the full disclaimer and the limitation of liability. *
// * *
// * This code implementation is the result of the scientific and *
// * technical work of the GEANT4 collaboration. *
// * By using, copying, modifying or distributing the software (or *
// * any work based on the software) you agree to acknowledge its *
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
// GEANT4 Class file
//
// File name: G4InterfaceToXS
//
// Authors V.Ivantchenko 12 July 2024
//
// The interface provide access to inelastic cross section of gamma,
// neutrons, and light ions based on G4PARTICLEXS evaluated data.
// The only one instance of the cross section class exist in each thread.
// This class may be used by any model, cross section or other classes.
#include "G4InterfaceToXS.hh"
#include "G4ParticleDefinition.hh"
#include "G4GammaNuclearXS.hh"
#include "G4NeutronInelasticXS.hh"
#include "G4ParticleInelasticXS.hh"
#include "G4CrossSectionDataSetRegistry.hh"
#include "G4Log.hh"
G4InterfaceToXS::G4InterfaceToXS(const G4ParticleDefinition* p, G4int idx)
: index(idx), fParticle(p)
{
auto reg = G4CrossSectionDataSetRegistry::Instance();
if (index == 0) {
fNeutronNuclear =
dynamic_cast<G4NeutronInelasticXS*>(reg->GetCrossSectionDataSet("G4NeutronInelasticXS"));
if (nullptr == fNeutronNuclear) { fNeutronNuclear = new G4NeutronInelasticXS(); }
fNeutronNuclear->BuildPhysicsTable(*fParticle);
} else if (index > 0 && index < 6) {
const G4String pname[6] = {"neutron", "proton", "deuteron", "triton", "He3", "alpha"};
const G4String& ss = pname[index] + "ParticleXS";
fParticleNuclear =
dynamic_cast<G4ParticleInelasticXS*>(reg->GetCrossSectionDataSet(ss));
if (nullptr == fParticleNuclear) { fParticleNuclear = new G4ParticleInelasticXS(fParticle); }
fParticleNuclear->BuildPhysicsTable(*fParticle);
} else if (index == 6) {
fGammaNuclear =
dynamic_cast<G4GammaNuclearXS*>(reg->GetCrossSectionDataSet("GammaNuclearXS"));
if (nullptr == fGammaNuclear) { fGammaNuclear = new G4GammaNuclearXS(); }
fGammaNuclear->BuildPhysicsTable(*fParticle);
}
}
G4double G4InterfaceToXS::GetElementCrossSection(const G4double ekin, const G4int Z)
{
G4double res = 0.0;
if (ekin <= 0.0) { return res; }
if (nullptr != fNeutronNuclear) {
res = fNeutronNuclear->ElementCrossSection(ekin, G4Log(ekin), Z);
} else if (nullptr != fParticleNuclear) {
res = fParticleNuclear->ElementCrossSection(ekin, G4Log(ekin), Z);
} else if (nullptr != fGammaNuclear) {
res = fGammaNuclear->ElementCrossSection(ekin, Z);
}
return res;
}
G4double G4InterfaceToXS::GetIsoCrossSection(const G4double ekin, const G4int Z, const G4int A)
{
G4double res = 0.0;
if (ekin <= 0.0) { return res; }
if (nullptr != fNeutronNuclear) {
res = fNeutronNuclear->IsoCrossSection(ekin, G4Log(ekin), Z, A);
} else if (nullptr != fParticleNuclear) {
res = fParticleNuclear->IsoCrossSection(ekin, G4Log(ekin), Z, A);
} else if (nullptr != fGammaNuclear) {
res = fGammaNuclear->IsoCrossSection(ekin, Z, A);
}
return res;
}
@@ -77,6 +77,7 @@ G4NeutronElasticXS::G4NeutronElasticXS()
if (ggXsection == nullptr)
ggXsection = new G4ComponentGGHadronNucleusXsc();
SetForAllAtomsAndEnergies(true);
FindDirectoryPath();
}
G4NeutronElasticXS::~G4NeutronElasticXS()
@@ -47,6 +47,7 @@
#include "G4Neutron.hh"
#include "G4SystemOfUnits.hh"
#include "G4IsotopeList.hh"
#include "G4NuclearRadii.hh"
#include "G4AutoLock.hh"
#include <fstream>
@@ -54,6 +55,7 @@
#include <thread>
G4double G4NeutronInelasticXS::coeff[] = {1.0};
G4double G4NeutronInelasticXS::lowcoeff[] = {1.0};
G4ElementData* G4NeutronInelasticXS::data = nullptr;
G4String G4NeutronInelasticXS::gDataDirectory = "";
@@ -68,10 +70,10 @@ G4NeutronInelasticXS::G4NeutronInelasticXS()
: G4VCrossSectionDataSet(Default_Name()),
neutron(G4Neutron::Neutron()),
elimit(20*CLHEP::MeV),
lowElimit(1.0e-5*CLHEP::eV)
lowElimit(1.0e-7*CLHEP::eV)
{
verboseLevel = 0;
if (verboseLevel > 0){
if (verboseLevel > 0) {
G4cout << "G4NeutronInelasticXS::G4NeutronInelasticXS Initialise for Z < "
<< MAXZINEL << G4endl;
}
@@ -136,6 +138,9 @@ G4NeutronInelasticXS::ElementCrossSection(G4double eKin, G4double logE, G4int ZZ
G4int Z = std::min(ZZ, MAXZINEL-1);
G4double ekin = eKin;
G4double loge = logE;
G4double xs;
// very low energy limit
if (ekin < lowElimit) {
ekin = lowElimit;
loge = loglowElimit;
@@ -144,8 +149,7 @@ G4NeutronInelasticXS::ElementCrossSection(G4double eKin, G4double logE, G4int ZZ
auto pv = GetPhysicsVector(Z);
const G4double e0 = pv->Energy(0);
G4double xs;
if (ekin < e0) {
if (ekin <= e0) {
xs = (*pv)[0];
if (xs > 0.0) { xs *= std::sqrt(e0/ekin); }
} else if (ekin <= pv->GetMaxEnergy()) {
@@ -190,14 +194,10 @@ G4double
G4NeutronInelasticXS::IsoCrossSection(G4double eKin, G4double logE,
G4int ZZ, G4int A)
{
G4double xs = 0.0;
G4double xs;
G4int Z = std::min(ZZ, MAXZINEL-1);
G4double ekin = eKin;
G4double loge = logE;
if (ekin < lowElimit) {
ekin = lowElimit;
loge = loglowElimit;
}
/*
G4cout << "G4NeutronInelasticXS::IsoCrossSection Z= "
@@ -206,13 +206,14 @@ G4NeutronInelasticXS::IsoCrossSection(G4double eKin, G4double logE,
<< " E(MeV)= " << ekin << " Ncomp="
<< data->GetNumberOfComponents(Z) << G4endl;
*/
GetPhysicsVector(Z);
// use isotope cross section if applicable
if (ekin <= elimit && data->GetNumberOfComponents(Z) > 0) {
auto pviso = data->GetComponentDataByID(Z, A);
if (nullptr != pviso) {
const G4double e0 = pviso->Energy(0);
if (ekin >= e0) {
if (ekin > e0) {
xs = pviso->LogVectorValue(ekin, loge);
} else {
xs = (*pviso)[0];
@@ -229,20 +230,9 @@ G4NeutronInelasticXS::IsoCrossSection(G4double eKin, G4double logE,
return xs;
}
}
// use element x-section
auto pv = GetPhysicsVector(Z);
const G4double e0 = pv->Energy(0);
if (ekin < e0) {
xs = (*pv)[0];
if (xs > 0.0) { xs *= std::sqrt(e0/ekin); }
} else if (ekin <= pv->GetMaxEnergy()) {
xs = pv->LogVectorValue(ekin, loge);
} else {
xs = coeff[Z]*ggXsection->GetInelasticElementCrossSection(neutron, ekin,
Z, aeff[Z]);
}
xs *= A/aeff[Z];
xs = ElementCrossSection(ekin, loge, Z)*A/aeff[Z];
#ifdef G4VERBOSE
if(verboseLevel > 1) {
@@ -401,7 +391,7 @@ void G4NeutronInelasticXS::Initialise(G4int Z)
G4double ehigh= v->GetMaxEnergy();
G4double sig2 = ggXsection->GetInelasticElementCrossSection(neutron,
ehigh, Z, aeff[Z]);
coeff[Z] = (sig2 > 0.) ? sig1/sig2 : 1.0;
coeff[Z] = (sig2 > 0.) ? sig1/sig2 : 1.0;
}
G4PhysicsVector*
@@ -55,13 +55,10 @@
#include <fstream>
#include <sstream>
#include <thread>
G4ElementData* G4ParticleInelasticXS::data[] = {nullptr, nullptr, nullptr, nullptr, nullptr};
G4double G4ParticleInelasticXS::coeff[MAXZINELP][5] = {{1.0}, {1.0}, {1.0}, {1.0}, {1.0}};
G4String G4ParticleInelasticXS::gDataDirectory[] = {"", "", "", "", ""};
static std::once_flag applyOnce;
G4String G4ParticleInelasticXS::gDataDirectory = {""};
namespace
{
@@ -74,7 +71,7 @@ G4ParticleInelasticXS::G4ParticleInelasticXS(const G4ParticleDefinition* part)
particle(part),
elimit(20*CLHEP::MeV)
{
if(nullptr == part) {
if (nullptr == part) {
G4Exception("G4ParticleInelasticXS::G4ParticleInelasticXS(..)","had015",
FatalException, "NO particle definition in constructor");
} else {
@@ -85,7 +82,7 @@ G4ParticleInelasticXS::G4ParticleInelasticXS(const G4ParticleDefinition* part)
<< particleName << " on atoms with Z < " << MAXZINELP << G4endl;
}
auto xsr = G4CrossSectionDataSetRegistry::Instance();
if(particleName == "proton") {
if (particleName == "proton") {
highEnergyXsection = xsr->GetComponentCrossSection("Glauber-Gribov");
if(highEnergyXsection == nullptr) {
highEnergyXsection = new G4ComponentGGHadronNucleusXsc();
@@ -99,22 +96,19 @@ G4ParticleInelasticXS::G4ParticleInelasticXS(const G4ParticleDefinition* part)
for (index=1; index<5; ++index) {
if (particleName == pname[index]) { break; }
}
if (index == 5) {
G4ExceptionDescription ed;
ed << particleName << " is a wrong particle type";
G4Exception("G4ParticleInelasticXS::BuildPhysicsTable(..)","had012",
FatalException, ed, "");
}
index = std::min(index, 4);
if (1 < index) { SetMaxKinEnergy(25.6*CLHEP::PeV); }
}
}
SetForAllAtomsAndEnergies(true);
if (data[0] == nullptr) {
for (G4int i=0; i<5; ++i) {
data[i] = new G4ElementData(MAXZINELP);
data[i]->SetName(pname[i] + "IonInel");
}
FindDirectoryPath();
if (gDataDirectory.empty()) {
gDataDirectory = G4HadronicParameters::Instance()->GetDirPARTICLEXS();
}
G4String ss = pname[index] + "ParticleXS";
SetName(ss);
if (data[index] == nullptr) {
data[index] = new G4ElementData(MAXZINELP);
data[index]->SetName(pname[index] + "PartInel");
}
}
@@ -162,11 +156,17 @@ G4ParticleInelasticXS::ComputeCrossSectionPerElement(G4double ekin, G4double log
G4double G4ParticleInelasticXS::ElementCrossSection(G4double ekin, G4double loge, G4int ZZ)
{
G4int Z = (ZZ >= MAXZINELP) ? MAXZINELP - 1 : ZZ;
// element data is always valid pointer by construction of XS
auto pv = GetPhysicsVector(Z);
G4double xs = (ekin <= pv->GetMaxEnergy()) ? pv->LogVectorValue(ekin, loge)
// set to null x-section below lowest energy in the table
G4double xs = 0.0;
if (ekin > pv->Energy(0)) {
xs = (ekin <= pv->GetMaxEnergy()) ? pv->LogVectorValue(ekin, loge)
: coeff[Z][index]*highEnergyXsection->GetInelasticElementCrossSection(particle,
ekin, Z, aeff[Z]);
}
#ifdef G4VERBOSE
if(verboseLevel > 1) {
@@ -203,12 +203,14 @@ G4ParticleInelasticXS::IsoCrossSection(G4double ekin, G4double logE,
{
G4double xs = 0.0;
G4int Z = (ZZ >= MAXZINELP) ? MAXZINELP - 1 : ZZ;
// needed here to gurantee upload data for Z
auto pv = GetPhysicsVector(Z);
// compute isotope cross section if applicable
if (ekin <= elimit && data[index]->GetNumberOfComponents(Z) > 0) {
auto pviso = data[index]->GetComponentDataByID(Z, A);
if(pviso != nullptr) {
if (pviso != nullptr && ekin > pviso->Energy(0)) {
xs = pviso->LogVectorValue(ekin, logE);
#ifdef G4VERBOSE
if(verboseLevel > 1) {
@@ -223,11 +225,12 @@ G4ParticleInelasticXS::IsoCrossSection(G4double ekin, G4double logE,
}
}
// use element x-section
xs = (ekin <= pv->GetMaxEnergy()) ? pv->LogVectorValue(ekin, logE)
: coeff[Z][index] *
highEnergyXsection->GetInelasticElementCrossSection(particle,
ekin, Z, aeff[Z]);
xs *= A/aeff[Z];
if (ekin > pv->Energy(0)) {
xs = (ekin <= pv->GetMaxEnergy()) ? pv->LogVectorValue(ekin, logE) :
coeff[Z][index] *
highEnergyXsection->GetInelasticElementCrossSection(particle, ekin, Z, aeff[Z])
* A/aeff[Z];
}
#ifdef G4VERBOSE
if(verboseLevel > 1) {
G4cout << "IsoXS for " << particle->GetParticleName()
@@ -250,7 +253,9 @@ const G4Isotope* G4ParticleInelasticXS::SelectIsotope(
// more than 1 isotope
G4int Z = anElement->GetZasInt();
if (nullptr == data[index]->GetElementData(Z)) { InitialiseOnFly(Z); }
// initialisation for given Z
GetPhysicsVector(Z);
const G4double* abundVector = anElement->GetRelativeAbundanceVector();
G4double q = G4UniformRand();
@@ -306,89 +311,62 @@ G4ParticleInelasticXS::BuildPhysicsTable(const G4ParticleDefinition& p)
// it is possible re-initialisation for the new run
const G4ElementTable* table = G4Element::GetElementTable();
// initialise static tables only once
std::call_once(applyOnce, [this]() { isInitializer = true; });
if (isInitializer) {
G4AutoLock l(&pInelasticXSMutex);
// Access to elements
for ( auto const & elm : *table ) {
G4int Z = std::max( 1, std::min( elm->GetZasInt(), MAXZINELP-1) );
for (G4int i=0; i<5; ++i) {
if ( nullptr == (data[i])->GetElementData(Z) ) { Initialise(Z, i); }
}
}
l.unlock();
}
// prepare isotope selection
std::size_t nIso = temp.size();
// Access to elements
for ( auto const & elm : *table ) {
std::size_t n = elm->GetNumberOfIsotopes();
if (n > nIso) { nIso = n; }
G4int Z = std::min( elm->GetZasInt(), MAXZINELP-1);
if ( nullptr == (data[index])->GetElementData(Z) ) {
Initialise(Z);
}
}
temp.resize(nIso, 0.0);
}
void G4ParticleInelasticXS::FindDirectoryPath()
void G4ParticleInelasticXS::Initialise(G4int Z)
{
// build the complete string identifying the file with the data set
if (gDataDirectory[0].empty()) {
for (G4int i=0; i<5; ++i) {
std::ostringstream ost;
ost << G4HadronicParameters::Instance()->GetDirPARTICLEXS() << "/"
<< pname[i] << "/inel";
gDataDirectory[i] = ost.str();
}
}
}
if ( nullptr != (data[index])->GetElementData(Z) ) { return; }
void G4ParticleInelasticXS::InitialiseOnFly(G4int Z)
{
G4AutoLock l(&pInelasticXSMutex);
for (G4int i=0; i<5; ++i) {
if ( nullptr == (data[i])->GetElementData(Z) ) { Initialise(Z, i); }
}
l.unlock();
}
if ( nullptr == (data[index])->GetElementData(Z) ) {
// upload element data
std::ostringstream ost;
ost << gDataDirectory << "/" << pname[index] << "/inel" << Z;
G4PhysicsVector* v = RetrieveVector(ost, true);
data[index]->InitialiseForElement(Z, v);
void G4ParticleInelasticXS::Initialise(G4int Z, G4int idx)
{
if (nullptr != data[idx]->GetElementData(Z)) { return; }
// upload isotope data
G4bool noComp = true;
if (amin[Z] < amax[Z]) {
// upload element data
std::ostringstream ost;
ost << gDataDirectory[idx] << Z ;
G4PhysicsVector* v = RetrieveVector(ost, true);
data[idx]->InitialiseForElement(Z, v);
// upload isotope data
G4bool noComp = true;
if (amin[Z] < amax[Z]) {
for (G4int A=amin[Z]; A<=amax[Z]; ++A) {
std::ostringstream ost1;
ost1 << gDataDirectory[idx] << Z << "_" << A;
G4PhysicsVector* v1 = RetrieveVector(ost1, false);
if (nullptr != v1) {
if (noComp) {
G4int nmax = amax[Z] - A + 1;
data[idx]->InitialiseForComponent(Z, nmax);
noComp = false;
for (G4int A=amin[Z]; A<=amax[Z]; ++A) {
std::ostringstream ost1;
ost1 << gDataDirectory << "/" << pname[index] << "/inel" << Z << "_" << A;
G4PhysicsVector* v1 = RetrieveVector(ost1, false);
if (nullptr != v1) {
if (noComp) {
G4int nmax = amax[Z] - A + 1;
data[index]->InitialiseForComponent(Z, nmax);
noComp = false;
}
data[index]->AddComponent(Z, A, v1);
}
data[idx]->AddComponent(Z, A, v1);
}
}
}
// no components case
if (noComp) { data[idx]->InitialiseForComponent(Z, 0); }
// no components case
if (noComp) { data[index]->InitialiseForComponent(Z, 0); }
// smooth transition
G4double sig1 = (*v)[v->GetVectorLength()-1];
G4double ehigh = v->GetMaxEnergy();
G4double sig2 = highEnergyXsection->GetInelasticElementCrossSection(
particle, ehigh, Z, aeff[Z]);
coeff[Z][idx] = (sig2 > 0.) ? sig1/sig2 : 1.0;
// smooth transition
G4double sig1 = (*v)[v->GetVectorLength()-1];
G4double ehigh = v->GetMaxEnergy();
G4double sig2 = highEnergyXsection->GetInelasticElementCrossSection(
particle, ehigh, Z, aeff[Z]);
coeff[Z][index] = (sig2 > 0.) ? sig1/sig2 : 1.0;
}
l.unlock();
}
G4PhysicsVector*
@@ -397,10 +375,11 @@ G4ParticleInelasticXS::RetrieveVector(std::ostringstream& ost, G4bool warn)
G4PhysicsLogVector* v = nullptr;
std::ifstream filein(ost.str().c_str());
if (!filein.is_open()) {
if(warn) {
if (warn) {
G4ExceptionDescription ed;
ed << "Data file <" << ost.str().c_str()
<< "> is not opened!";
<< "> is not opened! index=" << index
<< " dir: <" << gDataDirectory << ">. ";
G4Exception("G4ParticleInelasticXS::RetrieveVector(..)","had014",
FatalException, ed, "Check G4PARTICLEXSDATA");
}
@@ -1500,8 +1500,8 @@ G4PhotoNuclearCrossSection::G4PhotoNuclearCrossSection()
G4PhotoNuclearCrossSection::~G4PhotoNuclearCrossSection()
{
for (auto & ptr : GDR) { delete [] ptr; }
for (auto & ptr : HEN) { delete [] ptr; }
for (auto const & ptr : GDR) { delete [] ptr; }
for (auto const & ptr : HEN) { delete [] ptr; }
delete [] deuteron_GDR;
delete [] deuteron_HR;
@@ -1529,15 +1529,13 @@ G4PhotoNuclearCrossSection::IsIsoApplicable(const G4DynamicParticle*,
const G4Element*,
const G4Material*)
{
// explicitly allow deuterium and tritium
if ((Z == 1 && A == 2) || (Z == 1 && A == 3) ||
(Z == 2 && A == 3) ) return true;
return false;
// explicitly allow deuterium, tritium, and He3
return ((Z == 1 && A == 2) || (Z == 1 && A == 3) || (Z == 2 && A == 3));
}
G4bool
G4PhotoNuclearCrossSection::IsElementApplicable(const G4DynamicParticle* /*particle*/,
G4PhotoNuclearCrossSection::IsElementApplicable(const G4DynamicParticle*,
G4int /*Z*/, const G4Material*)
{
return true;
@@ -1550,11 +1548,15 @@ G4PhotoNuclearCrossSection::GetIsoCrossSection(const G4DynamicParticle* aPart,
G4int Z, G4int A,
const G4Isotope*,
const G4Element*,
const G4Material* mat)
const G4Material*)
{
G4double Energy = aPart->GetKineticEnergy()/MeV;
if (Energy < THmin) return 0.;
return ComputeIsoXSection(aPart->GetKineticEnergy(), Z, A);
}
G4double
G4PhotoNuclearCrossSection::ComputeIsoXSection(G4double Energy, G4int Z, G4int A)
{
if (Energy <= THmin) { return 0.0; }
G4double sigma;
G4double lE;
if (Z == 1 && A == 2) {
@@ -1622,7 +1624,7 @@ G4PhotoNuclearCrossSection::GetIsoCrossSection(const G4DynamicParticle* aPart,
}
} else {
return GetElementCrossSection(aPart, Z, mat);
return ComputeElementXSection(Energy, Z);
}
if(sigma < 0.) sigma = 0.;
@@ -1634,11 +1636,17 @@ G4PhotoNuclearCrossSection::GetIsoCrossSection(const G4DynamicParticle* aPart,
// (E in MeV, CS in mb)
G4double
G4PhotoNuclearCrossSection::GetElementCrossSection(const G4DynamicParticle* aPart,
G4int ZZ, const G4Material*)
G4int Z, const G4Material*)
{
const G4double Energy = aPart->GetKineticEnergy()/MeV;
if (Energy<THmin) return 0.;
return ComputeElementXSection(aPart->GetKineticEnergy(), Z);
}
G4double
G4PhotoNuclearCrossSection::ComputeElementXSection(G4double Energy, G4int Z)
{
if (Energy <= THmin) { return 0.0; }
G4int ZZ = std::min(Z, nL - 1);
G4double sigma=0.;
if(ZZ!=lastZ) // Otherwise the set of parameters is ready