Import Geant4 10.6.0 source tree

This commit is contained in:
Gabriele Cosmo
2019-12-06 15:12:28 +01:00
parent b2a62ae692
commit 5baee230e9
2997 changed files with 141580 additions and 98673 deletions
@@ -39,6 +39,7 @@
// (ANR-13-BS05-0002).
//
// Reference: Nucl. Instrum. Meth. A 899 (2018) 85 (arXiv:1802.08253 [hep-ph])
// Nucl. Instrum. Meth., A 936 (2019) 290
//
// Class Description:
//
@@ -104,6 +105,8 @@
#include "G4Electron.hh"
#include "G4Positron.hh"
#include "G4Gamma.hh"
#include "G4MuonPlus.hh"
#include "G4MuonMinus.hh"
#include "G4IonTable.hh"
#include "G4NucleiProperties.hh"
@@ -117,15 +120,31 @@
#include "G4ThreeVector.hh"
#include "G4RotationMatrix.hh"
#include <cassert>
// // Q : Use enum G4EmProcessSubType hire ?
// enum G45DConversionMode
// {
// kEPair, kMuPair
// };
const G4int kEPair = 0;
const G4int kMuPair = 1;
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4BetheHeitler5DModel::G4BetheHeitler5DModel(const G4ParticleDefinition* pd,
const G4String& nam)
: G4BetheHeitlerModel(pd, nam), fVerbose(1), fConversionType(0), iraw(false)
: G4PairProductionRelModel(pd, nam),fVerbose(1),fConversionType(0),
iraw(false),
fLepton1(G4Electron::Definition()),fLepton2(G4Positron::Definition()),
fConvMode(kEPair),
fTheMuPlus(G4MuonPlus::Definition()),fTheMuMinus(G4MuonMinus::Definition())
{
SetLowEnergyLimit(2*CLHEP::electron_mass_c2);
theIonTable = G4IonTable::GetIonTable();
//Q: Do we need this on Model
SetLowEnergyLimit(2*fTheElectron->GetPDGMass());
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
@@ -138,7 +157,7 @@ G4BetheHeitler5DModel::~G4BetheHeitler5DModel()
void G4BetheHeitler5DModel::Initialise(const G4ParticleDefinition* part,
const G4DataVector& vec)
{
G4BetheHeitlerModel::Initialise(part, vec);
G4PairProductionRelModel::Initialise(part, vec);
G4EmParameters* theManager = G4EmParameters::Instance();
// place to initialise model parameters
@@ -156,6 +175,90 @@ void G4BetheHeitler5DModel::Initialise(const G4ParticleDefinition* part,
iraw = theManager->OnIsolated();
// G4cout << "BH5DModel::Initialise verbose " << fVerbose
// << " isolated " << iraw << " ctype "<< fConversionType << G4endl;
//Q: Do we need this on Model
// The Leptons defined via SetLeptonPair(..) method
SetLowEnergyLimit(2*CLHEP::electron_mass_c2);
if (fConvMode == kEPair) {
assert(fLepton1->GetPDGEncoding() == fTheElectron->GetPDGEncoding()) ;
if (fVerbose > 3)
G4cout << "BH5DModel::Initialise conversion to e+ e-" << G4endl;
}
if (fConvMode == kMuPair) {
assert(fLepton1->GetPDGEncoding() == fTheMuMinus->GetPDGEncoding()) ;
if (fVerbose > 3)
G4cout << "BH5DModel::Initialise conversion to mu+ mu-" << G4endl;
}
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4BetheHeitler5DModel::SetLeptonPair(const G4ParticleDefinition* p1,
const G4ParticleDefinition* p2)
{
// Lepton1 - nagative charged particle
if ( p1->GetPDGEncoding() < 0 ){
if ( p1->GetPDGEncoding() ==
G4Positron::Definition()->GetPDGEncoding() ) {
SetConversionMode(kEPair);
fLepton1 = p2;
fLepton2 = p1;
// if (fVerbose)
G4cout << "G4BetheHeitler5DModel::SetLeptonPair conversion to e+ e-"
<< G4endl;
} else if ( p1->GetPDGEncoding() ==
G4MuonPlus::Definition()->GetPDGEncoding() ) {
SetConversionMode(kMuPair);
fLepton1 = p2;
fLepton2 = p1;
// if (fVerbose)
G4cout << "G4BetheHeitler5DModel::SetLeptonPair conversion to mu+ mu-"
<< G4endl;
} else {
// Exception
G4ExceptionDescription ed;
ed << "Model not applicable to particle(s) "
<< p1->GetParticleName() << ", "
<< p2->GetParticleName();
G4Exception("G4BetheHeitler5DModel::SetLeptonPair","em0002",
FatalException, ed);
}
} else {
if ( p1->GetPDGEncoding() ==
G4Electron::Definition()->GetPDGEncoding() ) {
SetConversionMode(kEPair);
fLepton1 = p1;
fLepton2 = p2;
// if (fVerbose)
G4cout << "G4BetheHeitler5DModel::SetLeptonPair conversion to e+ e-"
<< G4endl;
} else if ( p1->GetPDGEncoding() ==
G4MuonMinus::Definition()->GetPDGEncoding() ) {
SetConversionMode(kMuPair);
fLepton1 = p1;
fLepton2 = p2;
// if (fVerbose)
G4cout << "G4BetheHeitler5DModel::SetLeptonPair conversion to mu+ mu-"
<< G4endl;
} else {
// Exception
G4ExceptionDescription ed;
ed << "Model not applicable to particle(s) "
<< p1->GetParticleName() << ", "
<< p2->GetParticleName();
G4Exception("G4BetheHeitler5DModel::SetLeptonPair","em0002",
FatalException, ed);
}
}
if ( fLepton1->GetPDGEncoding() != fLepton2->GetAntiPDGEncoding() ) {
G4Exception("G4BetheHeitler5DModel::SetLeptonPair","em0007",
FatalErrorInArgument, "pair must be particle, antiparticle ");
G4cerr << "BH5DModel::SetLeptonPair BAD paricle/anti particle pair"
<< fLepton1->GetParticleName() << ", "
<< fLepton2->GetParticleName() << G4endl;
}
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
@@ -181,9 +284,12 @@ G4BetheHeitler5DModel::SampleSecondaries(std::vector<G4DynamicParticle*>* fvect,
{
// MeV
static const G4double ElectronMass = CLHEP::electron_mass_c2;
static const G4double ElectronMass2 = ElectronMass*ElectronMass;
const G4double LeptonMass = fLepton1->GetPDGMass();
const G4double LeptonMass2 = LeptonMass*LeptonMass;
static const G4double alpha0 = CLHEP::fine_structure_const;
// mm
// mm
static const G4double r0 = CLHEP::classic_electr_radius;
// mbarn
static const G4double r02 = r0*r0*1.e+25;
@@ -192,25 +298,45 @@ G4BetheHeitler5DModel::SampleSecondaries(std::vector<G4DynamicParticle*>* fvect,
// static const G4double factor1 = pow((6.0 * pi),(1.0/3.0))/(8.*alpha0*ElectronMass);
static const G4double factor1 = 2.66134007899/(8.*alpha0*ElectronMass);
//
static const G4double PairInvMassMin = 2.*ElectronMass;
G4double PairInvMassMin = 2.*LeptonMass;
G4double TrThreshold = 2.0 * ( (LeptonMass2)/ElectronMass + LeptonMass);
//
static const G4double nu[10] = { 0.0227436, 0.0582046, 3.0322675, 2.8275065,
-0.0034004, 1.1212766, 1.8989468, 68.3492750,
0.0211186, 14.4 };
static const G4double tr[10] = { 0.0332350, 4.3942537, 2.8515925, 2.6351695,
-0.0031510, 1.5737305, 1.8104647, 20.6434021,
-0.0272586, 28.9};
static const G4double nu[2][10] = {
//electron
{ 0.0227436, 0.0582046, 3.0322675, 2.8275065, -0.0034004,
1.1212766, 1.8989468, 68.3492750, 0.0211186, 14.4},
//muon
{0.67810E-06, 0.86037E+05, 2.0008395, 1.6739719, -0.0057279,
1.4222, 0.0, 263230.0, 0.0521, 51.1338}
};
static const G4double tr[2][10] = {
//electron
{ 0.0332350, 4.3942537, 2.8515925, 2.6351695, -0.0031510,
1.5737305, 1.8104647, 20.6434021, -0.0272586, 28.9},
//muon
{0.10382E-03, 0.14408E+17, 4.1368679, 3.2662121, -0.0163091,
0.0000, 0.0, 0.0, 0.0000, 1.0000}
};
//
static const G4double para[3][2] = { {11., -16.},{-1.17, -2.95},{-2., -0.5} };
static const G4double para[2][3][2] = {
//electron
{ {11., -16.},{-1.17, -2.95},{-2., -0.5} },
//muon
{ {17.5, 1.},{-1.17, -2.95},{2., 6.} }
};
//
static const G4double correctionIndex = 1.4;
//
const G4double GammaEnergy = aDynamicGamma->GetKineticEnergy();
// Protection, Will not be true tot cross section = 0
if ( GammaEnergy <= PairInvMassMin) { return; }
const G4double GammaEnergy2 = GammaEnergy*GammaEnergy;
// Will not be true tot cross section = 0
if ( GammaEnergy <= 2.0*ElectronMass) { return; }
//
const G4ParticleMomentum GammaDirection = aDynamicGamma->GetMomentumDirection();
//////////////////////////////////////////////////////////////
const G4ParticleMomentum GammaDirection =
aDynamicGamma->GetMomentumDirection();
G4ThreeVector GammaPolarization = aDynamicGamma->GetPolarization();
// The protection polarization perpendicular to the direction vector,
@@ -223,6 +349,7 @@ G4BetheHeitler5DModel::SampleSecondaries(std::vector<G4DynamicParticle*>* fvect,
// End of Protection
//
const G4double GammaPolarizationMag = GammaPolarization.mag();
//////////////////////////////////////////////////////////////
// target element
// select randomly one element constituting the material
@@ -234,6 +361,10 @@ G4BetheHeitler5DModel::SampleSecondaries(std::vector<G4DynamicParticle*>* fvect,
const G4double iZ13 = 1./anElement->GetIonisation()->GetZ3();
const G4double targetMass = G4NucleiProperties::GetNuclearMass(A, Z);
const G4double NuThreshold = 2.0 * ( (LeptonMass2)/targetMass + LeptonMass);
// No conversion possible below nuclear threshold
if ( GammaEnergy <= NuThreshold) { return; }
CLHEP::HepRandomEngine* rndmEngine = G4Random::getTheEngine();
// itriplet : true -- triplet, false -- nuclear.
@@ -242,8 +373,8 @@ G4BetheHeitler5DModel::SampleSecondaries(std::vector<G4DynamicParticle*>* fvect,
itriplet = false;
} else if (fConversionType == 2) {
itriplet = true;
if ( GammaEnergy <= 4.0*ElectronMass ) return;
} else if ( GammaEnergy > 4.0*ElectronMass ) {
if ( GammaEnergy <= TrThreshold ) return;
} else if ( GammaEnergy > TrThreshold ) {
// choose triplet or nuclear from a triplet/nuclear=1/Z
// total cross section ratio.
// approximate at low energies !
@@ -251,6 +382,7 @@ G4BetheHeitler5DModel::SampleSecondaries(std::vector<G4DynamicParticle*>* fvect,
itriplet = true;
}
}
//
const G4double RecoilMass = itriplet ? ElectronMass : targetMass;
const G4double RecoilMass2 = RecoilMass*RecoilMass;
@@ -269,27 +401,33 @@ G4BetheHeitler5DModel::SampleSecondaries(std::vector<G4DynamicParticle*>* fvect,
// maximum value of pdf
const G4double EffectiveZ = iraw ? 0.5 : Z;
const G4double Threshold = itriplet ? 4.*ElectronMass : 2.*ElectronMass;
const G4double Threshold = itriplet ? TrThreshold : NuThreshold;
const G4double AvailableEnergy = GammaEnergy - Threshold;
const G4double LogAvailableEnergy = G4Log(AvailableEnergy);
//
const G4double MaxDiffCross = itriplet
? MaxDiffCrossSection(tr, EffectiveZ, AvailableEnergy, LogAvailableEnergy)
: MaxDiffCrossSection(nu, EffectiveZ, AvailableEnergy, LogAvailableEnergy);
? MaxDiffCrossSection(tr[fConvMode],
EffectiveZ, AvailableEnergy, LogAvailableEnergy)
: MaxDiffCrossSection(nu[fConvMode],
EffectiveZ, AvailableEnergy, LogAvailableEnergy);
//
// 50% safety marging factor
const G4double ymax = 1.5 * MaxDiffCross;
// x1 bounds
const G4double xu1 = (LogAvailableEnergy > para[2][0])
? para[0][0] + para[1][0]*LogAvailableEnergy
: para[0][0] + para[2][0]*para[1][0];
const G4double xl1 = (LogAvailableEnergy > para[2][1])
? para[0][1] + para[1][1]*LogAvailableEnergy
: para[0][1] + para[2][1]*para[1][1];
const G4double xu1 = (LogAvailableEnergy > para[fConvMode][2][0])
? para[fConvMode][0][0] +
para[fConvMode][1][0]*LogAvailableEnergy
: para[fConvMode][0][0] +
para[fConvMode][2][0]*para[fConvMode][1][0];
const G4double xl1 = (LogAvailableEnergy > para[fConvMode][2][1])
? para[fConvMode][0][1] +
para[fConvMode][1][1]*LogAvailableEnergy
: para[fConvMode][0][1] +
para[fConvMode][2][1]*para[fConvMode][1][1];
//
G4LorentzVector Recoil;
G4LorentzVector Positron;
G4LorentzVector Electron;
G4LorentzVector LeptonPlus;
G4LorentzVector LeptonMinus;
G4double pdf = 0.;
G4double rndmv6[6];
@@ -356,30 +494,25 @@ G4BetheHeitler5DModel::SampleSecondaries(std::vector<G4DynamicParticle*>* fvect,
thePRecoil*cosTheta,
RecEnergyCMS);
// const G4LorentzVector Pair(-Recoil.x(),
// -Recoil.y(),
// -Recoil.z(),
// sqrts-RecEnergyCMS);
// in the pair frame
const G4double thePLepton = std::sqrt( (LeptonEnergy2-ElectronMass)
*(LeptonEnergy2+ElectronMass));
const G4double thePLepton = std::sqrt( (LeptonEnergy2-LeptonMass)
*(LeptonEnergy2+LeptonMass));
Positron.set(thePLepton*sinThetaLept*cosPhiLept,
LeptonPlus.set(thePLepton*sinThetaLept*cosPhiLept,
thePLepton*sinThetaLept*sinPhiLept,
thePLepton*cosThetaLept,
LeptonEnergy2);
Electron.set(-Positron.x(),
-Positron.y(),
-Positron.z(),
LeptonMinus.set(-LeptonPlus.x(),
-LeptonPlus.y(),
-LeptonPlus.z(),
LeptonEnergy2);
// Normalisation of final state phase space:
// Section 47 of Particle Data Group, Chin. Phys. C, 40, 100001 (2016)
// const G4double Norme = Recoil1.vect().mag() * Positron2.vect().mag();
const G4double Norme = Recoil.vect().mag() * Positron.vect().mag();
// const G4double Norme = Recoil1.vect().mag() * LeptonPlus2.vect().mag();
const G4double Norme = Recoil.vect().mag() * LeptonPlus.vect().mag();
// e+, e- to CMS frame from pair frame
@@ -388,50 +521,50 @@ G4BetheHeitler5DModel::SampleSecondaries(std::vector<G4DynamicParticle*>* fvect,
G4LorentzVector( -Recoil.x(), -Recoil.y(), -Recoil.z(),
sqrts-RecEnergyCMS).boostVector();
Positron.boost(pair2cms);
Electron.boost(pair2cms);
LeptonPlus.boost(pair2cms);
LeptonMinus.boost(pair2cms);
// back to the laboratory frame (make use of the CMS(0,0,Eg,Eg+RM)) form
Recoil.boostZ(betaCMS);
Positron.boostZ(betaCMS);
Electron.boostZ(betaCMS);
LeptonPlus.boostZ(betaCMS);
LeptonMinus.boostZ(betaCMS);
// Jacobian factors
const G4double Jacob0 = x0*dum0*dum0;
const G4double Jacob1 = 2.*X1*lnPairInvMassRange*PairInvMass;
const G4double Jacob2 = std::abs(sinThetaLept);
const G4double EPlus = Positron.t();
const G4double PPlus = Positron.vect().mag();
const G4double sinThetaPlus = Positron.vect().perp()/PPlus;
const G4double cosThetaPlus = Positron.vect().cosTheta();
const G4double EPlus = LeptonPlus.t();
const G4double PPlus = LeptonPlus.vect().mag();
const G4double sinThetaPlus = LeptonPlus.vect().perp()/PPlus;
const G4double cosThetaPlus = LeptonPlus.vect().cosTheta();
const G4double pPX = Positron.x();
const G4double pPY = Positron.y();
const G4double pPX = LeptonPlus.x();
const G4double pPY = LeptonPlus.y();
const G4double dum1 = 1./std::sqrt( pPX*pPX + pPY*pPY );
const G4double cosPhiPlus = pPX*dum1;
const G4double sinPhiPlus = pPY*dum1;
// denominators:
// the two cancelling leading terms for forward emission at high energy, removed
const G4double elMassCTP = ElectronMass*cosThetaPlus;
const G4double elMassCTP = LeptonMass*cosThetaPlus;
const G4double ePlusSTP = EPlus*sinThetaPlus;
const G4double DPlus = (elMassCTP*elMassCTP + ePlusSTP*ePlusSTP)
/(EPlus + PPlus*cosThetaPlus);
const G4double EMinus = Electron.t();
const G4double PMinus = Electron.vect().mag();
const G4double sinThetaMinus = Electron.vect().perp()/PMinus;
const G4double cosThetaMinus = Electron.vect().cosTheta();
const G4double EMinus = LeptonMinus.t();
const G4double PMinus = LeptonMinus.vect().mag();
const G4double sinThetaMinus = LeptonMinus.vect().perp()/PMinus;
const G4double cosThetaMinus = LeptonMinus.vect().cosTheta();
const G4double ePX = Electron.x();
const G4double ePY = Electron.y();
const G4double ePX = LeptonMinus.x();
const G4double ePY = LeptonMinus.y();
const G4double dum2 = 1./std::sqrt( ePX*ePX + ePY*ePY );
const G4double cosPhiMinus = ePX*dum2;
const G4double sinPhiMinus = ePY*dum2;
const G4double elMassCTM = ElectronMass*cosThetaMinus;
const G4double elMassCTM = LeptonMass*cosThetaMinus;
const G4double eMinSTM = EMinus*sinThetaMinus;
const G4double DMinus = (elMassCTM*elMassCTM + eMinSTM*eMinSTM)
/(EMinus + PMinus*cosThetaMinus);
@@ -440,7 +573,8 @@ G4BetheHeitler5DModel::SampleSecondaries(std::vector<G4DynamicParticle*>* fvect,
const G4double cosdPhi = cosPhiPlus*cosPhiMinus + sinPhiPlus*sinPhiMinus;
const G4double PRec = Recoil.vect().mag();
const G4double q2 = PRec*PRec;
const G4double BigPhi = -ElectronMass2 / (GammaEnergy*GammaEnergy2 * q2*q2);
const G4double BigPhi = -LeptonMass2 / (GammaEnergy*GammaEnergy2 * q2*q2);
G4double FormFactor = 1.;
if (!iraw) {
@@ -523,24 +657,22 @@ G4BetheHeitler5DModel::SampleSecondaries(std::vector<G4DynamicParticle*>* fvect,
G4RotationMatrix GtoW(GammaPolarization,yGrec,GammaDirection);
Recoil.transform(GtoW);
Positron.transform(GtoW);
Electron.transform(GtoW);
LeptonPlus.transform(GtoW);
LeptonMinus.transform(GtoW);
if ( fVerbose > 2 ) {
G4cout << "BetheHeitler5DModel Recoil " << Recoil.x() << " " << Recoil.y() << " " << Recoil.z()
<< " " << Recoil.t() << " " << G4endl;
G4cout << "BetheHeitler5DModel Positron " << Positron.x() << " " << Positron.y() << " "
<< Positron.z() << " " << Positron.t() << " " << G4endl;
G4cout << "BetheHeitler5DModel Electron " << Electron.x() << " " << Electron.y() << " "
<< Electron.z() << " " << Electron.t() << " " << G4endl;
G4cout << "BetheHeitler5DModel LeptonPlus " << LeptonPlus.x() << " " << LeptonPlus.y() << " "
<< LeptonPlus.z() << " " << LeptonPlus.t() << " " << G4endl;
G4cout << "BetheHeitler5DModel LeptonMinus " << LeptonMinus.x() << " " << LeptonMinus.y() << " "
<< LeptonMinus.z() << " " << LeptonMinus.t() << " " << G4endl;
}
// Create secondaries
G4DynamicParticle* aParticle1 = new G4DynamicParticle(fLepton1,LeptonMinus);
G4DynamicParticle* aParticle2 = new G4DynamicParticle(fLepton2,LeptonPlus);
// electron
G4DynamicParticle* aParticle1 = new G4DynamicParticle(fTheElectron,Electron);
// positron
G4DynamicParticle* aParticle2 = new G4DynamicParticle(fThePositron,Positron);
// create G4DynamicParticle object for the particle3 ( recoil )
G4ParticleDefinition* RecoilPart;
if (itriplet) {
@@ -105,7 +105,7 @@ G4double G4ESTARStopping::GetElectronicDEDX(G4int i, G4double energy)
void G4ESTARStopping::Initialise()
{
dirPath = getenv("G4LEDATA");
dirPath = std::getenv("G4LEDATA");
if(!dirPath) {
G4Exception("G4ESTARStopping()","em0006",FatalException,
"Environment variable G4LEDATA not defined");
@@ -253,7 +253,7 @@ void G4GSMottCorrection::InitMCDataPerMaterials() {
// it's called only if data has not been loaded for this element yet
void G4GSMottCorrection::LoadMCDataElement(const G4Element *elem) {
// allocate memory
G4int izet = G4lrint(elem->GetZ());
G4int izet = elem->GetZasInt();
if (izet>gMaxZet) {
izet = gMaxZet;
}
@@ -262,7 +262,7 @@ void G4GSMottCorrection::LoadMCDataElement(const G4Element *elem) {
fMCDataPerElement[izet] = perElem;
//
// load data from file
char* tmppath = getenv("G4LEDATA");
char* tmppath = std::getenv("G4LEDATA");
if (!tmppath) {
G4Exception("G4GSMottCorrection::LoadMCDataElement()","em0006",
FatalException,
@@ -175,12 +175,12 @@ void G4GSPWACorrections::InitDataPerMaterials() {
// it's called only if data has not been loaded for this element yet
void G4GSPWACorrections::LoadDataElement(const G4Element *elem) {
// allocate memory
G4int izet = G4lrint(elem->GetZ());
G4int izet = elem->GetZasInt();
if (izet>gMaxZet) {
izet = gMaxZet;
}
// load data from file
char* tmppath = getenv("G4LEDATA");
char* tmppath = std::getenv("G4LEDATA");
if (!tmppath) {
G4Exception("G4GSPWACorrection::LoadDataElement()","em0006",
FatalException,
@@ -35,7 +35,6 @@
#include "G4GammaConversion.hh"
#include "G4PhysicalConstants.hh"
#include "G4SystemOfUnits.hh"
#include "G4BetheHeitlerModel.hh"
#include "G4PairProductionRelModel.hh"
#include "G4Electron.hh"
#include "G4EmParameters.hh"
@@ -80,18 +79,10 @@ void G4GammaConversion::InitialiseProcess(const G4ParticleDefinition*)
SetMinKinEnergy(emin);
if(!EmModel(0)) { SetEmModel(new G4BetheHeitlerModel()); }
if(!EmModel(0)) { SetEmModel(new G4PairProductionRelModel()); }
EmModel(0)->SetLowEnergyLimit(emin);
G4double energyLimit = std::min(EmModel(0)->HighEnergyLimit(), 80*GeV);
EmModel(0)->SetHighEnergyLimit(energyLimit);
EmModel(0)->SetHighEnergyLimit(emax);
AddEmModel(1, EmModel(0));
if(emax > energyLimit) {
if(!EmModel(1)) { SetEmModel(new G4PairProductionRelModel()); }
EmModel(1)->SetLowEnergyLimit(energyLimit);
EmModel(1)->SetHighEnergyLimit(emax);
AddEmModel(1, EmModel(1));
}
}
}
@@ -165,7 +165,6 @@ G4GoudsmitSaundersonMscModel::G4GoudsmitSaundersonMscModel(const G4String& nam)
charge = 0;
currentMaterialIndex = -1;
//
lambdalimit = 1.*mm;
fr = 0.1;
rangeinit = 1.e+21;
geombig = 1.e+50*mm;
@@ -185,8 +184,6 @@ G4GoudsmitSaundersonMscModel::G4GoudsmitSaundersonMscModel(const G4String& nam)
mass = electron_mass_c2;
taulim = 1.e-6;
//
facsafety = 0.6;
currentCouple = nullptr;
fParticleChange = nullptr;
//
@@ -253,6 +250,7 @@ G4GoudsmitSaundersonMscModel::~G4GoudsmitSaundersonMscModel() {
void G4GoudsmitSaundersonMscModel::Initialise(const G4ParticleDefinition* p, const G4DataVector&) {
SetParticle(p);
InitialiseParameters(p);
// -create GoudsmitSaundersonTable and init its Mott-correction member if
// Mott-correction was required
if (IsMaster()) {
@@ -314,14 +312,13 @@ G4double G4GoudsmitSaundersonMscModel::CrossSectionPerVolume(const G4Material* m
G4double,
G4double) {
G4double xsecTr1 = 0.; // cross section per volume i.e. macroscopic 1st transport cross section
G4double efEnergy = kineticEnergy;
//
fLambda0 = 0.0; // elastic mean free path
fLambda1 = 0.0; // first transport mean free path
fScrA = 0.0; // screening parameter
fG1 = 0.0; // first transport coef.
// use Moliere's screening (with Mott-corretion if it was requested)
if (efEnergy<10.*CLHEP::eV) efEnergy = 10.*CLHEP::eV;
G4double efEnergy = std::max(kineticEnergy, 10.*CLHEP::eV);
// total mometum square
G4double pt2 = efEnergy*(efEnergy+2.0*electron_mass_c2);
// beta square
@@ -435,7 +435,7 @@ G4GoudsmitSaundersonTable::GSMSCAngularDtr* G4GoudsmitSaundersonTable::GetGSAngu
void G4GoudsmitSaundersonTable::LoadMSCData() {
char* path = getenv("G4LEDATA");
char* path = std::getenv("G4LEDATA");
if (!path) {
G4Exception("G4GoudsmitSaundersonTable::LoadMSCData()","em0006",
FatalException,
@@ -94,10 +94,11 @@ void G4ICRU49NuclearStoppingModel::InitialiseArray()
#ifdef G4MULTITHREADED
G4MUTEXLOCK(&G4ICRU49NuclearStoppingModel::ICRU49NuclearMutex);
#endif
if(0.0 == Z23[2]) {
for(G4int i=1; i<100; ++i) {
if(0.0 == Z23[1]) {
for(G4int i=2; i<100; ++i) {
Z23[i] = g4calc->powZ(i, 0.23);
}
Z23[1] = 1.0;
}
#ifdef G4MULTITHREADED
G4MUTEXUNLOCK(&G4ICRU49NuclearStoppingModel::ICRU49NuclearMutex);
@@ -117,6 +117,11 @@ G4PairProductionRelModel::G4PairProductionRelModel(const G4ParticleDefinition*,
fTheElectron(G4Electron::Electron()), fThePositron(G4Positron::Positron()),
fParticleChange(nullptr)
{
// gamma energy below which the parametrized atomic x-section is used (80 GeV)
fParametrizedXSectionThreshold = 80.0*CLHEP::GeV;
// gamma energy below the Coulomb correction is turned off (50 MeV)
fCoulombCorrectionThreshold = 50.0*CLHEP::MeV;
// set angular generator used in the final state kinematics computation
SetAngularDistribution(new G4ModifiedTsai());
}
@@ -174,7 +179,9 @@ G4double G4PairProductionRelModel::ComputeXSectionPerAtom(G4double gammaEnergy,
// the way in which the Coulomb correction is applied i.e. avoid negative DCS)
const G4int iz = std::min(gMaxZet, G4lrint(Z));
const G4double eps0 = CLHEP::electron_mass_c2/gammaEnergy;
const G4double dmax = gElementData[iz]->fDeltaMax;
// Coulomb correction is always included in the DCS even below 50 MeV (note:
// that this DCS is only used to get the integrated x-section)
const G4double dmax = gElementData[iz]->fDeltaMaxHigh;
const G4double dmin = 4.*eps0*gElementData[iz]->fDeltaFactor;
const G4double eps1 = 0.5 - 0.5*std::sqrt(1.-dmin/dmax);
const G4double epsMin = std::max(eps0, eps1);
@@ -306,18 +313,26 @@ G4PairProductionRelModel::ComputeCrossSectionPerAtom(const G4ParticleDefinition*
G4double crossSection = 0.0 ;
// check kinematical limit
if ( gammaEnergy <= 2.0*electron_mass_c2 ) { return crossSection; }
// Computes the cross section with or without LPM suppression depending on
// settings (by default with if the gamma energy is above a given threshold)
// and using or not using complete sreening approximation (by default not).
// Only the dependent part is computed in the numerical integration of the DCS
// i.e. the result must be multiplied here with 4 \alpha r_0^2 Z(Z+\eta(Z))
crossSection = ComputeXSectionPerAtom(gammaEnergy, Z);
// apply the constant factors:
// - eta(Z) is a correction to account interaction in the field of e-
// - gXSecFactor = 4 \alpha r_0^2
const G4int iz = std::min(gMaxZet, G4lrint(Z));
const G4double eta = gElementData[iz]->fEtaValue;
crossSection *= gXSecFactor*Z*(Z+eta);
// compute the atomic cross section either by using x-section parametrization
// or by numerically integrationg the DCS (with or without LPM)
if ( gammaEnergy < fParametrizedXSectionThreshold) {
// using the parametrized cross sections (max up to 80 GeV)
crossSection = ComputeParametrizedXSectionPerAtom(gammaEnergy, Z);
} else {
// by numerical integration of the DCS:
// Computes the cross section with or without LPM suppression depending on
// settings (by default with if the gamma energy is above a given threshold)
// and using or not using complete sreening approximation (by default not).
// Only the dependent part is computed in the numerical integration of the DCS
// i.e. the result must be multiplied here with 4 \alpha r_0^2 Z(Z+\eta(Z))
crossSection = ComputeXSectionPerAtom(gammaEnergy, Z);
// apply the constant factors:
// - eta(Z) is a correction to account interaction in the field of e-
// - gXSecFactor = 4 \alpha r_0^2
const G4int iz = std::min(gMaxZet, G4lrint(Z));
const G4double eta = gElementData[iz]->fEtaValue;
crossSection *= gXSecFactor*Z*(Z+eta);
}
// final protection
return std::max(crossSection, 0.);
}
@@ -363,76 +378,88 @@ G4PairProductionRelModel::SampleSecondaries(std::vector<G4DynamicParticle*>* fve
// 'eps' is the total energy transferred to one of the e-/e+ pair in initial
// gamma energy units Eg. Since the corresponding DCS is symmetric on eps=0.5,
// the kinematical limits for eps0=mc^2/Eg <= eps <= 0.5
//
// The Coulomb factor for the target element (Z) (Eg>50 MeV is assumed)
// F(Z) = 8*ln(Z)/3 + 8*fc(Z)
//
// The screening variable 'delta(eps)' = 136*Z^{-1/3}*eps0/[eps(1-eps)]
// Due to the Coulomb correction, the DCS can go below zero even at
// kinematicaly allowed eps > eps0 values. In order to exclude this eps
// range with negative DCS, the minimum eps value will be set to eps_min =
// max[eps0, epsp] with epsp is the solution of SF(delta(epsp)) - F(Z)/2 = 0
// with SF being the screening function (SF1=SF2 at high value of delta).
// The solution is epsp = 0.5 - 0.5*sqrt[ 1 - 4*136*Z^{-1/3}eps0/deltap]
// with deltap = Exp[(42.038-F(Z))/8.29]-0.958. So the limits are:
// - when eps=eps_max = 0.5 => delta_min = 136*Z^{-1/3}*eps0/4
// - epsp = 0.5 - 0.5*sqrt[ 1 - delta_min/deltap]
// - and eps_min = max[eps0, epsp]
const G4int iZet = std::min(gMaxZet, anElement->GetZasInt());
const G4double deltaFactor = gElementData[iZet]->fDeltaFactor*eps0;
const G4double deltaMin = 4.*deltaFactor;
const G4double deltaMax = gElementData[iZet]->fDeltaMax;
// compute the limits of eps
const G4double epsp = 0.5 - 0.5*std::sqrt(1. - deltaMin/deltaMax) ;
const G4double epsMin = std::max(eps0,epsp);
const G4double epsRange = 0.5 - epsMin;
const G4double FZ = 8.*(gElementData[iZet]->fLogZ13 +
gElementData[iZet]->fCoulomb);
//
// sample the energy rate (eps) of the created electron (or positron)
G4double F10, F20;
ScreenFunction12(deltaMin, F10, F20);
F10 -= FZ;
F20 -= FZ;
const G4double NormF1 = std::max(F10 * epsRange * epsRange, 0.);
const G4double NormF2 = std::max(1.5 * F20 , 0.);
const G4double NormCond = NormF1/(NormF1 + NormF2);
// check if LPM correction is active
const G4bool isLPM = (fIsUseLPMCorrection && gammaEnergy>gEgLPMActivation);
fLPMEnergy = mat->GetRadlen()*gLPMconstant;
// we will need 3 uniform random number for each trial of sampling
G4double rndmv[3];
G4double greject = 0.;
// 1. 'eps' is sampled uniformly on the [eps0, 0.5] inteval if Eg<Egsmall
// 2. otherwise, on the [eps_min, 0.5] interval according to the DCS (case 2.)
G4double eps;
do {
rndmEngine->flatArray(3, rndmv);
if (NormCond > rndmv[0]) {
eps = 0.5 - epsRange * fG4Calc->A13(rndmv[1]);
const G4double delta = deltaFactor/(eps*(1.-eps));
if (isLPM) {
G4double lpmXiS, lpmGS, lpmPhiS, phi1, phi2;
ComputePhi12(delta, phi1, phi2);
ComputeLPMfunctions(lpmXiS, lpmGS, lpmPhiS, eps, gammaEnergy, iZet);
greject = lpmXiS*((2.*lpmPhiS+lpmGS)*phi1-lpmGS*phi2-lpmPhiS*FZ)/F10;
} else {
greject = (ScreenFunction1(delta)-FZ)/F10;
}
} else {
eps = epsMin + epsRange*rndmv[1];
const G4double delta = deltaFactor/(eps*(1.-eps));
if (isLPM) {
G4double lpmXiS, lpmGS, lpmPhiS, phi1, phi2;
ComputePhi12(delta, phi1, phi2);
ComputeLPMfunctions(lpmXiS, lpmGS, lpmPhiS, eps, gammaEnergy, iZet);
greject = lpmXiS*( (lpmPhiS+0.5*lpmGS)*phi1 + 0.5*lpmGS*phi2
-0.5*(lpmGS+lpmPhiS)*FZ )/F20;
} else {
greject = (ScreenFunction2(delta)-FZ)/F20;
}
// case 1.
static const G4double Egsmall = 2.*CLHEP::MeV;
if (gammaEnergy < Egsmall) {
eps = eps0 + (0.5-eps0)*rndmEngine->flat();
} else {
// case 2.
// get the Coulomb factor for the target element (Z) and gamma energy (Eg)
// F(Z) = 8*ln(Z)/3 if Eg <= 50 [MeV] => no Coulomb correction
// F(Z) = 8*ln(Z)/3 + 8*fc(Z) if Eg > 50 [MeV] => fc(Z) is the Coulomb cor.
//
// The screening variable 'delta(eps)' = 136*Z^{-1/3}*eps0/[eps(1-eps)]
// Due to the Coulomb correction, the DCS can go below zero even at
// kinematicaly allowed eps > eps0 values. In order to exclude this eps
// range with negative DCS, the minimum eps value will be set to eps_min =
// max[eps0, epsp] with epsp is the solution of SF(delta(epsp)) - F(Z)/2 = 0
// with SF being the screening function (SF1=SF2 at high value of delta).
// The solution is epsp = 0.5 - 0.5*sqrt[ 1 - 4*136*Z^{-1/3}eps0/deltap]
// with deltap = Exp[(42.038-F(Z))/8.29]-0.958. So the limits are:
// - when eps=eps_max = 0.5 => delta_min = 136*Z^{-1/3}*eps0/4
// - epsp = 0.5 - 0.5*sqrt[ 1 - delta_min/deltap]
// - and eps_min = max[eps0, epsp]
const G4int iZet = std::min(gMaxZet, anElement->GetZasInt());
const G4double deltaFactor = gElementData[iZet]->fDeltaFactor*eps0;
const G4double deltaMin = 4.*deltaFactor;
G4double deltaMax = gElementData[iZet]->fDeltaMaxLow;
G4double FZ = 8.*gElementData[iZet]->fLogZ13;
if ( gammaEnergy > fCoulombCorrectionThreshold ) { // Eg > 50 MeV ?
FZ += 8.*gElementData[iZet]->fCoulomb;
deltaMax = gElementData[iZet]->fDeltaMaxHigh;
}
// Loop checking, 03-Aug-2015, Vladimir Ivanchenko
} while (greject < rndmv[2]);
// end of eps sampling
// compute the limits of eps
const G4double epsp = 0.5 - 0.5*std::sqrt(1. - deltaMin/deltaMax) ;
const G4double epsMin = std::max(eps0,epsp);
const G4double epsRange = 0.5 - epsMin;
//
// sample the energy rate (eps) of the created electron (or positron)
G4double F10, F20;
ScreenFunction12(deltaMin, F10, F20);
F10 -= FZ;
F20 -= FZ;
const G4double NormF1 = std::max(F10 * epsRange * epsRange, 0.);
const G4double NormF2 = std::max(1.5 * F20 , 0.);
const G4double NormCond = NormF1/(NormF1 + NormF2);
// check if LPM correction is active
const G4bool isLPM = (fIsUseLPMCorrection && gammaEnergy>gEgLPMActivation);
fLPMEnergy = mat->GetRadlen()*gLPMconstant;
// we will need 3 uniform random number for each trial of sampling
G4double rndmv[3];
G4double greject = 0.;
do {
rndmEngine->flatArray(3, rndmv);
if (NormCond > rndmv[0]) {
eps = 0.5 - epsRange * fG4Calc->A13(rndmv[1]);
const G4double delta = deltaFactor/(eps*(1.-eps));
if (isLPM) {
G4double lpmXiS, lpmGS, lpmPhiS, phi1, phi2;
ComputePhi12(delta, phi1, phi2);
ComputeLPMfunctions(lpmXiS, lpmGS, lpmPhiS, eps, gammaEnergy, iZet);
greject = lpmXiS*((2.*lpmPhiS+lpmGS)*phi1-lpmGS*phi2-lpmPhiS*FZ)/F10;
} else {
greject = (ScreenFunction1(delta)-FZ)/F10;
}
} else {
eps = epsMin + epsRange*rndmv[1];
const G4double delta = deltaFactor/(eps*(1.-eps));
if (isLPM) {
G4double lpmXiS, lpmGS, lpmPhiS, phi1, phi2;
ComputePhi12(delta, phi1, phi2);
ComputeLPMfunctions(lpmXiS, lpmGS, lpmPhiS, eps, gammaEnergy, iZet);
greject = lpmXiS*( (lpmPhiS+0.5*lpmGS)*phi1 + 0.5*lpmGS*phi2
-0.5*(lpmGS+lpmPhiS)*FZ )/F20;
} else {
greject = (ScreenFunction2(delta)-FZ)/F20;
}
}
// Loop checking, 03-Aug-2015, Vladimir Ivanchenko
} while (greject < rndmv[2]);
// end of eps sampling
}
//
// select charges randomly
G4double eTotEnergy, pTotEnergy;
@@ -452,8 +479,7 @@ G4PairProductionRelModel::SampleSecondaries(std::vector<G4DynamicParticle*>* fve
G4ThreeVector eDirection, pDirection;
//
GetAngularDistribution()->SamplePairDirections(aDynamicGamma,
eKinEnergy, pKinEnergy,
eDirection, pDirection);
eKinEnergy, pKinEnergy, eDirection, pDirection);
// create G4DynamicParticle object for the particle1
G4DynamicParticle* aParticle1= new G4DynamicParticle(
fTheElectron,eDirection,eKinEnergy);
@@ -486,7 +512,8 @@ void G4PairProductionRelModel::InitialiseElementData()
const G4double logZ13 = elem->GetIonisation()->GetlogZ3();
const G4double Z13 = elem->GetIonisation()->GetZ3();
const G4double fc = elem->GetfCoulomb();
const G4double FZ = 8.*(logZ13 + fc);
const G4double FZLow = 8.*logZ13;
const G4double FZHigh = 8.*(logZ13 + fc);
G4double Fel;
G4double Finel;
if (iz<5) { // use data from Dirac-Fock atomic model
@@ -501,7 +528,8 @@ void G4PairProductionRelModel::InitialiseElementData()
elD->fCoulomb = fc;
elD->fLradEl = Fel;
elD->fDeltaFactor = 136./Z13;
elD->fDeltaMax = G4Exp((42.038 - FZ)/8.29) - 0.958;
elD->fDeltaMaxLow = G4Exp((42.038 - FZLow)/8.29) - 0.958;
elD->fDeltaMaxHigh = G4Exp((42.038 - FZHigh)/8.29) - 0.958;
elD->fEtaValue = Finel/(Fel-fc);
elD->fLPMVarS1Cond = std::sqrt(2.)*Z13*Z13/(184.*184.);
elD->fLPMILVarS1Cond = 1./G4Log(elD->fLPMVarS1Cond);
@@ -611,3 +639,71 @@ void G4PairProductionRelModel::ComputeLPMfunctions(G4double &funcXiS,
}
}
// Calculates the microscopic cross section in GEANT4 internal units. Same as in
// G4BetheHeitlerModel and should be used below 80 GeV since it start to deverge
// from the cross section data above 80-90 GeV:
// Parametrized formula (L. Urban) is used to estimate the atomic cross sections
// given numerically in the table of [Hubbell, J. H., Heinz Albert Gimm, and I.
// Overbo: "Pair, Triplet, and Total Atomic Cross Sections (and Mass Attenuation
// Coefficients) for 1 MeV100 GeV Photons in Elements Z= 1 to 100." Journal of
// physical and chemical reference data 9.4 (1980): 1023-1148.]
//
// The formula gives a good approximation of the data from 1.5 MeV to 100 GeV.
// below 1.5 MeV: sigma=sigma(1.5MeV)*(GammaEnergy-2electronmass)
// *(GammaEnergy-2electronmass)
G4double
G4PairProductionRelModel::ComputeParametrizedXSectionPerAtom(G4double gammaE,
G4double Z)
{
G4double xSection = 0.0 ;
// short versions
static const G4double kMC2 = CLHEP::electron_mass_c2;
// zero cross section below the kinematical limit: Eg<2mc^2
if (Z < 0.9 || gammaE <= 2.0*kMC2) { return xSection; }
//
static const G4double gammaEnergyLimit = 1.5*CLHEP::MeV;
// set coefficients a, b c
static const G4double a0 = 8.7842e+2*CLHEP::microbarn;
static const G4double a1 = -1.9625e+3*CLHEP::microbarn;
static const G4double a2 = 1.2949e+3*CLHEP::microbarn;
static const G4double a3 = -2.0028e+2*CLHEP::microbarn;
static const G4double a4 = 1.2575e+1*CLHEP::microbarn;
static const G4double a5 = -2.8333e-1*CLHEP::microbarn;
static const G4double b0 = -1.0342e+1*CLHEP::microbarn;
static const G4double b1 = 1.7692e+1*CLHEP::microbarn;
static const G4double b2 = -8.2381 *CLHEP::microbarn;
static const G4double b3 = 1.3063 *CLHEP::microbarn;
static const G4double b4 = -9.0815e-2*CLHEP::microbarn;
static const G4double b5 = 2.3586e-3*CLHEP::microbarn;
static const G4double c0 = -4.5263e+2*CLHEP::microbarn;
static const G4double c1 = 1.1161e+3*CLHEP::microbarn;
static const G4double c2 = -8.6749e+2*CLHEP::microbarn;
static const G4double c3 = 2.1773e+2*CLHEP::microbarn;
static const G4double c4 = -2.0467e+1*CLHEP::microbarn;
static const G4double c5 = 6.5372e-1*CLHEP::microbarn;
// check low energy limit of the approximation (1.5 MeV)
G4double gammaEnergyOrg = gammaE;
if (gammaE < gammaEnergyLimit) { gammaE = gammaEnergyLimit; }
// compute gamma energy variables
const G4double x = G4Log(gammaE/kMC2);
const G4double x2 = x *x;
const G4double x3 = x2*x;
const G4double x4 = x3*x;
const G4double x5 = x4*x;
//
const G4double F1 = a0 + a1*x + a2*x2 + a3*x3 + a4*x4 + a5*x5;
const G4double F2 = b0 + b1*x + b2*x2 + b3*x3 + b4*x4 + b5*x5;
const G4double F3 = c0 + c1*x + c2*x2 + c3*x3 + c4*x4 + c5*x5;
// compute the approximated cross section
xSection = (Z + 1.)*(F1*Z + F2*Z*Z + F3);
// check if we are below the limit of the approximation and apply correction
if (gammaEnergyOrg < gammaEnergyLimit) {
const G4double dum = (gammaEnergyOrg-2.*kMC2)/(gammaEnergyLimit-2.*kMC2);
xSection *= dum*dum;
}
return xSection;
}
@@ -333,7 +333,7 @@ void G4SBBremTable::InitSamplingTables() {
// should be called only from LoadSamplingTables(G4int) and once
void G4SBBremTable::LoadSTGrid() {
char* path = getenv("G4LEDATA");
char* path = std::getenv("G4LEDATA");
if (!path) {
G4Exception("G4SBBremTable::LoadSTGrid()","em0006",
FatalException, "Environment variable G4LEDATA not defined");
@@ -391,7 +391,7 @@ void G4SBBremTable::LoadSamplingTables(G4int iz) {
}
// load data for a given Z only once
iz = std::max(std::min(fMaxZet, iz),1);
char* path = getenv("G4LEDATA");
char* path = std::getenv("G4LEDATA");
if (!path) {
G4Exception("G4SBBremTable::LoadSamplingTables()","em0006",
FatalException, "Environment variable G4LEDATA not defined");
File diff suppressed because one or more lines are too long
@@ -23,7 +23,6 @@
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
//
// -------------------------------------------------------------------
//
// GEANT4 Class file
@@ -40,11 +39,12 @@
// Modifications:
//
// 24.07.2018 Introduced possibility to use sampling tables to sample the
// emitted photon energy (instead of using rejectio) from the Seltzer-
// Berger scalled DCS for bremsstrahlung photon emission. Using these
// sampling tables option gives faster(30-70%) final state generation
// than the original rejection but takes some extra memory (+ ~6MB in
// the case of the full CMS detector). (M Novak)
// emitted photon energy (instead of using rejectio) from the
// Seltzer-Berger scalled DCS for bremsstrahlung photon emission.
// Using these sampling tables option gives faster(30-70%) final
// state generation than the original rejection but takes some
// extra memory (+ ~6MB in the case of the full CMS detector).
// (M Novak)
//
// -------------------------------------------------------------------
//
@@ -61,21 +61,32 @@
#include "G4ModifiedTsai.hh"
//#include "G4DipBustGenerator.hh"
#include "G4EmParameters.hh"
#include "G4ProductionCutsTable.hh"
#include "G4Physics2DVector.hh"
#include "G4Exp.hh"
#include "G4Log.hh"
#include "G4ios.hh"
#include <fstream>
#include <iomanip>
#include <sstream>
G4Physics2DVector* G4SeltzerBergerModel::gSBDCSData[] = { nullptr };
G4SBBremTable* G4SeltzerBergerModel::gSBSamplingTable = nullptr;
G4double G4SeltzerBergerModel::gYLimitData[] = { 0.0 };
G4String G4SeltzerBergerModel::gDataDirectory = "";
#ifdef G4MULTITHREADED
G4Mutex G4SeltzerBergerModel::theSBMutex = G4MUTEX_INITIALIZER;
#endif
static const G4double kMC2 = CLHEP::electron_mass_c2;
static const G4double kAlpha = CLHEP::twopi*CLHEP::fine_structure_const;
G4SeltzerBergerModel::G4SeltzerBergerModel(const G4ParticleDefinition* p,
const G4String& nam)
const G4String& nam)
: G4eBremsstrahlungRelModel(p,nam), fIsUseBicubicInterpolation(false),
fIsUseSamplingTables(true), fNumWarnings(0), fIndx(0), fIndy(0)
{
@@ -83,7 +94,6 @@ G4SeltzerBergerModel::G4SeltzerBergerModel(const G4ParticleDefinition* p,
SetLowEnergyLimit(fLowestKinEnergy);
SetLPMFlag(false);
SetAngularDistribution(new G4ModifiedTsai());
//SetAngularDistribution(new G4DipBustGenerator());
}
G4SeltzerBergerModel::~G4SeltzerBergerModel()
@@ -104,7 +114,7 @@ G4SeltzerBergerModel::~G4SeltzerBergerModel()
}
void G4SeltzerBergerModel::Initialise(const G4ParticleDefinition* p,
const G4DataVector& cuts)
const G4DataVector& cuts)
{
if (p) {
SetParticle(p);
@@ -112,17 +122,17 @@ void G4SeltzerBergerModel::Initialise(const G4ParticleDefinition* p,
fIsUseSamplingTables = G4EmParameters::Instance()->EnableSamplingTable();
// Access to elements
if (IsMaster()) {
// check environment variable
// build the complete string identifying the file with the data set
char* path = getenv("G4LEDATA");
const G4ElementTable* theElemTable = G4Element::GetElementTable();
size_t numOfElem = G4Element::GetNumberOfElements();
for (size_t ie = 0; ie < numOfElem; ++ie) {
G4int izet =
std::max(1,std::min(((*theElemTable)[ie])->GetZasInt(), gMaxZet-1));
// load SB-DCS data for this atomic number if it has not been loaded yet
if (!gSBDCSData[izet]) {
ReadData(izet, path);
auto theCoupleTable = G4ProductionCutsTable::GetProductionCutsTable();
size_t numOfCouples = theCoupleTable->GetTableSize();
for(size_t j=0; j<numOfCouples; ++j) {
auto mat = theCoupleTable->GetMaterialCutsCouple(j)->GetMaterial();
auto elmVec = mat->GetElementVector();
size_t numOfElem = mat->GetNumberOfElements();
for (size_t ie = 0; ie < numOfElem; ++ie) {
G4int Z = std::max(1,std::min(((*elmVec)[ie])->GetZasInt(), gMaxZet-1));
// load SB-DCS data for this atomic number if it has not been loaded yet
InitialiseForElement(nullptr, Z);
}
}
// elem.selectr. only for master: base class init-local will set for workers
@@ -146,26 +156,32 @@ void G4SeltzerBergerModel::Initialise(const G4ParticleDefinition* p,
}
}
G4String G4SeltzerBergerModel::DirectoryPath() const {
return "/brem_SB/br";
}
void G4SeltzerBergerModel::ReadData(G4int izet, const char* path) {
// return if it has been already loaded
if (gSBDCSData[izet]) {
return;
}
const char* datadir = path;
if (!datadir) {
datadir = getenv("G4LEDATA");
if (!datadir) {
G4Exception("G4SeltzerBergerModel::ReadData()","em0006",FatalException,
const G4String& G4SeltzerBergerModel::FindDirectoryPath()
{
// check environment variable
// build the complete string identifying the file with the data set
if(gDataDirectory.empty()) {
const char* path = std::getenv("G4LEDATA");
if (path) {
std::ostringstream ost;
ost << path << "/brem_SB/br";
gDataDirectory = ost.str();
} else {
G4Exception("G4SeltzerBergerModel::FindDirectoryPath()","em0006",
FatalException,
"Environment variable G4LEDATA not defined");
return;
}
}
return gDataDirectory;
}
void G4SeltzerBergerModel::ReadData(G4int Z) {
// return if it has been already loaded
if (gSBDCSData[Z]) {
return;
}
std::ostringstream ost;
ost << datadir << DirectoryPath() << izet;
ost << FindDirectoryPath() << Z;
std::ifstream fin(ost.str().c_str());
if (!fin.is_open()) {
G4ExceptionDescription ed;
@@ -180,9 +196,9 @@ void G4SeltzerBergerModel::ReadData(G4int izet, const char* path) {
G4Physics2DVector* v = new G4Physics2DVector();
if (v->Retrieve(fin)) {
v->SetBicubicInterpolation(fIsUseBicubicInterpolation);
gSBDCSData[izet] = v;
static const G4double emaxlog = 4*G4Log(10.);
gYLimitData[izet] = v->Value(0.97, emaxlog, fIndx, fIndy);
gYLimitData[Z] = v->Value(0.97, emaxlog, fIndx, fIndy);
gSBDCSData[Z] = v;
} else {
G4ExceptionDescription ed;
ed << "Bremsstrahlung data file <" << ost.str().c_str()
@@ -191,13 +207,10 @@ void G4SeltzerBergerModel::ReadData(G4int izet, const char* path) {
ed,"G4LEDATA version should be G4EMLOW6.23 or later.");
delete v;
}
// G4cout << dataSB[Z] << G4endl;
}
G4double G4SeltzerBergerModel::ComputeDXSectionPerAtom(G4double gammaEnergy)
{
static const G4double kMC2 = CLHEP::electron_mass_c2;
static const G4double kAlpha = CLHEP::twopi*CLHEP::fine_structure_const;
G4double dxsec = 0.0;
if (gammaEnergy < 0.0 || fPrimaryKinEnergy <= 0.0) {
return dxsec;
@@ -212,14 +225,6 @@ G4double G4SeltzerBergerModel::ComputeDXSectionPerAtom(G4double gammaEnergy)
if (!gSBDCSData[fCurrentIZ]) {
InitialiseForElement(nullptr, fCurrentIZ);
}
/*
G4ExceptionDescription ed;
ed << "Bremsstrahlung data for Z= " << Z
<< " are not initialized!";
G4Exception("G4SeltzerBergerModel::ComputeDXSectionPerAtom()","em0005",
FatalException, ed,
"G4LEDATA version should be G4EMLOW6.23 or later.");
*/
// NOTE: SetupForMaterial should have been called before!
const G4double pt2 = fPrimaryKinEnergy*(fPrimaryKinEnergy+2.*kMC2);
const G4double invb2 = fPrimaryTotalEnergy*fPrimaryTotalEnergy/pt2;
@@ -251,7 +256,6 @@ G4SeltzerBergerModel::SampleSecondaries(std::vector<G4DynamicParticle*>* vdp,
G4double cutEnergy,
G4double maxEnergy)
{
static const G4double kMC2 = CLHEP::electron_mass_c2;
const G4double kinEnergy = dp->GetKineticEnergy();
const G4double logKinEnergy = dp->GetLogKineticEnergy();
const G4double tmin = std::min(cutEnergy, kinEnergy);
@@ -292,7 +296,8 @@ G4SeltzerBergerModel::SampleSecondaries(std::vector<G4DynamicParticle*>* vdp,
vdp->push_back(gamma);
//
// compute post-interaction kinematics of the primary e-/e+
G4ThreeVector dir = (totMomentum*dp->GetMomentumDirection()-gammaEnergy*gamDir).unit();
G4ThreeVector dir =
(totMomentum*dp->GetMomentumDirection()-gammaEnergy*gamDir).unit();
const G4double finalE = kinEnergy - gammaEnergy;
/*
G4cout << "### G4SBModel: v= "
@@ -323,8 +328,6 @@ G4SeltzerBergerModel::SampleEnergyTransfer(const G4double kinEnergy,
const G4double tmin,
const G4double tmax)
{
static const G4double kMC2 = CLHEP::electron_mass_c2;
static const G4double kAlpha = CLHEP::twopi*CLHEP::fine_structure_const;
// min max of the transformed variable: x(k) = ln(k^2+k_p^2) that is in
// [ln(k_c^2+k_p^2), ln(E_k^2+k_p^2)]
const G4double xmin = G4Log(tmin*tmin+fDensityCorr);
@@ -333,24 +336,19 @@ G4SeltzerBergerModel::SampleEnergyTransfer(const G4double kinEnergy,
// majoranta
const G4double x0 = tmin/kinEnergy;
G4double vmax;
if (fCurrentIZ < 93) {
vmax = gSBDCSData[fCurrentIZ]->Value(x0, y, fIndx, fIndy)*1.02;
} else {
// reset cashed x and y indices
fIndx = 0;
fIndy = 0;
vmax = gSBDCSData[fCurrentIZ]->Value(x0, y, fIndx, fIndy)*1.2;
if (!gSBDCSData[fCurrentIZ]) {
InitialiseForElement(nullptr, fCurrentIZ);
}
vmax = gSBDCSData[fCurrentIZ]->Value(x0, y, fIndx, fIndy)*1.02;
//
static const G4double kEPeakLim = 300.*CLHEP::MeV;
static const G4double kELowLim = 20.*CLHEP::keV;
// majoranta corrected for e-
if (fIsElectron && x0 < 0.97 && ((kinEnergy>kEPeakLim) || (kinEnergy<kELowLim))) {
const G4double ylim = std::min(gYLimitData[fCurrentIZ],
if (fIsElectron && x0 < 0.97 &&
((kinEnergy>kEPeakLim) || (kinEnergy<kELowLim))) {
G4double ylim = std::min(gYLimitData[fCurrentIZ],
1.1*gSBDCSData[fCurrentIZ]->Value(0.97,y,fIndx,fIndy));
if (ylim > vmax) {
vmax = ylim;
}
vmax = std::max(vmax, ylim);
}
if (x0 < 0.05) {
vmax *= 1.2;
@@ -363,7 +361,8 @@ G4SeltzerBergerModel::SampleEnergyTransfer(const G4double kinEnergy,
G4double gammaEnergy, v;
for (G4int nn = 0; nn < kNCountMax; ++nn) {
rndmEngine->flatArray(2, rndm);
gammaEnergy = std::sqrt(std::max(G4Exp(xmin + rndm[0]*xrange)-fDensityCorr,0.));
gammaEnergy =
std::sqrt(std::max(G4Exp(xmin + rndm[0]*xrange)-fDensityCorr,0.));
v = gSBDCSData[fCurrentIZ]->Value(gammaEnergy/kinEnergy, y, fIndx, fIndy);
// e+ correction
if (!fIsElectron) {
@@ -401,21 +400,25 @@ G4SeltzerBergerModel::SampleEnergyTransfer(const G4double kinEnergy,
return gammaEnergy;
}
#include "G4AutoLock.hh"
namespace { G4Mutex SeltzerBergerModel1Mutex = G4MUTEX_INITIALIZER; }
void G4SeltzerBergerModel::InitialiseForElement(const G4ParticleDefinition*,
G4int izet)
G4int Z)
{
G4AutoLock l(&SeltzerBergerModel1Mutex);
// G4cout << "G4SeltzerBergerModel::InitialiseForElement Z= " << Z << G4endl;
if (!gSBDCSData[izet]) {
ReadData(izet);
}
if (!gSBDCSData[Z]) {
#ifdef G4MULTITHREADED
G4MUTEXLOCK(&theSBMutex);
if (!gSBDCSData[Z]) {
#endif
ReadData(Z);
#ifdef G4MULTITHREADED
}
G4MUTEXUNLOCK(&theSBMutex);
#endif
}
}
void G4SeltzerBergerModel::SetupForMaterial(const G4ParticleDefinition*,
const G4Material* mat,
G4double kineticEnergy)
const G4Material* mat,
G4double kineticEnergy)
{
fDensityFactor = gMigdalConstant*mat->GetElectronDensity();
// calculate threshold for density effect: gamma*k_p = sqrt(fDensityCorr)
File diff suppressed because it is too large Load Diff
@@ -123,16 +123,15 @@ void G4WentzelOKandVIxSection::Initialise(const G4ParticleDefinition* p,
// cosThetaMax is below 1.0 only when MSC is combined with SS
if(isCombined) { cosThetaMax = cosThetaLim; }
G4double a = G4EmParameters::Instance()->FactorForAngleLimit()
*CLHEP::hbarc/CLHEP::fermi;
G4EmParameters* param = G4EmParameters::Instance();
G4double a = param->FactorForAngleLimit()*CLHEP::hbarc/CLHEP::fermi;
factorA2 = 0.5*a*a;
currentMaterial = nullptr;
fNucFormfactor = G4EmParameters::Instance()->NuclearFormfactorType();
fNucFormfactor = param->NuclearFormfactorType();
if(0.0 == ScreenRSquare[0]) { InitialiseA(); }
// Mott corrections
// Mott corrections always added
if((p == theElectron || p == thePositron) && !fMottXSection) {
fMottXSection = new G4ScreeningMottCrossSection();
fMottXSection->Initialise(p, 1.0);
@@ -158,7 +157,7 @@ void G4WentzelOKandVIxSection::InitialiseA()
G4double constn = 6.937e-6/(MeV*MeV);
G4double fct = G4EmParameters::Instance()->ScreeningFactor();
G4double afact = fct*0.5*alpha2*a0*a0;
G4double afact = 0.5*fct*alpha2*a0*a0;
ScreenRSquare[0] = afact;
ScreenRSquare[1] = afact;
ScreenRSquareElec[1] = afact;
@@ -388,14 +387,14 @@ G4WentzelOKandVIxSection::SampleSingleScattering(G4double cosTMin,
}
G4double grej;
if(fMottXSection) {
fMottXSection->SetupKinematic(tkin, (G4double)targetZ);
fMottXSection->SetupKinematic(tkin, targetZ);
grej = fMottXSection->RatioMottRutherfordCosT(std::sqrt(z1))*fm*fm;
} else {
grej = (1. - z1*factB + factB1*targetZ*sqrt(z1*factB)*(2. - z1))
*fm*fm/(1.0 + z1*factD);
}
//G4cout << "SampleSingleScattering: E= " << tkin << " z1= "
// << z1 << " grej= " << grej << G4endl;
// G4cout << "SampleSingleScattering: E= " << tkin << " z1= "
// << z1 << " grej= "<< grej << " mottFact= "<< fMottFactor<< G4endl;
if(fMottFactor*rndmEngineMod->flat() <= grej ) {
// exclude "false" scattering due to formfactor and spin effect
G4double cost = 1.0 - z1;
@@ -124,6 +124,7 @@ void G4WentzelVIModel::Initialise(const G4ParticleDefinition* p,
{
// reset parameters
SetupParticle(p);
InitialiseParameters(p);
currentRange = 0.0;
if(isCombined) {
@@ -59,8 +59,6 @@
#include "G4ProductionCutsTable.hh"
#include "G4NucleiProperties.hh"
#include "G4Pow.hh"
#include "G4LossTableManager.hh"
#include "G4LossTableBuilder.hh"
#include "G4NistManager.hh"
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
@@ -94,13 +94,15 @@ G4eSingleCoulombScatteringModel::G4eSingleCoulombScatteringModel(const G4String&
currentMaterialIndex = -1;
Mottcross = new G4ScreeningMottCrossSection();
//G4cout <<"## G4eSingleCoulombScatteringModel: " << this << " " << Mottcross << G4endl;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4eSingleCoulombScatteringModel::~G4eSingleCoulombScatteringModel()
{
delete Mottcross;
//G4cout <<"## G4eSingleCoulombScatteringModel: delete " << this << " " << Mottcross << G4endl;
delete Mottcross;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
@@ -168,7 +168,7 @@ G4VParticleChange* G4eplusAnnihilation::AtRestDoIt(const G4Track& track,
G4Track* t = new G4Track(dp, time, track.GetPosition());
t->SetTouchableHandle(track.GetTouchableHandle());
if (biasManager) {
t->SetWeight(biasManager->GetWeight(i));
t->SetWeight(weight * biasManager->GetWeight(i));
} else {
t->SetWeight(weight);
}
@@ -23,7 +23,6 @@
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
//
// -------------------------------------------------------------------
//
// GEANT4 Class file
@@ -58,8 +57,6 @@
#include "G4ProductionCutsTable.hh"
#include "G4NucleiProperties.hh"
#include "G4Pow.hh"
#include "G4LossTableManager.hh"
#include "G4LossTableBuilder.hh"
#include "G4NistManager.hh"
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....