Import Geant4 11.2.0 source tree

This commit is contained in:
Gabriele Cosmo
2023-12-08 10:43:34 +01:00
parent dd1f179cda
commit 860a2b92bf
3962 changed files with 139318 additions and 164259 deletions
@@ -6,6 +6,50 @@ It must **not** be used as a substitute for writing good git commit messages!
-------------------------------------------------------------------------------
## 2023-11-03 Ben Morgan (emstand-V11-01-24)
- Use "G4" prefixed version of EXPAT/ZLIB CMake variables
## 2023-10-19 V.Ivanchenko (emstand-V11-01-23)
- G4UrbanMscModel - (L. Urban) tuned step limit parameterisation for
the case of enabled optional algorithm of lateral displacement.
The default tracking is not affected.
## 2023-10-07 V.Ivanchenko (emstand-V11-01-22)
- G4ASTARStopping, G4PSTARStopping, G4IonICRU73Data - use logarithmic search
of bin for free vectors
## 2023-10-05 V.Ivanchenko (emstand-V11-01-21)
- G4UrbanMscModel - (L. Urban) optional method SampleDisplacementNew(..) is
rewritten. This method is not used so far in any EM physics configurations
by default but may be enabled via UI command and/or C++ interface
## 2023-10-02 V.Ivanchenko (emstand-V11-01-20)
- G4eBremsstrahlungRelModel - fixed potential division by zero if advanced
compiler options are used, use G4Pow
## 2023-08-21 V.Ivanchenko (emstand-V11-01-19)
- G4SeltzerBergerModel - implement inheritance from G4VEmModel instead of
G4eBremsstrahlungRelModel, which means re-implementing common methods
by cut and paster from G4eBremsstrahlungRelModel and removal LPM
computations; use std::applyOnce approach to initilize static data;
upplied code format.
- G4eBremsstrahlungRelModel - use std::applyOncy approach to initilize
static data. This MR is a continuation of implementing a general
solution for initialisation of static data proposed by Stephan
Hageboeck
## 2023-06-18 V.Ivanchenko (emstand-V11-01-18)
- G4BetheHeitlerModel, G4PairProductionRelModel, G4eBremsstrahlungRelModel,
G4SeltzerBergerModel - further reorganized initialisation for #2543 and
considered neccesity to fix, Initilise(..) method described by Stephan
Hageboeck, to have thread safe check if a model is the first
instance of the class, set lock and perform initilisation of all static
data. Results of standard EM tests are unchanged.
## 2023-06-17 V.Ivanchenko (emstand-V11-01-17)
- G4UrbanMscModel - reduced number of re-computations of safety,
results of EM tests unchanged
## 2023-06-13 V.Ivanchenko (emstand-V11-01-16)
- G4LindHardSorensenIonModel - do not try to use ICRU73 data for projectile Z>80
@@ -51,7 +51,6 @@
// 1. S.M. Seltzer and M.J. Berger Nucl. Instr. Meth. B12 (1985) 95
// 2. S.M. Seltzer and M.J. Berger Atomic data and Nuclear Data
// Tables 35 (1986) 345
// Cross section computation in the base class G4eBremsstrahlungRelModel
// -------------------------------------------------------------------
//
@@ -59,13 +58,15 @@
#ifndef G4SeltzerBergerModel_h
#define G4SeltzerBergerModel_h 1
#include "G4VEmModel.hh"
#include "G4eBremsstrahlungRelModel.hh"
#include "globals.hh"
class G4Physics2DVector;
class G4SBBremTable;
class G4ParticleChangeForLoss;
class G4SeltzerBergerModel : public G4eBremsstrahlungRelModel
class G4SeltzerBergerModel : public G4VEmModel
{
public:
@@ -77,6 +78,21 @@ public:
void Initialise(const G4ParticleDefinition*, const G4DataVector&) override;
void InitialiseLocal(const G4ParticleDefinition*,
G4VEmModel* masterModel) override;
G4double ComputeDEDXPerVolume(const G4Material*,
const G4ParticleDefinition*,
G4double ekin,
G4double cutEnergy) override;
G4double ComputeCrossSectionPerAtom(const G4ParticleDefinition*,
G4double ekin,
G4double zet,
G4double,
G4double cutEnergy,
G4double maxEnergy = DBL_MAX) override;
void SampleSecondaries(std::vector<G4DynamicParticle*>*,
const G4MaterialCutsCouple*,
const G4DynamicParticle*,
@@ -86,6 +102,10 @@ public:
void SetupForMaterial(const G4ParticleDefinition*,
const G4Material*, G4double) override;
G4double MinPrimaryEnergy(const G4Material*,
const G4ParticleDefinition*,
G4double cutEnergy) override;
inline void SetBicubicInterpolationFlag(G4bool val)
{ fIsUseBicubicInterpolation = val; };
@@ -93,33 +113,58 @@ public:
G4SeltzerBergerModel & operator=(const G4SeltzerBergerModel &right) = delete;
G4SeltzerBergerModel(const G4SeltzerBergerModel&) = delete;
protected:
G4double ComputeDXSectionPerAtom(G4double gammaEnergy) override;
private:
void SetParticle(const G4ParticleDefinition* p);
void ReadData(G4int Z);
G4double ComputeBremLoss(G4double cutEnergy);
G4double ComputeXSectionPerAtom(G4double cutEnergy);
G4double ComputeDXSectionPerAtom(G4double gammaEnergy);
G4double SampleEnergyTransfer(const G4double kineticEnergy,
const G4double logKineticEnergy,
const G4double cut,
const G4double emax);
static constexpr G4int gMaxZet = 101;
static constexpr G4double gExpNumLimit = -12.;
static G4double gYLimitData[gMaxZet];
protected:
G4ParticleChangeForLoss* fParticleChange{nullptr};
private:
static constexpr G4int gMaxZet{101};
static constexpr G4double gExpNumLimit{-12.};
static G4double gYLimitData[gMaxZet];
static G4Physics2DVector* gSBDCSData[gMaxZet];
static G4SBBremTable* gSBSamplingTable;
static G4SBBremTable* gSBSamplingTable;
static const G4double gBremFactor;
static const G4double gMigdalConstant;
G4bool fIsUseBicubicInterpolation;
G4bool fIsUseSamplingTables;
G4bool fIsUseBicubicInterpolation{false};
G4bool fIsUseSamplingTables{true};
G4bool fIsElectron{true};
G4bool fIsScatOffElectron{false};
G4bool isInitializer{false};
//
G4int fCurrentIZ{0};
G4int fNumWarnings{0};
G4int fNumWarnings;
const G4ParticleDefinition* fPrimaryParticle{nullptr};
G4ParticleDefinition* fGammaParticle;
size_t fIndx;
size_t fIndy;
G4bool isFirstInstance{false};
// cash
G4double fPrimaryKinEnergy{0.};
G4double fPrimaryTotalEnergy{0.};
G4double fDensityFactor{0.};
G4double fDensityCorr{0.};
G4double fLowestKinEnergy;
std::size_t fIndx{0};
std::size_t fIndy{0};
};
#endif
@@ -179,7 +179,7 @@ private:
G4double rndmarray[2];
struct mscData {
G4double Z23, sqrtZ;
G4double Z23, sqrtZ, factmin;
G4double coeffth1, coeffth2;
G4double coeffc1, coeffc2, coeffc3, coeffc4;
G4double stepmina, stepminb;
@@ -233,8 +233,8 @@ inline G4double G4UrbanMscModel::SimpleScattering()
{
// 'large angle scattering'
// 2 model functions with correct xmean and x2mean
G4double a = (2.*xmeanth+9.*x2meanth-3.)/(2.*xmeanth-3.*x2meanth+1.);
G4double prob = (a+2.)*xmeanth/a;
const G4double a = (2.*xmeanth+9.*x2meanth-3.)/(2.*xmeanth-3.*x2meanth+1.);
const G4double prob = (a+2.)*xmeanth/a;
// sampling
rndmEngineMod->flatArray(2, rndmarray);
@@ -248,8 +248,9 @@ inline G4double G4UrbanMscModel::ComputeStepmin()
{
// define stepmin using estimation of the ratio
// of lambda_elastic/lambda_transport
G4double rat = currentKinEnergy*invmev;
return lambda0*1.e-3/(2.e-3+rat*(msc[idx]->stepmina+msc[idx]->stepminb*rat));
const G4double rat = currentKinEnergy*invmev;
return lambda0*msc[idx]->factmin/
(0.002 + rat*(msc[idx]->stepmina + msc[idx]->stepminb*rat));
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
@@ -143,7 +143,7 @@ private:
private:
G4bool fIsUseCompleteScreening = false;
G4bool fIsFirstInstance = false;
G4bool fIsInitializer = false;
G4bool fUseLPM = true;
protected:
@@ -179,4 +179,4 @@ geant4_module_link_libraries(G4emstandard
G4ions
G4mesons
G4procman
${ZLIB_LIBRARIES})
${G4ZLIB_LIBRARIES})
@@ -48,6 +48,7 @@
#include "G4ASTARStopping.hh"
#include "G4NISTStoppingData.hh"
#include "G4EmParameters.hh"
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
@@ -356,6 +357,7 @@ void G4ASTARStopping::AddData(const G4float* stop, const G4Material* mat)
v->PutValues(i, T0[i], stop[i]*fac);
}
v->FillSecondDerivatives();
v->EnableLogBinSearch(G4EmParameters::Instance()->NumberForFreeVector());
materials.push_back(mat);
sdata.push_back(v);
++nvectors;
@@ -86,18 +86,15 @@ void G4BetheHeitlerModel::Initialise(const G4ParticleDefinition* p,
{
if (!fParticleChange) { fParticleChange = GetParticleChangeForGamma(); }
if (gElementData.empty()) {
if (isFirstInstance || gElementData.empty()) {
G4AutoLock l(&theBetheHMutex);
if (gElementData.empty()) {
isFirstInstance = true;
gElementData.resize(gMaxZet+1, nullptr);
}
l.unlock();
}
// static data should be initialised only in the one instance
if(isFirstInstance) {
// static data should be initialised only in the one instance
InitialiseElementData();
l.unlock();
}
// element selectors should be initialised in the master thread
if(IsMaster()) {
@@ -407,6 +407,7 @@ G4IonICRU73Data::RetrieveVector(std::ostringstream& ost, G4bool warn)
FatalException, ed, "Check G4LEDATA");
} else {
if(fSpline) { fVector->FillSecondDerivatives(); }
fVector->EnableLogBinSearch(G4EmParameters::Instance()->NumberForFreeVector());
v = new G4PhysicsLogVector(fEmin, fEmax, fNbins, fSpline);
for(G4int i=0; i<=fNbins; ++i) {
G4double e = v->Energy(i);
@@ -48,6 +48,7 @@
#include "G4PSTARStopping.hh"
#include "G4NISTStoppingData.hh"
#include "G4EmParameters.hh"
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
@@ -357,6 +358,7 @@ void G4PSTARStopping::AddData(const G4float* stop, const G4Material* mat)
v->PutValues(i, T0[i], ((G4double)stop[i])*fac);
}
v->FillSecondDerivatives();
v->EnableLogBinSearch(G4EmParameters::Instance()->NumberForFreeVector());
materials.push_back(mat);
sdata.push_back(v);
++nvectors;
@@ -124,7 +124,7 @@ 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)
// gamma energy below which the parametrized atomic x-section is used (30 GeV)
fParametrizedXSectionThreshold = 30.0*CLHEP::GeV;
// gamma energy below the Coulomb correction is turned off (50 MeV)
fCoulombCorrectionThreshold = 50.0*CLHEP::MeV;
@@ -153,21 +153,19 @@ void G4PairProductionRelModel::Initialise(const G4ParticleDefinition* p,
{
if(nullptr == fParticleChange) { fParticleChange = GetParticleChangeForGamma(); }
if (gElementData.empty()) {
if (isFirstInstance || gElementData.empty()) {
// init element data and LPM funcs
G4AutoLock l(&thePairProdRelMutex);
if (gElementData.empty()) {
isFirstInstance = true;
gElementData.resize(gMaxZet+1, nullptr);
}
l.unlock();
}
// static data should be initialised only in the one instance
if(isFirstInstance) {
// static data should be initialised only in the one instance
InitialiseElementData();
if (fIsUseLPMCorrection) {
InitLPMFunctions();
}
l.unlock();
}
// element selectors should be initialised in the master thread
if (IsMaster()) {
@@ -62,6 +62,8 @@
#include "G4EmParameters.hh"
#include "G4ProductionCutsTable.hh"
#include "G4Gamma.hh"
#include "G4Electron.hh"
#include "G4Physics2DVector.hh"
#include "G4Exp.hh"
@@ -73,33 +75,56 @@
#include <fstream>
#include <iomanip>
#include <sstream>
#include <thread>
G4Physics2DVector* G4SeltzerBergerModel::gSBDCSData[] = { nullptr };
G4SBBremTable* G4SeltzerBergerModel::gSBSamplingTable = nullptr;
G4double G4SeltzerBergerModel::gYLimitData[] = { 0.0 };
G4double G4SeltzerBergerModel::gYLimitData[] = { 0.0 };
G4Physics2DVector* G4SeltzerBergerModel::gSBDCSData[] = { nullptr };
G4SBBremTable* G4SeltzerBergerModel::gSBSamplingTable = nullptr;
// constant DCS factor: 16\alpha r_0^2/3
const G4double G4SeltzerBergerModel::gBremFactor
= 16. * CLHEP::fine_structure_const * CLHEP::classic_electr_radius
* CLHEP::classic_electr_radius/3.;
// Migdal's constant: 4\pi r_0*electron_reduced_compton_wavelength^2
const G4double G4SeltzerBergerModel::gMigdalConstant
= 4. * CLHEP::pi * CLHEP::classic_electr_radius
* CLHEP::electron_Compton_length * CLHEP::electron_Compton_length;
static constexpr G4double twoMass = 2* CLHEP::electron_mass_c2;
static constexpr G4double kAlpha = CLHEP::twopi*CLHEP::fine_structure_const;
static std::once_flag applyOnce;
namespace
{
G4Mutex theSBMutex = G4MUTEX_INITIALIZER;
}
static const G4double kMC2 = CLHEP::electron_mass_c2;
static const G4double kAlpha = CLHEP::twopi*CLHEP::fine_structure_const;
// for numerical integration on [0,1]
const G4double gXGL[8] = {
1.98550718e-02, 1.01666761e-01, 2.37233795e-01, 4.08282679e-01,
5.91717321e-01, 7.62766205e-01, 8.98333239e-01, 9.80144928e-01
};
const G4double gWGL[8] = {
5.06142681e-02, 1.11190517e-01, 1.56853323e-01, 1.81341892e-01,
1.81341892e-01, 1.56853323e-01, 1.11190517e-01, 5.06142681e-02
};
}
G4SeltzerBergerModel::G4SeltzerBergerModel(const G4ParticleDefinition* p,
const G4String& nam)
: G4eBremsstrahlungRelModel(p,nam), fIsUseBicubicInterpolation(false),
fIsUseSamplingTables(true), fNumWarnings(0), fIndx(0), fIndy(0)
: G4VEmModel(nam),
fGammaParticle(G4Gamma::Gamma()),
fLowestKinEnergy(1.0*CLHEP::keV)
{
fLowestKinEnergy = 1.0*keV;
SetLowEnergyLimit(fLowestKinEnergy);
SetAngularDistribution(new G4ModifiedTsai());
if (fPrimaryParticle != p) { SetParticle(p); }
}
G4SeltzerBergerModel::~G4SeltzerBergerModel()
{
// delete SB-DCS data per Z
if (isFirstInstance) {
if (isInitializer) {
for (std::size_t iz = 0; iz < gMaxZet; ++iz) {
if (gSBDCSData[iz]) {
delete gSBDCSData[iz];
@@ -116,23 +141,20 @@ G4SeltzerBergerModel::~G4SeltzerBergerModel()
void G4SeltzerBergerModel::Initialise(const G4ParticleDefinition* p,
const G4DataVector& cuts)
{
// parameters in each thread
if (fPrimaryParticle != p) {
SetParticle(p);
}
fIsUseSamplingTables = G4EmParameters::Instance()->EnableSamplingTable();
fCurrentIZ = 0;
// initialise static tables for the Seltzer-Berger model
if (0.0 == gYLimitData[0]) {
std::call_once(applyOnce, [this]() { isInitializer = true; });
if (isInitializer) {
G4AutoLock l(&theSBMutex);
if (0.0 == gYLimitData[0]) {
isFirstInstance = true;
gYLimitData[0] = 1.0;
}
l.unlock();
}
// initialise base class
G4eBremsstrahlungRelModel::Initialise(p, cuts);
// initialisation per element is done only once
if (isFirstInstance) {
// initialisation per element is done only once
auto elemTable = G4Element::GetElementTable();
for (auto const & elm : *elemTable) {
G4int Z = std::max(1,std::min(elm->GetZasInt(), gMaxZet-1));
@@ -148,7 +170,33 @@ void G4SeltzerBergerModel::Initialise(const G4ParticleDefinition* p,
gSBSamplingTable->Initialize(std::max(fLowestKinEnergy, LowEnergyLimit()),
HighEnergyLimit());
}
l.unlock();
}
// element selectors are initialized in the master thread
if (IsMaster()) {
InitialiseElementSelectors(p, cuts);
}
// initialisation in all threads
if (nullptr == fParticleChange) {
fParticleChange = GetParticleChangeForLoss();
}
auto trmodel = GetTripletModel();
if (nullptr != trmodel) {
trmodel->Initialise(p, cuts);
fIsScatOffElectron = true;
}
}
void G4SeltzerBergerModel::InitialiseLocal(const G4ParticleDefinition*,
G4VEmModel* masterModel)
{
SetElementSelectors(masterModel->GetElementSelectors());
}
void G4SeltzerBergerModel::SetParticle(const G4ParticleDefinition* p)
{
fPrimaryParticle = p;
fIsElectron = (p == G4Electron::Electron());
}
void G4SeltzerBergerModel::ReadData(G4int Z) {
@@ -174,7 +222,7 @@ void G4SeltzerBergerModel::ReadData(G4int Z) {
v->SetBicubicInterpolation(fIsUseBicubicInterpolation);
static const G4double emaxlog = 4*G4Log(10.);
gYLimitData[Z] = v->Value(0.97, emaxlog, fIndx, fIndy);
gSBDCSData[Z] = v;
gSBDCSData[Z] = v;
} else {
G4ExceptionDescription ed;
ed << "Bremsstrahlung data file <" << ost.str().c_str()
@@ -186,6 +234,191 @@ void G4SeltzerBergerModel::ReadData(G4int Z) {
}
}
// minimum primary (e-/e+) energy at which discrete interaction is possible
G4double G4SeltzerBergerModel::MinPrimaryEnergy(const G4Material*,
const G4ParticleDefinition*,
G4double cut)
{
return std::max(fLowestKinEnergy, cut);
}
// Sets kinematical variables like E_kin, E_t and some material dependent
// for characteristic photon energy k_p (more exactly
// k_p^2) for the Ter-Mikaelian suppression effect.
void G4SeltzerBergerModel::SetupForMaterial(const G4ParticleDefinition*,
const G4Material* mat,
G4double kinEnergy)
{
fDensityFactor = gMigdalConstant*mat->GetElectronDensity();
// calculate threshold for density effect: k_p = sqrt(fDensityCorr)
fPrimaryKinEnergy = kinEnergy;
fPrimaryTotalEnergy = kinEnergy + CLHEP::electron_mass_c2;
fDensityCorr = fDensityFactor*fPrimaryTotalEnergy*fPrimaryTotalEnergy;
}
// Computes the restricted dE/dx as the appropriate weight of the individual
// element contributions that are computed by numerically integrating the DCS.
G4double
G4SeltzerBergerModel::ComputeDEDXPerVolume(const G4Material* material,
const G4ParticleDefinition* p,
G4double kineticEnergy,
G4double cutEnergy)
{
G4double dedx = 0.0;
if (nullptr == fPrimaryParticle) {
SetParticle(p);
}
if (kineticEnergy <= fLowestKinEnergy) {
return dedx;
}
// maximum value of the dE/dx integral (the minimum is 0 of course)
G4double tmax = std::min(cutEnergy, kineticEnergy);
if (tmax == 0.0) {
return dedx;
}
// sets kinematical and material related variables
SetupForMaterial(fPrimaryParticle, material, kineticEnergy);
// get element compositions of the material
const G4ElementVector* theElemVector = material->GetElementVector();
const G4double* theAtomNumDensVector = material->GetAtomicNumDensityVector();
const std::size_t numberOfElements = theElemVector->size();
// loop over the elements of the material and compute their contributions to
// the restricted dE/dx by numerical integration of the dependent part of DCS
for (std::size_t ie = 0; ie < numberOfElements; ++ie) {
G4VEmModel::SetCurrentElement((*theElemVector)[ie]);
G4int Z = (*theElemVector)[ie]->GetZasInt();
fCurrentIZ = std::min(Z, gMaxZet);
dedx += (Z*Z)*theAtomNumDensVector[ie]*ComputeBremLoss(tmax);
}
// apply the constant factor C/Z = 16\alpha r_0^2/3
dedx *= gBremFactor;
return std::max(dedx, 0.);
}
// Computes the integral part of the restricted dE/dx contribution from a given
// element (Z) by numerically integrating the k dependent DCS between
// k_min=0 and k_max = tmax = min[gamma-cut, electron-kinetic-energy].
// The numerical integration is done by dividing the integration range into 'n'
// subintervals and an 8 pint GL integral (on [0,1]) is performed on each sub-
// inteval by tranforming k to alpha=k/E_t (E_t is the total energy of the e-)
// and each sub-interavl is transformed to [0,1]. So the integrastion is done
// in xi(alpha) = xi(k) = [k/E_t-alpha_i]/delta where alpha_i=(i-1)*delta for
// the i = 1,2,..,n-th sub-interval so xi(k) in [0,1] on each sub-intevals.
// This transformation from 'k' to 'xi(k)' results in a multiplicative factor
// of E_t*delta at each step.
// The restricted dE/dx = N int_{0}^{k_max} k*ds/dk dk. In this case not
// the ds/dk(Z,k) but ds/dk(Z,k)*[F*k/C] is computed since:
// (i) what we need here is ds/dk*k and not k so this multiplication is done
// (ii) the Ter-Mikaelian suppression i.e. F related factor is done here
// (iii) the constant factor C (includes Z^2 as well)is accounted in the caller
G4double G4SeltzerBergerModel::ComputeBremLoss(G4double tmax)
{
// number of intervals and integration step
const G4double alphaMax = tmax/fPrimaryTotalEnergy;
const G4int nSub = (G4int)(20*alphaMax)+3;
const G4double delta = alphaMax/((G4double)nSub);
// set minimum value of the first sub-inteval
G4double alpha_i = 0.0;
G4double dedxInteg = 0.0;
for (G4int l = 0; l < nSub; ++l) {
for (G4int igl = 0; igl < 8; ++igl) {
// compute the emitted photon energy k
const G4double k = (alpha_i+gXGL[igl]*delta)*fPrimaryTotalEnergy;
// compute the DCS value at k (without the constant, the 1/k, 1/F factors)
const G4double dcs = ComputeDXSectionPerAtom(k);
// account Ter-Mikaelian suppression: times 1/F with F = 1+(k_p/k)^2
dedxInteg += gWGL[igl]*dcs/(1.0+fDensityCorr/(k*k));
}
// update sub-interval minimum value
alpha_i += delta;
}
// apply corrections due to variable transformation i.e. E_t*delta
dedxInteg *= delta*fPrimaryTotalEnergy;
return std::max(dedxInteg,0.);
}
// Computes restrected atomic cross section by numerically integrating the
// DCS between the proper kinematical limits accounting the gamma production cut
G4double
G4SeltzerBergerModel::ComputeCrossSectionPerAtom(const G4ParticleDefinition* p,
G4double kineticEnergy,
G4double Z,
G4double,
G4double cut,
G4double maxEnergy)
{
G4double crossSection = 0.0;
if (nullptr == fPrimaryParticle) {
SetParticle(p);
}
if (kineticEnergy <= fLowestKinEnergy) {
return crossSection;
}
// min/max kinetic energy limits of the DCS integration:
const G4double tmin = std::min(cut, kineticEnergy);
const G4double tmax = std::min(maxEnergy, kineticEnergy);
// zero restricted x-section if e- kinetic energy is below gamma cut
if (tmin >= tmax) {
return crossSection;
}
fCurrentIZ = std::min(G4lrint(Z), gMaxZet);
// integrate numerically (dependent part of) the DCS between the kin. limits:
// a. integrate between tmin and kineticEnergy of the e-
crossSection = ComputeXSectionPerAtom(tmin);
// allow partial integration: only if maxEnergy < kineticEnergy
// b. integrate between tmax and kineticEnergy (tmax=maxEnergy in this case)
// (so the result in this case is the integral of DCS between tmin and
// maxEnergy)
if (tmax < kineticEnergy) {
crossSection -= ComputeXSectionPerAtom(tmax);
}
// multiply with the constant factors: 16\alpha r_0^2/3 Z^2
crossSection *= Z*Z*gBremFactor;
return std::max(crossSection, 0.);
}
// Numerical integral of the (k dependent part of) DCS between k_min=tmin and
// k_max = E_k (where E_k is the kinetic energy of the e- and tmin is the
// minimum of energy of the emitted photon). The integration is done in the
// transformed alpha(k) = ln(k/E_t) variable (with E_t being the total energy of
// the primary e-). The integration range is divided into n sub-intervals with
// delta = [ln(k_min/E_t)-ln(k_max/E_t)]/n width each. An 8 point GL integral
// on [0,1] is applied on each sub-inteval so alpha is transformed to
// xi(alpha) = xi(k) = [ln(k/E_t)-alpha_i]/delta where alpha_i = ln(k_min/E_t) +
// (i-1)*delta for the i = 1,2,..,n-th sub-interval and xi(k) in [0,1] on each
// sub-intevals. From the transformed xi, k(xi) = E_t exp[xi*delta+alpha_i].
// Since the integration is done in variable xi instead of k this
// transformation results in a multiplicative factor of k*delta at each step.
// However, DCS differential in k is ~1/k so the multiplicative factor is simple
// becomes delta and the 1/k factor is dropped from the DCS computation.
// Ter-Mikaelian suppression is always accounted
G4double G4SeltzerBergerModel::ComputeXSectionPerAtom(G4double tmin)
{
G4double xSection = 0.0;
const G4double alphaMin = G4Log(tmin/fPrimaryTotalEnergy);
const G4double alphaMax = G4Log(fPrimaryKinEnergy/fPrimaryTotalEnergy);
const G4int nSub = (G4int)(0.45*(alphaMax-alphaMin))+4;
const G4double delta = (alphaMax-alphaMin)/((G4double)nSub);
// set minimum value of the first sub-inteval
G4double alpha_i = alphaMin;
for (G4int l = 0; l < nSub; ++l) {
for (G4int igl = 0; igl < 8; ++igl) {
// compute the emitted photon energy k
const G4double k = G4Exp(alpha_i+gXGL[igl]*delta)*fPrimaryTotalEnergy;
// compute the DCS value at k (without the constant, the 1/k, 1/F factors)
const G4double dcs = ComputeDXSectionPerAtom(k);
// account Ter-Mikaelian suppression: times 1/F with F = 1+(k_p/k)^2
xSection += gWGL[igl]*dcs/(1.0+fDensityCorr/(k*k));
}
// update sub-interval minimum value
alpha_i += delta;
}
// apply corrections due to variable transformation
xSection *= delta;
// final check
return std::max(xSection, 0.);
}
G4double G4SeltzerBergerModel::ComputeDXSectionPerAtom(G4double gammaEnergy)
{
G4double dxsec = 0.0;
@@ -205,17 +438,18 @@ G4double G4SeltzerBergerModel::ComputeDXSectionPerAtom(G4double gammaEnergy)
l.unlock();
}
// NOTE: SetupForMaterial should have been called before!
const G4double pt2 = fPrimaryKinEnergy*(fPrimaryKinEnergy+2.*kMC2);
const G4double pt2 = fPrimaryKinEnergy*(fPrimaryKinEnergy + twoMass);
const G4double invb2 = fPrimaryTotalEnergy*fPrimaryTotalEnergy/pt2;
G4double val = gSBDCSData[fCurrentIZ]->Value(x,y,fIndx,fIndy);
dxsec = val*invb2*CLHEP::millibarn/gBremFactor;
// e+ correction
if (!fIsElectron) {
const G4double invbeta1 = std::sqrt(invb2);
const G4double e2 = fPrimaryKinEnergy-gammaEnergy;
const G4double e2 = fPrimaryKinEnergy - gammaEnergy;
if (e2 > 0.0) {
const G4double invbeta2 = (e2+kMC2)/std::sqrt(e2*(e2+2.0*kMC2));
const G4double dum0 = kAlpha*fCurrentIZ*(invbeta1-invbeta2);
const G4double invbeta2 =
(e2 + CLHEP::electron_mass_c2)/std::sqrt(e2*(e2 + twoMass));
const G4double dum0 = kAlpha*fCurrentIZ*(invbeta1-invbeta2);
if (dum0 < gExpNumLimit) {
dxsec = 0.0;
} else {
@@ -235,7 +469,7 @@ G4SeltzerBergerModel::SampleSecondaries(std::vector<G4DynamicParticle*>* vdp,
G4double cutEnergy,
G4double maxEnergy)
{
const G4double kinEnergy = dp->GetKineticEnergy();
const G4double kinEnergy = dp->GetKineticEnergy();
const G4double logKinEnergy = dp->GetLogKineticEnergy();
const G4double tmin = std::min(cutEnergy, kinEnergy);
const G4double tmax = std::min(maxEnergy, kinEnergy);
@@ -246,9 +480,9 @@ G4SeltzerBergerModel::SampleSecondaries(std::vector<G4DynamicParticle*>* vdp,
SetupForMaterial(fPrimaryParticle, couple->GetMaterial(), kinEnergy);
const G4Element* elm = SelectTargetAtom(couple, fPrimaryParticle, kinEnergy,
logKinEnergy, tmin, tmax);
fCurrentIZ = std::max(std::min(elm->GetZasInt(),gMaxZet-1), 1);
fCurrentIZ = std::max(std::min(elm->GetZasInt(), gMaxZet-1), 1);
//
const G4double totMomentum = std::sqrt(kinEnergy*(fPrimaryTotalEnergy+kMC2));
const G4double totMomentum = std::sqrt(kinEnergy*(kinEnergy + twoMass));
/*
G4cout << "G4SeltzerBergerModel::SampleSecondaries E(MeV)= "
<< kinEnergy/MeV
@@ -268,14 +502,14 @@ G4SeltzerBergerModel::SampleSecondaries(std::vector<G4DynamicParticle*>* vdp,
// angles of the emitted gamma. ( Z - axis along the parent particle) use
// general interface
G4ThreeVector gamDir = GetAngularDistribution()->SampleDirection(dp,
fPrimaryTotalEnergy-gammaEnergy, fCurrentIZ, couple->GetMaterial());
fPrimaryTotalEnergy-gammaEnergy, fCurrentIZ, couple->GetMaterial());
// create G4DynamicParticle object for the emitted Gamma
auto gamma = new G4DynamicParticle(fGammaParticle, gamDir, gammaEnergy);
vdp->push_back(gamma);
//
// compute post-interaction kinematics of the primary e-/e+
G4ThreeVector dir =
(totMomentum*dp->GetMomentumDirection()-gammaEnergy*gamDir).unit();
(totMomentum*dp->GetMomentumDirection() - gammaEnergy*gamDir).unit();
const G4double finalE = kinEnergy - gammaEnergy;
/*
G4cout << "### G4SBModel: v= "
@@ -291,7 +525,7 @@ G4SeltzerBergerModel::SampleSecondaries(std::vector<G4DynamicParticle*>* vdp,
fParticleChange->ProposeTrackStatus(fStopAndKill);
fParticleChange->SetProposedKineticEnergy(0.0);
auto el = new G4DynamicParticle(
const_cast<G4ParticleDefinition*>(fPrimaryParticle), dir, finalE);
const_cast<G4ParticleDefinition*>(fPrimaryParticle), dir, finalE);
vdp->push_back(el);
} else { // continue tracking the primary e-/e+ otherwise
fParticleChange->SetProposedMomentumDirection(dir);
@@ -344,10 +578,12 @@ G4SeltzerBergerModel::SampleEnergyTransfer(const G4double kinEnergy,
v = gSBDCSData[fCurrentIZ]->Value(gammaEnergy/kinEnergy, y, fIndx, fIndy);
// e+ correction
if (!fIsElectron) {
const G4double e1 = kinEnergy - tmin;
const G4double invbeta1 = (e1+kMC2)/std::sqrt(e1*(e1+2.*kMC2));
const G4double e1 = kinEnergy - tmin;
const G4double invbeta1 =
(e1 + CLHEP::electron_mass_c2)/std::sqrt(e1*(e1 + twoMass));
const G4double e2 = kinEnergy-gammaEnergy;
const G4double invbeta2 = (e2+kMC2)/std::sqrt(e2*(e2+2.*kMC2));
const G4double invbeta2 =
(e2 + CLHEP::electron_mass_c2)/std::sqrt(e2*(e2 + twoMass));
const G4double dum0 = kAlpha*fCurrentIZ*(invbeta1-invbeta2);
if (dum0 < gExpNumLimit) {
v = 0.0;
@@ -377,17 +613,3 @@ G4SeltzerBergerModel::SampleEnergyTransfer(const G4double kinEnergy,
}
return gammaEnergy;
}
void G4SeltzerBergerModel::SetupForMaterial(const G4ParticleDefinition*,
const G4Material* mat,
G4double kineticEnergy)
{
fDensityFactor = gMigdalConstant*mat->GetElectronDensity();
// calculate threshold for density effect: gamma*k_p = sqrt(fDensityCorr)
fPrimaryKinEnergy = kineticEnergy;
fPrimaryTotalEnergy = kineticEnergy+CLHEP::electron_mass_c2;
fDensityCorr = fDensityFactor*fPrimaryTotalEnergy*fPrimaryTotalEnergy;
// flag for the base class
fIsLPMActive = false;
}
@@ -454,6 +454,12 @@ G4double G4UrbanMscModel::ComputeTruePathLengthLimit(
<< " range= " <<currentRange<< " lambda= "<<lambda0
<<G4endl;
*/
// extreme small step
if(tPathLength < tlimitminfix) {
latDisplasment = false;
return ConvertTrueToGeom(tPathLength, currentMinimalStep);
}
presafety = (stepStatus == fGeomBoundary) ? sp->GetSafety()
: ComputeSafety(sp->GetPosition(), tPathLength);
@@ -1046,123 +1052,42 @@ void G4UrbanMscModel::SampleDisplacement(G4double, G4double phi)
void G4UrbanMscModel::SampleDisplacementNew(G4double, G4double phi)
{
// best sampling based on single scattering results
G4double rmax =
// simple and fast sampling
// based on single scattering results
// u = (r/rmax)**2 : distribution from ss simulations
const G4double eps = 1.e-3;
const G4double rmax =
std::sqrt((tPathLength-zPathLength)*(tPathLength+zPathLength));
G4double r(0.0);
G4double u(0.0);
static const G4double reps = 5.e-3;
if(rmax > 0.)
{
static const G4double umax = 0.855;
static const G4double wlow = 0.750;
const G4double x0 = 0.73 ;
const G4double alpha = G4Log(7.33)/x0 ;
const G4double a1 = 1.-x0 ;
const G4double a2 = 1.-G4Exp(-alpha*x0) ;
const G4double a3 = G4Exp(alpha*x0)-1. ;
const G4double w1 = 2.*a2/(alpha*a1+2.*a2) ;
static const G4double ralpha = 6.83e+0;
static const G4double ra1 =-4.16179e+1;
static const G4double ra2 = 1.12548e+2;
static const G4double ra3 =-8.66665e+1;
static const G4double ralpha1 = 0.751*ralpha;
static const G4double ralpha2 =ralpha-ralpha1;
static const G4double rwa1 = G4Exp(ralpha1*reps);
static const G4double rwa2 = G4Exp(ralpha1*umax)-rwa1;
static const G4double rejamax = 1.16456;
static const G4double rbeta = 2.18e+1;
static const G4double rb0 = 4.81382e+2;
static const G4double rb1 =-1.12842e+4;
static const G4double rb2 = 4.57745e+4;
static const G4double rbeta1 = 0.732*rbeta;
static const G4double rbeta2 = rbeta-rbeta1;
static const G4double rwb1 = G4Exp(-rbeta1*umax);
static const G4double rwb2 = rwb1-G4Exp(-rbeta1*(1.-reps));
static const G4double rejbmax = 1.62651;
G4int count = 0;
G4double uc,rej;
if(rndmEngineMod->flat() < wlow)
G4double r, sqx;
if (rmax/currentRange < eps)
{
do {
rndmEngineMod->flatArray(2, rndmarray);
u = G4Log(rwa1+rwa2*rndmarray[0])/ralpha1;
uc = umax-u;
rej = G4Exp(-ralpha2*uc)*
(1.+ralpha*uc+ra1*uc*uc+ra2*uc*uc*uc+ra3*uc*uc*uc*uc);
} while (rejamax*rndmarray[1] > rej && ++count < 1000);
r = 0.73*rmax ;
sqx = 1.;
}
else
{
do {
rndmEngineMod->flatArray(2, rndmarray);
u = -G4Log(rwb1-rwb2*rndmarray[0])/rbeta1;
uc = u-umax;
rej = G4Exp(-rbeta2*uc)*
(1.+rbeta*uc+rb0*uc*uc+rb1*uc*uc*uc+rb2*uc*uc*uc*uc);
} while (rejbmax*rndmarray[1] > rej && ++count < 1000);
rndmEngineMod->flatArray(2,rndmarray);
const G4double x = (rndmarray[0] < w1) ? G4Log(1. + a3*rndmarray[1])/alpha :
1. - a1*std::sqrt(1.-rndmarray[1]);
sqx = std::sqrt(x);
r = sqx*rmax;
}
r = rmax*u;
}
if(r > 0.)
{
// sample Phi using lateral correlation
// and r/rmax - (Phi-phi) correlation
// v = Phi-phi = acos(latcorr/(r*sth))
// from SS simulation f(v)*g(v)
// f(v) ~ exp(-a1*v) normalized distribution
// g(v) rejection function (0 < g(v) <= 1)
G4double v, rej;
static const G4double peps = 1.e-4;
static const G4double palpha[10] = {2.300e+0,2.490e+0,2.610e+0,2.820e+0,2.710e+0,
2.750e+0,2.910e+0,3.400e+0,4.150e+0,5.400e+0};
static const G4double palpha1[10]= {4.600e-2,1.245e-1,2.610e-1,2.820e-1,2.710e-1,
6.875e-1,1.019e+0,1.360e+0,1.660e+0,2.430e+0};
static const G4double pejmax[10] = {3.513,1.968,1.479,1.239,1.116,
1.081,1.064,1.073,1.103,1.158};
static const G4double pa1[10] = { 3.218e+0, 2.412e+0, 2.715e+0, 2.787e+0, 2.541e+0,
2.508e+0, 2.600e+0, 3.231e+0, 4.588e+0, 6.584e+0};
static const G4double pa2[10] = {-5.528e-1, 2.523e+0, 1.738e+0, 2.082e+0, 1.423e+0,
4.682e-1,-6.883e-1,-2.147e+0,-5.127e+0,-1.054e+1};
static const G4double pa3[10] = { 3.618e+0, 2.032e+0, 2.341e+0, 2.172e+0, 7.205e-1,
4.655e-1, 6.318e-1, 1.255e+0, 2.425e+0, 4.938e+0};
static const G4double pa4[10] = { 2.437e+0, 9.450e-1, 4.349e-1, 2.221e-1, 1.130e-1,
5.405e-2, 2.245e-2, 7.370e-3, 1.456e-3, 1.508e-4};
static const G4double pw1[10] = {G4Exp(-palpha1[0]*peps),G4Exp(-palpha1[1]*peps),
G4Exp(-palpha1[2]*peps),G4Exp(-palpha1[3]*peps),
G4Exp(-palpha1[4]*peps),G4Exp(-palpha1[5]*peps),
G4Exp(-palpha1[6]*peps),G4Exp(-palpha1[7]*peps),
G4Exp(-palpha1[8]*peps),G4Exp(-palpha1[9]*peps)};
static const G4double pw2[10] = {pw1[0]-G4Exp(-palpha1[0]*(CLHEP::pi-peps)),
pw1[1]-G4Exp(-palpha1[1]*(CLHEP::pi-peps)),
pw1[2]-G4Exp(-palpha1[2]*(CLHEP::pi-peps)),
pw1[3]-G4Exp(-palpha1[3]*(CLHEP::pi-peps)),
pw1[4]-G4Exp(-palpha1[4]*(CLHEP::pi-peps)),
pw1[5]-G4Exp(-palpha1[5]*(CLHEP::pi-peps)),
pw1[6]-G4Exp(-palpha1[6]*(CLHEP::pi-peps)),
pw1[7]-G4Exp(-palpha1[7]*(CLHEP::pi-peps)),
pw1[8]-G4Exp(-palpha1[8]*(CLHEP::pi-peps)),
pw1[9]-G4Exp(-palpha1[9]*(CLHEP::pi-peps))};
G4int iphi = (G4int)(u*10.);
if(iphi < 0) { iphi = 0; }
else if(iphi > 9) { iphi = 9; }
G4int count = 0;
do {
rndmEngineMod->flatArray(2, rndmarray);
v = -G4Log(pw1[iphi]-pw2[iphi]*rndmarray[0])/palpha1[iphi];
rej = (G4Exp(-palpha[iphi]*v)*
(1+pa1[iphi]*v+pa2[iphi]*v*v+pa3[iphi]*v*v*v)+pa4[iphi])/
G4Exp(-pw1[iphi]*v);
}
// Loop checking, 5-March-2018, Vladimir Ivanchenko
while (pejmax[iphi]*rndmarray[1] > rej && ++count < 1000);
G4double Phi = (rndmEngineMod->flat() < 0.5) ? phi+v : phi-v;
fDisplacement.set(r*std::cos(Phi),r*std::sin(Phi),0.0);
// Gaussian distribution for Phi-phi=psi
const G4double sigma = 0.1+0.9*sqx;
const G4double psi = G4RandGauss::shoot(0.,sigma);
const G4double Phi = phi+psi;
fDisplacement.set(r*std::cos(Phi), r*std::sin(Phi), 0.0);
}
}
@@ -1182,7 +1107,10 @@ void G4UrbanMscModel::InitialiseModelCache()
// new couple
msc[j] = new mscData();
G4double Zeff = aCouple->GetMaterial()->GetIonisation()->GetZeffective();
msc[j]->sqrtZ = std::sqrt(Zeff);
G4double sqrz = std::sqrt(Zeff);
msc[j]->sqrtZ = sqrz;
// parameterisation of step limitation
msc[j]->factmin = dispAlg96 ? 0.001 : 0.001/(1.+0.028*sqrz);
G4double lnZ = G4Log(Zeff);
// correction in theta0 formula
G4double w = G4Exp(lnZ/6.);
@@ -70,8 +70,10 @@
#include "G4ModifiedTsai.hh"
#include "G4Exp.hh"
#include "G4Log.hh"
#include "G4Pow.hh"
#include "G4EmParameters.hh"
#include "G4AutoLock.hh"
#include <thread>
const G4int G4eBremsstrahlungRelModel::gMaxZet = 120;
@@ -116,6 +118,8 @@ G4eBremsstrahlungRelModel::LPMFuncs G4eBremsstrahlungRelModel::gLPMFuncs;
// special data structure per element i.e. per Z
std::vector<G4eBremsstrahlungRelModel::ElementData*> G4eBremsstrahlungRelModel::gElementData;
static std::once_flag applyOnce;
namespace
{
G4Mutex theBremRelMutex = G4MUTEX_INITIALIZER;
@@ -127,7 +131,7 @@ G4eBremsstrahlungRelModel::G4eBremsstrahlungRelModel(const G4ParticleDefinition*
{
fGammaParticle = G4Gamma::Gamma();
//
fLowestKinEnergy = 1.0*MeV;
fLowestKinEnergy = 1.0*CLHEP::MeV;
SetLowEnergyLimit(fLowestKinEnergy);
//
fLPMEnergyThreshold = 1.e+39;
@@ -141,12 +145,12 @@ G4eBremsstrahlungRelModel::G4eBremsstrahlungRelModel(const G4ParticleDefinition*
G4eBremsstrahlungRelModel::~G4eBremsstrahlungRelModel()
{
if (fIsFirstInstance) {
if (fIsInitializer) {
// clear ElementData container
for (auto const & ptr : gElementData) { delete ptr; }
gElementData.clear();
// clear LPMFunctions (if any)
if (fUseLPM) {
if (gLPMFuncs.fIsInitialized) {
gLPMFuncs.fLPMFuncG.clear();
gLPMFuncs.fLPMFuncPhi.clear();
gLPMFuncs.fIsInitialized = false;
@@ -165,18 +169,17 @@ void G4eBremsstrahlungRelModel::Initialise(const G4ParticleDefinition* p,
fCurrentIZ = 0;
// init static element data and precompute LPM functions only once
std::call_once(applyOnce, [this]() { fIsInitializer = true; });
// for all treads and derived classes
if (gElementData.empty()) {
if (fIsInitializer || gElementData.empty()) {
G4AutoLock l(&theBremRelMutex);
if (gElementData.empty()) {
fIsFirstInstance = true;
gElementData.resize(gMaxZet+1, nullptr);
}
l.unlock();
}
if (fIsFirstInstance) {
InitialiseElementData();
if (fUseLPM) { InitLPMFunctions(); }
InitLPMFunctions();
l.unlock();
}
// element selectors are initialized in the master thread
@@ -383,11 +386,11 @@ G4double G4eBremsstrahlungRelModel::ComputeXSectionPerAtom(G4double tmin)
{
G4double xSection = 0.0;
const G4double alphaMin = G4Log(tmin/fPrimaryTotalEnergy);
const G4double alphaMax = G4Log(fPrimaryKinEnergy/fPrimaryTotalEnergy);
const G4int nSub = (G4int)(0.45*(alphaMax-alphaMin))+4;
const G4double delta = (alphaMax-alphaMin)/((G4double)nSub);
const G4double alphaMax = G4Log(fPrimaryKinEnergy/tmin);
const G4int nSub = std::max((G4int)(0.45*alphaMax), 0) + 4;
const G4double delta = alphaMax/((G4double)nSub);
// set minimum value of the first sub-inteval
G4double alpha_i = alphaMin;
G4double alpha_i = alphaMin;
for (G4int l = 0; l < nSub; ++l) {
for (G4int igl = 0; igl < 8; ++igl) {
// compute the emitted photon energy k
@@ -550,7 +553,6 @@ G4eBremsstrahlungRelModel::SampleSecondaries(std::vector<G4DynamicParticle*>* vd
G4double maxEnergy)
{
const G4double kineticEnergy = dp->GetKineticEnergy();
// const G4double logKineticEnergy = dp->GetLogKineticEnergy();
if (kineticEnergy < LowEnergyLimit()) {
return;
}
@@ -650,8 +652,8 @@ void G4eBremsstrahlungRelModel::InitialiseElementData()
Fel = G4Log(184.15) - elemData->fLogZ/3.;
Finel = G4Log(1194) - 2.*elemData->fLogZ/3.;
}
const G4double z23 = std::pow(zet,2./3.);
const G4double z13 = std::pow(zet,1./3.);
const G4double z13 = G4Pow::GetInstance()->Z13(izet);
const G4double z23 = z13*z13;
elemData->fZFactor1 = (Fel-fc)+Finel/zet;
elemData->fZFactor11 = (Fel-fc); // used only for the triplet
elemData->fZFactor2 = (1.+1./zet)/12.;