Import Geant4 10.7.0 source tree

This commit is contained in:
Gabriele Cosmo
2020-12-04 12:30:43 +01:00
parent 67ba86d073
commit dab42d2018
3770 changed files with 226369 additions and 286486 deletions
@@ -62,8 +62,8 @@ G4DeltaAngle::G4DeltaAngle(const G4String&)
{
fElectron = G4Electron::Electron();
nprob = 26;
prob.resize(nprob,0.0);
fShellIdx = -1;
prob.resize(nprob,0.0);
}
G4DeltaAngle::~G4DeltaAngle()
@@ -191,6 +191,3 @@ G4DeltaAngle::SampleDirection(const G4DynamicParticle* dp,
return fLocalDirection;
}
void G4DeltaAngle::PrintGeneratorInformation() const
{}
@@ -93,14 +93,14 @@ void G4ICRU49NuclearStoppingModel::InitialiseArray()
if(0.0 == Z23[1]) {
#ifdef G4MULTITHREADED
G4MUTEXLOCK(&G4ICRU49NuclearStoppingModel::ICRU49NuclearMutex);
#endif
if(0.0 == Z23[1]) {
#endif
for(G4int i=2; i<100; ++i) {
Z23[i] = g4calc->powZ(i, 0.23);
}
Z23[1] = 1.0;
}
#ifdef G4MULTITHREADED
}
G4MUTEXUNLOCK(&G4ICRU49NuclearStoppingModel::ICRU49NuclearMutex);
#endif
}
@@ -54,12 +54,14 @@
#include "G4Log.hh"
#include "G4DeltaAngle.hh"
#include "G4LindhardSorensenData.hh"
#include "G4BraggIonModel.hh"
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
using namespace std;
G4LindhardSorensenData* G4LindhardSorensenIonModel::lsdata = nullptr;
std::vector<G4float>* G4LindhardSorensenIonModel::fact[] = {nullptr};
G4LindhardSorensenIonModel::G4LindhardSorensenIonModel(const G4ParticleDefinition*,
const G4String& nam)
@@ -73,6 +75,7 @@ G4LindhardSorensenIonModel::G4LindhardSorensenIonModel(const G4ParticleDefinitio
SetParticle(theElectron);
corr = G4LossTableManager::Instance()->EmCorrections();
nist = G4NistManager::Instance();
fBraggIonModel = new G4BraggIonModel();
SetLowEnergyLimit(2.0*MeV);
}
@@ -84,23 +87,23 @@ G4LindhardSorensenIonModel::~G4LindhardSorensenIonModel()
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
void G4LindhardSorensenIonModel::Initialise(const G4ParticleDefinition* p,
const G4DataVector&)
const G4DataVector& ptr)
{
fBraggIonModel->Initialise(p, ptr);
SetParticle(p);
//G4cout << "G4LindhardSorensenIonModel::Initialise for " << p->GetParticleName()
// << G4endl;
//G4cout << "G4LindhardSorensenIonModel::Initialise for "
// << p->GetParticleName() << G4endl;
// always false before the run
SetDeexcitationFlag(false);
if(nullptr == fParticleChange) {
fParticleChange = GetParticleChangeForLoss();
if(UseAngularGeneratorFlag() && !GetAngularDistribution()) {
if(UseAngularGeneratorFlag() && nullptr == GetAngularDistribution()) {
SetAngularDistribution(new G4DeltaAngle());
}
}
if(IsMaster() && !lsdata) {
if(IsMaster() && nullptr == lsdata) {
lsdata = new G4LindhardSorensenData();
}
}
@@ -59,7 +59,7 @@
#include "G4ParticleChangeForLoss.hh"
#include "G4SBBremTable.hh"
#include "G4ModifiedTsai.hh"
//#include "G4DipBustGenerator.hh"
#include "G4EmParameters.hh"
#include "G4ProductionCutsTable.hh"
@@ -75,7 +75,7 @@
G4Physics2DVector* G4SeltzerBergerModel::gSBDCSData[] = { nullptr };
G4SBBremTable* G4SeltzerBergerModel::gSBSamplingTable = nullptr;
G4double G4SeltzerBergerModel::gYLimitData[] = { 0.0 };
G4double G4SeltzerBergerModel::gYLimitData[] = { 0.0 };
G4String G4SeltzerBergerModel::gDataDirectory = "";
#ifdef G4MULTITHREADED
@@ -128,11 +128,10 @@ void G4SeltzerBergerModel::Initialise(const G4ParticleDefinition* p,
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));
for (auto & elm : *elmVec) {
G4int Z = std::max(1,std::min(elm->GetZasInt(), gMaxZet-1));
// load SB-DCS data for this atomic number if it has not been loaded yet
InitialiseForElement(nullptr, Z);
if (gSBDCSData[Z] == nullptr) ReadData(Z);
}
}
// elem.selectr. only for master: base class init-local will set for workers
@@ -177,9 +176,13 @@ const G4String& G4SeltzerBergerModel::FindDirectoryPath()
void G4SeltzerBergerModel::ReadData(G4int Z) {
// return if it has been already loaded
if (gSBDCSData[Z]) {
return;
}
if (gSBDCSData[Z] != nullptr) return;
#ifdef G4MULTITHREADED
G4MUTEXLOCK(&theSBMutex);
if (gSBDCSData[Z] != nullptr) return;
#endif
std::ostringstream ost;
ost << FindDirectoryPath() << Z;
std::ifstream fin(ost.str().c_str());
@@ -207,6 +210,9 @@ void G4SeltzerBergerModel::ReadData(G4int Z) {
ed,"G4LEDATA version should be G4EMLOW6.23 or later.");
delete v;
}
#ifdef G4MULTITHREADED
G4MUTEXUNLOCK(&theSBMutex);
#endif
}
G4double G4SeltzerBergerModel::ComputeDXSectionPerAtom(G4double gammaEnergy)
@@ -222,8 +228,8 @@ G4double G4SeltzerBergerModel::ComputeDXSectionPerAtom(G4double gammaEnergy)
// make sure that the Z-related SB-DCS are loaded
// NOTE: fCurrentIZ should have been set before.
fCurrentIZ = std::max(std::min(fCurrentIZ, gMaxZet-1), 1);
if (!gSBDCSData[fCurrentIZ]) {
InitialiseForElement(nullptr, fCurrentIZ);
if (nullptr == gSBDCSData[fCurrentIZ]) {
ReadData(fCurrentIZ);
}
// NOTE: SetupForMaterial should have been called before!
const G4double pt2 = fPrimaryKinEnergy*(fPrimaryKinEnergy+2.*kMC2);
@@ -336,8 +342,8 @@ G4SeltzerBergerModel::SampleEnergyTransfer(const G4double kinEnergy,
// majoranta
const G4double x0 = tmin/kinEnergy;
G4double vmax;
if (!gSBDCSData[fCurrentIZ]) {
InitialiseForElement(nullptr, fCurrentIZ);
if (nullptr == gSBDCSData[fCurrentIZ]) {
ReadData(fCurrentIZ);
}
vmax = gSBDCSData[fCurrentIZ]->Value(x0, y, fIndx, fIndy)*1.02;
//
@@ -400,22 +406,6 @@ G4SeltzerBergerModel::SampleEnergyTransfer(const G4double kinEnergy,
return gammaEnergy;
}
void G4SeltzerBergerModel::InitialiseForElement(const G4ParticleDefinition*,
G4int Z)
{
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)
@@ -542,7 +542,8 @@ G4double G4UrbanMscModel::ComputeTruePathLengthLimit(
}
//step limit
tlimit = facrange*rangeinit;
tlimit = (currentRange > presafety) ?
std::max(facrange*rangeinit, facsafety*presafety) : currentRange;
//lower limit for tlimit
tlimit = std::min(std::max(tlimit,tlimitmin), tgeom);
@@ -727,9 +728,6 @@ G4double G4UrbanMscModel::ComputeGeomPathLength(G4double)
// z = t for very small tPathLength
if(tPathLength < tlimitminfix2) return zPathLength;
// VI: it is already checked
// if(tPathLength > currentRange)
// tPathLength = currentRange ;
/*
G4cout << "ComputeGeomPathLength: tpl= " << tPathLength
<< " R= " << currentRange << " L0= " << lambda0
@@ -1133,10 +1131,9 @@ void G4UrbanMscModel::SampleDisplacement(G4double, G4double phi)
void G4UrbanMscModel::SampleDisplacementNew(G4double, G4double phi)
{
// best sampling based on single scattering results
G4double rmax = sqrt((tPathLength-zPathLength)*(tPathLength+zPathLength));
G4double r = 0.;
G4double u = r/rmax;
G4double r(0.0);
G4double u(0.0);
static const G4double reps = 5.e-3;
if(rmax > 0.)
@@ -1294,7 +1291,12 @@ void G4UrbanMscModel::InitialiseModelCache()
msc[j]->stepmina = 27.725/(1.+0.203*Zeff);
msc[j]->stepminb = 6.152/(1.+0.111*Zeff);
msc[j]->doverra = 1.20 - Zeff*(0.0162 - 9.22e-5*Zeff);
// 21.07.2020
msc[j]->doverra = 9.6280e-1 - 8.4848e-2*msc[j]->sqrtZ + 4.3769e-3*Zeff;
// 06.10.2020
// msc[j]->doverra = 7.7024e-1 - 6.7878e-2*msc[j]->sqrtZ + 3.5015e-3*Zeff;
msc[j]->doverrb = 1.15 - 9.76e-4*Zeff;
}
}
@@ -151,8 +151,8 @@ void G4WentzelOKandVIxSection::InitialiseA()
// Formfactors from A.V. Butkevich et al., NIM A 488 (2002) 282
#ifdef G4MULTITHREADED
G4MUTEXLOCK(&G4WentzelOKandVIxSection::WentzelOKandVIxSectionMutex);
#endif
if(0.0 == ScreenRSquare[0]) {
#endif
G4double a0 = electron_mass_c2/0.88534;
G4double constn = 6.937e-6/(MeV*MeV);
G4double fct = G4EmParameters::Instance()->ScreeningFactor();
@@ -170,8 +170,8 @@ void G4WentzelOKandVIxSection::InitialiseA()
x = fNistManager->GetA27(j);
FormFactor[j] = constn*x*x;
}
}
#ifdef G4MULTITHREADED
}
G4MUTEXUNLOCK(&G4WentzelOKandVIxSection::WentzelOKandVIxSectionMutex);
#endif
@@ -67,7 +67,7 @@
std::vector<G4double> G4WentzelVIRelModel::effMass;
#ifdef G4MULTITHREADED
G4Mutex G4WentzelVIRelModel::WentzelVIRelModelMutex;
G4Mutex G4WentzelVIRelModel::WentzelVIRelModelMutex = G4MUTEX_INITIALIZER;
#endif
G4WentzelVIRelModel::G4WentzelVIRelModel() :
@@ -152,13 +152,13 @@ G4double G4WentzelVIRelModel::ComputeCrossSectionPerAtom(
void G4WentzelVIRelModel::ComputeEffectiveMass()
{
#ifdef G4MULTITHREADED
G4MUTEXLOCK(&G4WentzelVIRelModel::WentzelVIRelModelMutex);
#endif
const G4ProductionCutsTable* theCoupleTable =
G4ProductionCutsTable::GetProductionCutsTable();
size_t ncouples = theCoupleTable->GetTableSize();
#ifdef G4MULTITHREADED
G4MUTEXLOCK(&G4WentzelVIRelModel::WentzelVIRelModelMutex);
if(ncouples != effMass.size()) {
#endif
effMass.resize(ncouples, 0.0);
for(size_t i=0; i<ncouples; ++i) {
const G4Material* mat =
@@ -168,16 +168,16 @@ void G4WentzelVIRelModel::ComputeEffectiveMass()
G4double sum = 0.0;
G4double norm= 0.0;
for(G4int j=0; j<nelm; ++j) {
G4int Z = (*elmVector)[j]->GetZasInt();
G4double mass = fNistManager->GetAtomicMassAmu(Z)*CLHEP::amu_c2;
G4int Z2 = Z*Z;
sum += mass*Z2;
norm += Z2;
G4int Z = (*elmVector)[j]->GetZasInt();
G4double mass = fNistManager->GetAtomicMassAmu(Z)*CLHEP::amu_c2;
G4int Z2 = Z*Z;
sum += mass*Z2;
norm += Z2;
}
effMass[i] = sum/norm;
}
}
#ifdef G4MULTITHREADED
}
G4MUTEXUNLOCK(&G4WentzelVIRelModel::WentzelVIRelModelMutex);
#endif
}
@@ -426,7 +426,7 @@ G4double G4eBremsstrahlungRelModel::ComputeXSectionPerAtom(G4double tmin)
// v(k)=ln(k/E_t) -> dk/dv=E_t*e^v=k -> ds/dv= ds/dk*dk/dv=ds/dk*k so it
// would cnacell out the 1/k factor => 1/k don't included here
// (ii) the constant factor C and Z don't depend on 'k' => not included here
// (iii) the 1/F(k) factor is accounted in the callers: explicitely (cross sec-
// (iii) the 1/F(k) factor is accounted in the callers: explicitly (cross sec-
// tion computation) or implicitly through further variable transformaton
// (in the final state sampling algorithm)
// COMPLETE SCREENING: see more at the DCS without LPM effect below.
@@ -460,7 +460,7 @@ G4eBremsstrahlungRelModel::ComputeRelDXSectionPerAtom(G4double gammaEnergy)
// where f_c(Z) is the Coulomb correction factor and phi1(g),phi2(g) and psi1(e),
// psi2(e) are coherent and incoherent screening functions. In the Thomas-Fermi
// model of the atom, the screening functions will have a form that do not
// depend on Z (not explicitely). These numerical screening functions can be
// depend on Z (not explicitly). These numerical screening functions can be
// approximated as Tsai Eqs. [3.38-3.41] with the variables g=gamma and
// e=epsilon given by Tsai Eqs. [3.30 and 3.31] (see more details at the method
// ComputeScreeningFunctions()). Note, that in case of complete screening i.e.
@@ -0,0 +1,195 @@
//
// ********************************************************************
// * 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: G4eDPWACoulombScatteringModel
//
// Author: Mihaly Novak
//
// Creation date: 02.07.2020
//
// Modifications:
//
// -------------------------------------------------------------------
#include "G4eDPWACoulombScatteringModel.hh"
#include "G4eDPWAElasticDCS.hh"
#include "G4ParticleChangeForGamma.hh"
#include "G4ParticleDefinition.hh"
#include "G4DataVector.hh"
#include "G4ProductionCutsTable.hh"
#include "G4Material.hh"
#include "G4Element.hh"
#include "G4ElementVector.hh"
#include "G4Electron.hh"
#include "G4PhysicalConstants.hh"
#include "G4SystemOfUnits.hh"
#include "Randomize.hh"
#include "G4ThreeVector.hh"
G4eDPWACoulombScatteringModel::G4eDPWACoulombScatteringModel(G4bool ismixed, G4bool isscpcor, G4double mumin)
: G4VEmModel("eDPWACoulombScattering"),
fIsMixedModel(ismixed),
fIsScpCorrection(isscpcor),
fMuMin(mumin),
fTheDCS(nullptr),
fParticleChange(nullptr)
{
SetLowEnergyLimit ( 0.0*CLHEP::eV); // ekin = 10 eV is used if (E< 10 eV)
SetHighEnergyLimit(100.0*CLHEP::MeV); // ekin = 100 MeV is used if (E>100 MeV)
}
G4eDPWACoulombScatteringModel::~G4eDPWACoulombScatteringModel()
{
if (IsMaster()) {
delete fTheDCS;
}
}
void G4eDPWACoulombScatteringModel::Initialise(const G4ParticleDefinition* pdef,
const G4DataVector& prodcuts)
{
if(!fParticleChange) {
fParticleChange = GetParticleChangeForGamma();
}
fMuMin = 0.5*(1.0-std::cos(PolarAngleLimit()));
fIsMixedModel = (fMuMin > 0.0);
if(IsMaster()) {
// clean the G4eDPWAElasticDCS object if any
if (fTheDCS) {
delete fTheDCS;
}
fTheDCS = new G4eDPWAElasticDCS(pdef==G4Electron::Electron(), fIsMixedModel);
// init only for the elements that are used in the geometry
G4ProductionCutsTable* theCpTable = G4ProductionCutsTable::GetProductionCutsTable();
std::size_t numOfCouples = theCpTable->GetTableSize();
for(std::size_t j=0; j<numOfCouples; ++j) {
const G4Material* mat = theCpTable->GetMaterialCutsCouple(j)->GetMaterial();
const G4ElementVector* elV = mat->GetElementVector();
std::size_t numOfElem = mat->GetNumberOfElements();
for (size_t ie = 0; ie < numOfElem; ++ie) {
fTheDCS->InitialiseForZ((*elV)[ie]->GetZasInt());
}
}
// init scattering power correction
if (fIsScpCorrection) {
fTheDCS->InitSCPCorrection(LowEnergyLimit(), HighEnergyLimit());
}
// will make use of the cross sections so the above needs to be done before
InitialiseElementSelectors(pdef, prodcuts);
}
}
void G4eDPWACoulombScatteringModel::InitialiseLocal(const G4ParticleDefinition*,
G4VEmModel* masterModel)
{
SetElementSelectors(masterModel->GetElementSelectors());
SetTheDCS(static_cast<G4eDPWACoulombScatteringModel*>(masterModel)->GetTheDCS());
}
G4double
G4eDPWACoulombScatteringModel::ComputeCrossSectionPerAtom(const G4ParticleDefinition*,
G4double ekin,
G4double Z,
G4double /*A*/,
G4double /*prodcut*/,
G4double /*emax*/)
{
// Cross sections are computed by numerical integration of the pre-computed
// DCS data between the muMin, muMax limits where mu(theta)=0.5[1-cos(theta)].
// In case of single scattering model (i.e. when fMuMin=0): [muMin=0, muMax=1]
// In case of mixed simulation model (i.e. when fMuMin>0): [fMuMin , muMax=1]
// NOTE: cross sections will be zero if the kinetic enrgy is out of the
// [10 eV-100 MeV] range for which DCS data has been computed.
//
G4double elCS = 0.0; // elastic cross section
G4double tr1CS = 0.0; // first transport cross section
G4double tr2CS = 0.0; // second transport cross section
const G4double muMin = fMuMin;
const G4double muMax = 1.0;
fTheDCS->ComputeCSPerAtom((G4int)Z, ekin, elCS, tr1CS, tr2CS, muMin, muMax);
// scattering power correction: should be only in condensed history ioni!
if (fIsScpCorrection && CurrentCouple()) {
const G4double theScpCor = fTheDCS->ComputeScatteringPowerCorrection(CurrentCouple(), ekin);
elCS *= (theScpCor*(1.0+1.0/Z));
}
return std::max(0.0, elCS);
}
void
G4eDPWACoulombScatteringModel::SampleSecondaries(std::vector<G4DynamicParticle*>*,
const G4MaterialCutsCouple* cp,
const G4DynamicParticle* dp,
G4double, G4double)
{
const G4double ekin = dp->GetKineticEnergy();
const G4double lekin = dp->GetLogKineticEnergy();
const G4Element* target = SelectTargetAtom(cp, dp->GetParticleDefinition(), ekin, lekin);
const G4int izet = target->GetZasInt();
// sample cosine of the polar scattering angle in (hard) elastic insteraction
CLHEP::HepRandomEngine* rndmEngine = G4Random::getTheEngine();
G4double cost = 1.0;
if (!fIsMixedModel) {
G4double rndm[3];
rndmEngine->flatArray(3, rndm);
cost = fTheDCS->SampleCosineTheta(izet, lekin, rndm[0], rndm[1], rndm[2]);
} else {
//sample cost between costMax,costMin where costMax = 1-2xfMuMin;
const G4double costMax = 1.0-2.0*fMuMin;
const G4double costMin = -1.0;
G4double rndm[2];
rndmEngine->flatArray(2, rndm);
cost = fTheDCS->SampleCosineThetaRestricted(izet, lekin, rndm[0], rndm[1], costMin, costMax);
}
// compute the new direction in the scattering frame
const G4double sint = std::sqrt((1.0-cost)*(1.0+cost));
const G4double phi = CLHEP::twopi*rndmEngine->flat();
G4ThreeVector theNewDirection(sint*std::cos(phi), sint*std::sin(phi), cost);
// get original direction in lab frame and rotate new direction to lab frame
G4ThreeVector theOrgDirectionLab = dp->GetMomentumDirection();
theNewDirection.rotateUz(theOrgDirectionLab);
// set new direction
fParticleChange->ProposeMomentumDirection(theNewDirection);
}
@@ -0,0 +1,705 @@
//
// ********************************************************************
// * 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: G4eDPWAElasticDCS
//
// Author: Mihaly Novak
//
// Creation date: 02.07.2020
//
// Modifications:
//
//
// -------------------------------------------------------------------
#include "G4eDPWAElasticDCS.hh"
#include "G4Physics2DVector.hh"
//
// Global variables:
//
G4bool G4eDPWAElasticDCS::gIsGridLoaded = false;
G4String G4eDPWAElasticDCS::gDataDirectory = "";
// final values of these variables will be set in LoadGrid() called by master
std::size_t G4eDPWAElasticDCS::gNumEnergies = 106;
std::size_t G4eDPWAElasticDCS::gIndxEnergyLim = 35;
std::size_t G4eDPWAElasticDCS::gNumThetas1 = 247;
std::size_t G4eDPWAElasticDCS::gNumThetas2 = 128;
G4double G4eDPWAElasticDCS::gLogMinEkin = 1.0;
G4double G4eDPWAElasticDCS::gInvDelLogEkin = 1.0;
// containers for grids: Ekin, mu(t)=0.5[1-cos(t)] and u(mu,A)=(A+1)mu/(mu+A)
std::vector<G4double> G4eDPWAElasticDCS::gTheEnergies(G4eDPWAElasticDCS::gNumEnergies);
std::vector<G4double> G4eDPWAElasticDCS::gTheMus1(G4eDPWAElasticDCS::gNumThetas1);
std::vector<G4double> G4eDPWAElasticDCS::gTheMus2(G4eDPWAElasticDCS::gNumThetas2);
std::vector<G4double> G4eDPWAElasticDCS::gTheU1(G4eDPWAElasticDCS::gNumThetas1);
std::vector<G4double> G4eDPWAElasticDCS::gTheU2(G4eDPWAElasticDCS::gNumThetas2);
// abscissas and weights of an 8 point Gauss-Legendre quadrature
// for numerical integration on [0,1]
const G4double G4eDPWAElasticDCS::gXGL[] = {
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 G4eDPWAElasticDCS::gWGL[] = {
5.06142681E-02, 1.11190517E-01, 1.56853323E-01, 1.81341892E-01,
1.81341892E-01, 1.56853323E-01, 1.11190517E-01, 5.06142681E-02
};
// - iselectron : data for e- (for e+ otherwise)
// - isrestricted : sampling of angular deflection on restricted interavl is
// required (i.e. in case of mixed-simulation models)
G4eDPWAElasticDCS::G4eDPWAElasticDCS(G4bool iselectron, G4bool isrestricted)
: fIsRestrictedSamplingRequired(isrestricted), fIsElectron(iselectron) {
fDCS.resize(gMaxZ+1, nullptr);
fDCSLow.resize(gMaxZ+1, nullptr);
fSamplingTables.resize(gMaxZ+1, nullptr);
}
// DTR
G4eDPWAElasticDCS::~G4eDPWAElasticDCS() {
for (std::size_t i=0; i<fDCS.size(); ++i) {
if (fDCS[i]) delete fDCS[i];
}
for (std::size_t i=0; i<fDCSLow.size(); ++i) {
if (fDCSLow[i]) delete fDCSLow[i];
}
for (std::size_t i=0; i<fSamplingTables.size(); ++i) {
if (fSamplingTables[i]) delete fSamplingTables[i];
}
// clear scp correction data
for (std::size_t imc=0; imc<fSCPCPerMatCuts.size(); ++imc) {
if (fSCPCPerMatCuts[imc]) {
fSCPCPerMatCuts[imc]->fVSCPC.clear();
delete fSCPCPerMatCuts[imc];
}
}
fSCPCPerMatCuts.clear();
}
// initialise for a given 'iz' atomic number:
// - nothing happens if it has already been initialised for that Z.
void G4eDPWAElasticDCS::InitialiseForZ(std::size_t iz) {
if (!gIsGridLoaded) {
LoadGrid();
}
LoadDCSForZ(iz);
BuildSmplingTableForZ(iz);
}
// loads the kinetic energy and theta grids for the DCS data (first init step)
// should be called only by the master
void G4eDPWAElasticDCS::LoadGrid() {
G4String fname = FindDirectoryPath() + "grid.dat";
std::ifstream infile(fname.c_str());
if (!infile.is_open()) {
G4String msg =
" Problem while trying to read " + fname + " file.\n"+
" G4LEDATA version should be G4EMLOW7.12 or later.\n";
G4Exception("G4eDPWAElasticDCS::ReadCompressedFile","em0006",
FatalException,msg.c_str());
return;
}
// read size
infile >> gNumEnergies;
infile >> gNumThetas1;
infile >> gNumThetas2;
// read the grids
// - energy in [MeV]
G4double dum = 0.0;
gTheEnergies.resize(gNumEnergies);
for (std::size_t ie=0; ie<gNumEnergies; ++ie) {
infile >> dum;
gTheEnergies[ie] = G4Log(dum*CLHEP::MeV);
if (gTheEnergies[ie]<G4Log(2.0*CLHEP::keV)) gIndxEnergyLim = ie; // only for e-
}
++gIndxEnergyLim;
// store/set usefull logarithms of the kinetic energy grid
gLogMinEkin = gTheEnergies[0];
gInvDelLogEkin = (gNumEnergies-1)/(gTheEnergies[gNumEnergies-1]-gTheEnergies[0]);
// - theta1 in [deg.] (247): we store mu(theta) = 0.5[1-cos(theta)]
gTheMus1.resize(gNumThetas1);
gTheU1.resize(gNumThetas1);
const double theA = 0.01;
for (std::size_t it=0; it<gNumThetas1; ++it) {
infile >> dum;
gTheMus1[it] = 0.5*(1.0-std::cos(dum*CLHEP::degree));
gTheU1[it] = (theA+1.0)*gTheMus1[it]/(theA+gTheMus1[it]);
}
// - theta2 in [deg.] (128): we store mu(theta) = 0.5[1-cos(theta)]
gTheMus2.resize(gNumThetas2);
gTheU2.resize(gNumThetas2);
for (std::size_t it=0; it<gNumThetas2; ++it) {
infile >> dum;
gTheMus2[it] = 0.5*(1.0-std::cos(dum*CLHEP::degree));
gTheU2[it] = (theA+1.0)*gTheMus2[it]/(theA+gTheMus2[it]);
}
infile.close();
gIsGridLoaded = true;
}
// load DCS data for a given Z
void G4eDPWAElasticDCS::LoadDCSForZ(G4int iz) {
// Check if it has already been done:
if (fDCS[iz]) return;
// Do it otherwise
if (fIsElectron) {
// e-
// load the high energy part firt:
// - with gNumThetas2 theta and gNumEnergies-gIndxEnergyLim energy values
const std::size_t hNumEnergries = gNumEnergies-gIndxEnergyLim;
G4Physics2DVector* v2DHigh = new G4Physics2DVector(gNumThetas2, hNumEnergries);
v2DHigh->SetBicubicInterpolation(true);
for (std::size_t it=0; it<gNumThetas2; ++it) {
v2DHigh->PutX(it, gTheMus2[it]);
}
for (std::size_t ie=0; ie<hNumEnergries; ++ie) {
v2DHigh->PutY(ie, gTheEnergies[gIndxEnergyLim+ie]);
}
std::ostringstream ossh;
ossh << FindDirectoryPath() << "dcss/el/dcs_"<< iz<<"_h";
std::istringstream finh(std::ios::in);
ReadCompressedFile(ossh.str(), finh);
G4double dum = 0.0;
for (std::size_t it=0; it<gNumThetas2; ++it) {
finh >> dum;
for (std::size_t ie=0; ie<hNumEnergries; ++ie) {
finh >> dum;
v2DHigh->PutValue(it, ie, G4Log(dum*CLHEP::cm2/CLHEP::sr));
}
}
// load the low energy part:
// - with gNumThetas1 theta and gIndxEnergyLim+1 energy values (the +1 is
// for including the firts DCS from the higher part above for being
// able to perform interpolation between the high and low energy DCS set)
G4Physics2DVector* v2DLow = new G4Physics2DVector(gNumThetas1, gIndxEnergyLim+1);
v2DLow->SetBicubicInterpolation(true);
for (std::size_t it=0; it<gNumThetas1; ++it) {
v2DLow->PutX(it, gTheMus1[it]);
}
for (std::size_t ie=0; ie<gIndxEnergyLim+1; ++ie) {
v2DLow->PutY(ie, gTheEnergies[ie]);
}
std::ostringstream ossl;
ossl << FindDirectoryPath() << "dcss/el/dcs_"<< iz<<"_l";
std::istringstream finl(std::ios::in);
ReadCompressedFile(ossl.str(), finl);
for (std::size_t it=0; it<gNumThetas1; ++it) {
finl >> dum;
for (std::size_t ie=0; ie<gIndxEnergyLim; ++ie) {
finl >> dum;
v2DLow->PutValue(it, ie, G4Log(dum*CLHEP::cm2/CLHEP::sr));
}
}
// add the +1 part: interpolate the firts DCS from the high energy
std::size_t ix = 0;
std::size_t iy = 0;
for (std::size_t it=0; it<gNumThetas1; ++it) {
const G4double val = v2DHigh->Value(gTheMus1[it], gTheEnergies[gIndxEnergyLim], ix, iy);
v2DLow->PutValue(it, gIndxEnergyLim, val);
}
// store
fDCSLow[iz] = v2DLow;
fDCS[iz] = v2DHigh;
} else {
// e+
G4Physics2DVector* v2D= new G4Physics2DVector(gNumThetas2, gNumEnergies);
v2D->SetBicubicInterpolation(true);
for (std::size_t it=0; it<gNumThetas2; ++it) {
v2D->PutX(it, gTheMus2[it]);
}
for (std::size_t ie=0; ie<gNumEnergies; ++ie) {
v2D->PutY(ie, gTheEnergies[ie]);
}
std::ostringstream oss;
oss << FindDirectoryPath() << "dcss/pos/dcs_"<< iz;
std::istringstream fin(std::ios::in);
ReadCompressedFile(oss.str(), fin);
G4double dum = 0.0;
for (std::size_t it=0; it<gNumThetas2; ++it) {
fin >> dum;
for (std::size_t ie=0; ie<gNumEnergies; ++ie) {
fin >> dum;
v2D->PutValue(it, ie, G4Log(dum*CLHEP::cm2/CLHEP::sr));
}
}
fDCS[iz]= v2D;
}
}
// Computes the elastic, first and second cross sections for the given kinetic
// energy and target atom.
// Cross sections are zero ff ekin is below/above the kinetic energy grid
void G4eDPWAElasticDCS::ComputeCSPerAtom(G4int iz, G4double ekin, G4double& elcs,
G4double& tr1cs, G4double& tr2cs,
G4double mumin, G4double mumax) {
// init all cross section values to zero;
elcs = 0.0;
tr1cs = 0.0;
tr2cs = 0.0;
// make sure that mu(theta) = 0.5[1-cos(theta)] limits have appropriate vals
mumin = std::max(0.0, std::min(1.0, mumin));
mumax = std::max(0.0, std::min(1.0, mumax));
if (mumin>=mumax) return;
// make sure that kin. energy is within the available range (10 eV-100MeV)
const G4double lekin = std::max(gTheEnergies[0], std::min(gTheEnergies[gNumEnergies-1], G4Log(ekin)));
// if the lower, denser in theta, DCS set should be used
const G4bool isLowerGrid = (fIsElectron && lekin<gTheEnergies[gIndxEnergyLim]);
const std::vector<G4double>& theMuVector = (isLowerGrid) ? gTheMus1 : gTheMus2;
const G4Physics2DVector* the2DDCS = (isLowerGrid) ? fDCSLow[iz] : fDCS[iz];
// find lower/upper mu bin of integration:
// 0.0 <= mumin < 1.0 for sure here
const std::size_t iMuStart = (mumin == 0.0) ? 0 : std::distance( theMuVector.begin(), std::upper_bound(theMuVector.begin(), theMuVector.end(), mumin) )-1 ;
// 0.0 < mumax <= 1.0 for sure here
const std::size_t iMuEnd = (mumax == 1.0) ? theMuVector.size()-2 : std::distance( theMuVector.begin(), std::upper_bound(theMuVector.begin(), theMuVector.end(), mumax) )-1 ;
// perform numerical integration of the DCS over the given [mumin, mumax]
// interval (where mu(theta) = 0.5[1-cos(theta)]) to get the elastic, first
std::size_t ix = 0;
std::size_t iy = 0;
for (std::size_t imu=iMuStart; imu<=iMuEnd; ++imu) {
G4double elcsPar = 0.0;
G4double tr1csPar = 0.0;
G4double tr2csPar = 0.0;
const G4double low = (imu==iMuStart) ? mumin : theMuVector[imu];
const G4double del = (imu==iMuEnd) ? mumax-low : theMuVector[imu+1]-low;
ix = imu;
for (std::size_t igl=0; igl<8; ++igl) {
const double mu = low + del*gXGL[igl];
const double dcs = G4Exp(the2DDCS->Value(mu, lekin, ix, iy));
elcsPar += gWGL[igl]*dcs; // elastic
tr1csPar += gWGL[igl]*dcs*mu; // first transport
tr2csPar += gWGL[igl]*dcs*mu*(1.0-mu); // second transport
}
elcs += del*elcsPar;
tr1cs += del*tr1csPar;
tr2cs += del*tr2csPar;
}
elcs *= 2.0*CLHEP::twopi;
tr1cs *= 4.0*CLHEP::twopi;
tr2cs *= 12.0*CLHEP::twopi;
}
// data structure to store one sampling table: combined Alias + RatIn
// NOTE: when Alias is used, sampling on a resctricted interval is not possible
// However, Alias makes possible faster sampling. Alias is used in case
// of single scattering model while it's not used in case of mixed-model
// when restricted interval sampling is needed. This is controlled by
// the fIsRestrictedSamplingRequired flag (false by default).
struct OneSamplingTable {
OneSamplingTable () {}
void SetSize(std::size_t nx, G4bool useAlias) {
fN = nx;
// Alias
if (useAlias) {
fW.resize(nx);
fI.resize(nx);
}
// Ratin
fCum.resize(nx);
fA.resize(nx);
fB.resize(nx);
}
// members
std::size_t fN; // # data points
G4double fScreenParA; // the screening parameter
std::vector<G4double> fW;
std::vector<G4double> fCum;
std::vector<G4double> fA;
std::vector<G4double> fB;
std::vector<G4int> fI;
};
// loads sampling table for the given Z over the enrgy grid
void G4eDPWAElasticDCS::BuildSmplingTableForZ(G4int iz) {
// Check if it has already been done:
if (fSamplingTables[iz]) return;
// Do it otherwise:
// allocate space
std::vector<OneSamplingTable>* sTables = new std::vector<OneSamplingTable>(gNumEnergies);
// read compressed sampling table data
std::ostringstream oss;
const G4String fname = fIsElectron ? "stables/el/" : "stables/pos/";
oss << FindDirectoryPath() << fname << "stable_" << iz;
std::istringstream fin(std::ios::in);
ReadCompressedFile(oss.str(), fin);
std::size_t ndata = 0;
for (std::size_t ie=0; ie<gNumEnergies; ++ie) {
OneSamplingTable& aTable = (*sTables)[ie];
// #data in this table
fin >> ndata;
aTable.SetSize(ndata, !fIsRestrictedSamplingRequired);
// the A screening parameter value used for transformation of mu to u
fin >> aTable.fScreenParA;
// load data: Alias(W,I) + RatIn(Cum, A, B)
if (!fIsRestrictedSamplingRequired) {
for (std::size_t id=0; id<ndata; ++id) {
fin >> aTable.fW[id];
}
for (std::size_t id=0; id<ndata; ++id) {
fin >> aTable.fI[id];
}
}
for (std::size_t id=0; id<ndata; ++id) {
fin >> aTable.fCum[id];
}
for (std::size_t id=0; id<ndata; ++id) {
fin >> aTable.fA[id];
}
for (std::size_t id=0; id<ndata; ++id) {
fin >> aTable.fB[id];
}
}
fSamplingTables[iz] = sTables;
}
// samples cos(theta) i.e. cosine of the polar angle of scattering in elastic
// interaction (Coulomb scattering) of the projectile (e- or e+ depending on
// fIsElectron) with kinetic energy of exp('lekin'), target atom with atomic
// muber of 'iz'. See the 'SampleCosineThetaRestricted' for obtain samples on
// a restricted inteval.
G4double
G4eDPWAElasticDCS::SampleCosineTheta(std::size_t iz, G4double lekin, G4double r1,
G4double r2, G4double r3) {
lekin = std::max(gTheEnergies[0], std::min(gTheEnergies[gNumEnergies-1], lekin));
// determine the discrete ekin sampling table to be used:
// - statistical interpolation (i.e. linear) on log energy scale
const G4double rem = (lekin-gLogMinEkin)*gInvDelLogEkin;
const std::size_t k = (std::size_t)rem;
const std::size_t iekin = (r1 < rem-k) ? k+1 : k;
// sample the mu(t)=0.5(1-cos(t))
const double mu = SampleMu(iz, iekin, r2, r3);
return std::max(-1.0, std::min(1.0, 1.0-2.0*mu));
}
// samples cos(theta) i.e. cosine of the polar angle of scattering in elastic
// interaction (Coulomb scattering) of the projectile (e- or e+ depending on
// fIsElectron) with kinetic energy of exp('lekin'), target atom with atomic
// muber of 'iz'.
// The cosine theta will be in the [costMin, costMax] interval where costMin
// corresponds to a maximum allowed polar scattering angle thetaMax while
// costMin corresponds to minimum allowed polar scatterin angle thetaMin.
// See the 'SampleCosineTheta' for obtain samples on the entire [-1,1] range.
G4double
G4eDPWAElasticDCS::SampleCosineThetaRestricted(std::size_t iz, G4double lekin,
G4double r1, G4double r2,
G4double costMax, G4double costMin) {
// costMin corresponds to mu-max while costMax to mu-min: mu(t)=0.5[1-cos(t)]
lekin = std::max(gTheEnergies[0], std::min(gTheEnergies[gNumEnergies-1], lekin));
// determine the discrete ekin sampling table to be used:
// - statistical interpolation (i.e. linear) on log energy scale
const G4double rem = (lekin-gLogMinEkin)*gInvDelLogEkin;
const std::size_t k = (size_t)rem;
const std::size_t iekin = (r1 < rem-k) ? k : k+1;
// sample the mu(t)=0.5(1-cos(t))
const G4double mu = SampleMu(iz, iekin, r2, 0.5*(1.0-costMax), 0.5*(1.0-costMin));
return std::max(-1.0, std::min(1.0, 1.0-2.0*mu));
}
G4double
G4eDPWAElasticDCS::SampleMu(std::size_t izet, std::size_t ie, G4double r1, G4double r2) {
OneSamplingTable& rtn = (*fSamplingTables[izet])[ie];
// get the lower index of the bin by using the alias part
const G4double rest = r1 * (rtn.fN - 1);
std::size_t indxl = (std::size_t)rest;
const G4double dum0 = rest - indxl;
if (rtn.fW[indxl] < dum0) indxl = rtn.fI[indxl];
// sample value within the selected bin by using ratin based numerical inversion
const G4double delta = rtn.fCum[indxl + 1] - rtn.fCum[indxl];
const G4double aval = r2 * delta;
const G4double dum1 = (1.0 + rtn.fA[indxl] + rtn.fB[indxl]) * delta * aval;
const G4double dum2 = delta * delta + rtn.fA[indxl] * delta * aval + rtn.fB[indxl] * aval * aval;
const std::vector<G4double>& theUVect = (fIsElectron && ie<gIndxEnergyLim) ? gTheU1 : gTheU2;
const G4double u = theUVect[indxl] + dum1 / dum2 * (theUVect[indxl + 1] - theUVect[indxl]);
// transform back u to mu
return rtn.fScreenParA*u/(rtn.fScreenParA+1.0-u);
}
G4double
G4eDPWAElasticDCS::FindCumValue(G4double u, const OneSamplingTable& stable,
const std::vector<G4double>& uvect) {
const std::size_t iLow = std::distance( uvect.begin(), std::upper_bound(uvect.begin(), uvect.end(), u) )-1;
const G4double tau = (u-uvect[iLow])/(uvect[iLow+1]-uvect[iLow]); // Note: I could store 1/(fX[iLow+1]-fX[iLow])
const G4double dum0 = (1.0+stable.fA[iLow]*(1.0-tau)+stable.fB[iLow]);
const G4double dum1 = 2.0*stable.fB[iLow]*tau;
const G4double dum2 = 1.0 - std::sqrt(std::max(0.0, 1.0-2.0*dum1*tau/(dum0*dum0)));
return std::min(stable.fCum[iLow+1], std::max(stable.fCum[iLow], stable.fCum[iLow]+dum0*dum2*(stable.fCum[iLow+1]-stable.fCum[iLow])/dum1 ));
}
// muMin and muMax : no checks on these
G4double G4eDPWAElasticDCS::SampleMu(std::size_t izet, std::size_t ie, G4double r1,
G4double muMin, G4double muMax) {
const OneSamplingTable& rtn = (*fSamplingTables[izet])[ie];
const G4double theA = rtn.fScreenParA;
//
const std::vector<G4double>& theUVect = (fIsElectron && ie<gIndxEnergyLim) ? gTheU1 : gTheU2;
const G4double xiMin = (muMin > 0.0) ? FindCumValue((theA+1.0)*muMin/(theA+muMin), rtn, theUVect) : 0.0;
const G4double xiMax = (muMax < 1.0) ? FindCumValue((theA+1.0)*muMax/(theA+muMax), rtn, theUVect) : 1.0;
//
const G4double xi = xiMin+r1*(xiMax-xiMin); // a smaple within the range
const std::size_t iLow = std::distance( rtn.fCum.begin(), std::upper_bound(rtn.fCum.begin(), rtn.fCum.end(), xi) )-1;
const G4double delta = rtn.fCum[iLow + 1] - rtn.fCum[iLow];
const G4double aval = xi - rtn.fCum[iLow];
const G4double dum1 = (1.0 + rtn.fA[iLow] + rtn.fB[iLow]) * delta * aval;
const G4double dum2 = delta * delta + rtn.fA[iLow] * delta * aval + rtn.fB[iLow] * aval * aval;
const G4double u = theUVect[iLow] + dum1 / dum2 * (theUVect[iLow + 1] - theUVect[iLow]);
return theA*u/(theA+1.0-u);
}
// set the DCS data directory path
const G4String& G4eDPWAElasticDCS::FindDirectoryPath() {
// check environment variable
if (gDataDirectory.empty()) {
const char* path = std::getenv("G4LEDATA");
if (path) {
std::ostringstream ost;
ost << path << "/dpwa/";
gDataDirectory = ost.str();
} else {
G4Exception("G4eDPWAElasticDCS::FindDirectoryPath()","em0006",
FatalException,
"Environment variable G4LEDATA not defined");
}
}
return gDataDirectory;
}
// uncompress one data file into the input string stream
void
G4eDPWAElasticDCS::ReadCompressedFile(G4String fname, std::istringstream &iss) {
G4String *dataString = nullptr;
G4String compfilename(fname+".z");
// create input stream with binary mode operation and positioning at the end of the file
std::ifstream in(compfilename, std::ios::binary | std::ios::ate);
if (in.good()) {
// get current position in the stream (was set to the end)
G4int fileSize = in.tellg();
// set current position being the beginning of the stream
in.seekg(0,std::ios::beg);
// create (zlib) byte buffer for the data
Bytef *compdata = new Bytef[fileSize];
while(in) {
in.read((char*)compdata, fileSize);
}
// create (zlib) byte buffer for the uncompressed data
uLongf complen = (uLongf)(fileSize*4);
Bytef *uncompdata = new Bytef[complen];
while (Z_OK!=uncompress(uncompdata, &complen, compdata, fileSize)) {
// increase uncompressed byte buffer
delete[] uncompdata;
complen *= 2;
uncompdata = new Bytef[complen];
}
// delete the compressed data buffer
delete [] compdata;
// create a string from the uncompressed data (will be deallocated by the caller)
dataString = new G4String((char*)uncompdata, (long)complen);
// delete the uncompressed data buffer
delete [] uncompdata;
} else {
G4String msg =
" Problem while trying to read " + fname + " data file.\n"+
" G4LEDATA version should be G4EMLOW7.12 or later.\n";
G4Exception("G4eDPWAElasticDCS::ReadCompressedFile","em0006",
FatalException,msg.c_str());
return;
}
// create the input string stream from the data string
if (dataString) {
iss.str(*dataString);
in.close();
delete dataString;
}
}
G4double
G4eDPWAElasticDCS::ComputeScatteringPowerCorrection(const G4MaterialCutsCouple *matcut,
G4double ekin) {
const G4int imc = matcut->GetIndex();
G4double corFactor = 1.0;
if (!(fSCPCPerMatCuts[imc]->fIsUse) || ekin<=fSCPCPerMatCuts[imc]->fPrCut) {
return corFactor;
}
// get the scattering power correction factor
const G4double lekin = G4Log(ekin);
G4double remaining = (lekin-fSCPCPerMatCuts[imc]->fLEmin)*fSCPCPerMatCuts[imc]->fILDel;
G4int lindx = (G4int)remaining;
remaining -= lindx;
G4int imax = fSCPCPerMatCuts[imc]->fVSCPC.size()-1;
if (lindx>=imax) {
corFactor = fSCPCPerMatCuts[imc]->fVSCPC[imax];
} else {
corFactor = fSCPCPerMatCuts[imc]->fVSCPC[lindx] + remaining*(fSCPCPerMatCuts[imc]->fVSCPC[lindx+1]-fSCPCPerMatCuts[imc]->fVSCPC[lindx]);
}
return corFactor;
}
void G4eDPWAElasticDCS::InitSCPCorrection(G4double lowEnergyLimit,
G4double highEnergyLimit) {
// get the material-cuts table
G4ProductionCutsTable *thePCTable = G4ProductionCutsTable::GetProductionCutsTable();
std::size_t numMatCuts = thePCTable->GetTableSize();
// clear container if any
for (std::size_t imc=0; imc<fSCPCPerMatCuts.size(); ++imc) {
if (fSCPCPerMatCuts[imc]) {
fSCPCPerMatCuts[imc]->fVSCPC.clear();
delete fSCPCPerMatCuts[imc];
fSCPCPerMatCuts[imc] = nullptr;
}
}
//
// set size of the container and create the corresponding data structures
fSCPCPerMatCuts.resize(numMatCuts,nullptr);
// loop over the material-cuts and create scattering power correction data structure for each
for (std::size_t imc=0; imc<numMatCuts; ++imc) {
const G4MaterialCutsCouple *matCut = thePCTable->GetMaterialCutsCouple(imc);
const G4Material* mat = matCut->GetMaterial();
// get e- production cut in the current material-cuts in energy
const G4double ecut = (*(thePCTable->GetEnergyCutsVector(idxG4ElectronCut)))[matCut->GetIndex()];
const G4double limit = fIsElectron ? 2.0*ecut : ecut;
const G4double min = std::max(limit,lowEnergyLimit);
const G4double max = highEnergyLimit;
if (min>=max) {
fSCPCPerMatCuts[imc] = new SCPCorrection();
fSCPCPerMatCuts[imc]->fIsUse = false;
fSCPCPerMatCuts[imc]->fPrCut = min;
continue;
}
G4int numEbins = fNumSPCEbinPerDec*G4lrint(std::log10(max/min));
numEbins = std::max(numEbins,3);
const G4double lmin = G4Log(min);
const G4double ldel = G4Log(max/min)/(numEbins-1.0);
fSCPCPerMatCuts[imc] = new SCPCorrection();
fSCPCPerMatCuts[imc]->fVSCPC.resize(numEbins,1.0);
fSCPCPerMatCuts[imc]->fIsUse = true;
fSCPCPerMatCuts[imc]->fPrCut = min;
fSCPCPerMatCuts[imc]->fLEmin = lmin;
fSCPCPerMatCuts[imc]->fILDel = 1./ldel;
// compute Moliere material dependet parameetrs
G4double moliereBc = 0.0;
G4double moliereXc2 = 0.0;
ComputeMParams(mat, moliereBc, moliereXc2);
// compute scattering power correction over the enrgy grid
for (G4int ie=0; ie<numEbins; ++ie) {
const G4double ekin = G4Exp(lmin+ie*ldel);
G4double scpCorr = 1.0;
// compute correction factor: I.Kawrakow, Med.Phys.24,505-517(1997)(Eqs(32-37)
if (ie>0) {
const G4double tau = ekin/CLHEP::electron_mass_c2;
const G4double tauCut = ecut/CLHEP::electron_mass_c2;
// Moliere's screening parameter
const G4double A = moliereXc2/(4.0*tau*(tau+2.)*moliereBc);
const G4double gr = (1.+2.*A)*G4Log(1.+1./A)-2.;
const G4double dum0 = (tau+2.)/(tau+1.);
const G4double dum1 = tau+1.;
G4double gm = G4Log(0.5*tau/tauCut) + (1.+dum0*dum0)*G4Log(2.*(tau-tauCut+2.)/(tau+4.))
- 0.25*(tau+2.)*( tau+2.+2.*(2.*tau+1.)/(dum1*dum1))*
G4Log((tau+4.)*(tau-tauCut)/tau/(tau-tauCut+2.))
+ 0.5*(tau-2*tauCut)*(tau+2.)*(1./(tau-tauCut)-1./(dum1*dum1));
if (gm<gr) {
gm = gm/gr;
} else {
gm = 1.;
}
const G4double z0 = matCut->GetMaterial()->GetIonisation()->GetZeffective();
scpCorr = 1.-gm*z0/(z0*(z0+1.));
}
fSCPCPerMatCuts[imc]->fVSCPC[ie] = scpCorr;
}
}
}
// compute material dependent Moliere MSC parameters at initialisation
void G4eDPWAElasticDCS::ComputeMParams(const G4Material* mat, G4double& theBc,
G4double& theXc2) {
const G4double const1 = 7821.6; // [cm2/g]
const G4double const2 = 0.1569; // [cm2 MeV2 / g]
const G4double finstrc2 = 5.325135453E-5; // fine-structure const. square
// G4double xi = 1.0;
const G4ElementVector* theElemVect = mat->GetElementVector();
const G4int numelems = mat->GetNumberOfElements();
//
const G4double* theNbAtomsPerVolVect = mat->GetVecNbOfAtomsPerVolume();
G4double theTotNbAtomsPerVol = mat->GetTotNbOfAtomsPerVolume();
//
G4double zs = 0.0;
G4double zx = 0.0;
G4double ze = 0.0;
G4double sa = 0.0;
//
for(G4int ielem = 0; ielem < numelems; ielem++) {
const G4double zet = (*theElemVect)[ielem]->GetZ();
const G4double iwa = (*theElemVect)[ielem]->GetN();
const G4double ipz = theNbAtomsPerVolVect[ielem]/theTotNbAtomsPerVol;
const G4double dum = ipz*zet*(zet+1.0);
zs += dum;
ze += dum*(-2.0/3.0)*G4Log(zet);
zx += dum*G4Log(1.0+3.34*finstrc2*zet*zet);
sa += ipz*iwa;
}
const G4double density = mat->GetDensity()*CLHEP::cm3/CLHEP::g; // [g/cm3]
//
theBc = const1*density*zs/sa*G4Exp(ze/zs)/G4Exp(zx/zs); //[1/cm]
theXc2 = const2*density*zs/sa; // [MeV2/cm]
// change to Geant4 internal units of 1/length and energ2/length
theBc *= 1.0/CLHEP::cm;
theXc2 *= CLHEP::MeV*CLHEP::MeV/CLHEP::cm;
}
@@ -241,7 +241,8 @@ G4eplusTo3GammaOKVIModel::SampleSecondaries(vector<G4DynamicParticle*>* vdp,
{
G4double posiKinEnergy = dp->GetKineticEnergy();
G4DynamicParticle *aGamma1, *aGamma2, *aGamma3;
G4DynamicParticle *aGamma1, *aGamma2;
G4DynamicParticle* aGamma3 = nullptr;
G4double border;
if(posiKinEnergy < 500*MeV) {
@@ -376,7 +377,7 @@ G4eplusTo3GammaOKVIModel::SampleSecondaries(vector<G4DynamicParticle*>* vdp,
vdp->push_back(aGamma1);
vdp->push_back(aGamma2);
vdp->push_back(aGamma3);
if(aGamma3 != nullptr) { vdp->push_back(aGamma3); }
// kill primary positron
fParticleChange->SetProposedKineticEnergy(0.0);