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
@@ -28,133 +28,124 @@
// File: G4BetaMinusDecay.cc //
// Author: D.H. Wright (SLAC) //
// Date: 25 October 2014 //
// Modifications: //
// 23.08.2023 V.Ivanchenko make it thread safe using static utility //
// //
////////////////////////////////////////////////////////////////////////////////
#include "G4BetaMinusDecay.hh"
#include "G4BetaDecayCorrections.hh"
#include "G4ThreeVector.hh"
#include "G4LorentzVector.hh"
#include "G4DynamicParticle.hh"
#include "G4DecayProducts.hh"
#include "G4PhysicalConstants.hh"
#include "G4SystemOfUnits.hh"
#include "G4Electron.hh"
#include "G4AntiNeutrinoE.hh"
#include "G4RandomDirection.hh"
#include "G4BetaSpectrumSampler.hh"
#include <iostream>
#include <iomanip>
namespace {
const G4double eMass = CLHEP::electron_mass_c2;
}
G4BetaMinusDecay::G4BetaMinusDecay(const G4ParticleDefinition* theParentNucleus,
const G4double& branch, const G4double& e0,
const G4double& excitationE,
const G4Ions::G4FloatLevelBase& flb,
const G4BetaDecayType& betaType)
: G4NuclearDecay("beta- decay", BetaMinus, excitationE, flb), endpointEnergy(e0)
: G4NuclearDecay("beta- decay", BetaMinus, excitationE, flb),
maxEnergy(e0),
estep(maxEnergy/(G4double)(npti - 1))
{
SetParent(theParentNucleus); // Store name of parent nucleus, delete G4MT_parent
SetBR(branch);
SetNumberOfDaughters(3);
G4IonTable* theIonTable =
(G4IonTable*)(G4ParticleTable::GetParticleTable()->GetIonTable());
fPrimaryIon = theParentNucleus;
fLepton = G4Electron::Electron();
fNeutrino = G4AntiNeutrinoE::AntiNeutrinoE();
G4IonTable* theIonTable = G4ParticleTable::GetParticleTable()->GetIonTable();
G4int daughterZ = theParentNucleus->GetAtomicNumber() + 1;
G4int daughterA = theParentNucleus->GetAtomicMass();
SetDaughter(0, theIonTable->GetIon(daughterZ, daughterA, excitationE, flb) );
SetDaughter(1, "e-");
SetDaughter(2, "anti_nu_e");
fResIon = const_cast<const G4ParticleDefinition*>(theIonTable->GetIon(daughterZ, daughterA,
excitationE, flb));
parentMass = theParentNucleus->GetPDGMass();
resMass = fResIon->GetPDGMass();
SetUpBetaSpectrumSampler(daughterZ, daughterA, betaType);
}
SetDaughter(0, fResIon);
SetDaughter(1, fLepton);
SetDaughter(2, fNeutrino);
G4BetaMinusDecay::~G4BetaMinusDecay()
{
delete betaSampler;
}
G4DecayProducts* G4BetaMinusDecay::DecayIt(G4double)
{
// Fill G4MT_parent with theParentNucleus (stored by SetParent in ctor)
CheckAndFillParent();
// Fill G4MT_daughters with e-, nu and residual nucleus (stored by SetDaughter)
CheckAndFillDaughters();
}
G4double parentMass = G4MT_parent->GetPDGMass();
G4double eMass = G4MT_daughters[1]->GetPDGMass();
G4double nucleusMass = G4MT_daughters[0]->GetPDGMass();
G4DecayProducts* G4BetaMinusDecay::DecayIt(G4double)
{
// Set up final state
// parentParticle is set at rest here because boost with correct momentum
// is done later
G4DynamicParticle parentParticle(G4MT_parent, G4ThreeVector(0,0,0), 0.0);
G4DecayProducts* products = new G4DecayProducts(parentParticle);
G4DynamicParticle prim(fPrimaryIon, G4ThreeVector(0,0,1), 0.0);
G4DecayProducts* products = new G4DecayProducts(prim);
if (betaSampler) {
// Electron, neutrino and daughter nucleus energies
G4double eKE = endpointEnergy*betaSampler->shoot();
G4double eMomentum = std::sqrt(eKE*(eKE + 2.*eMass) );
// Generate positron isotropic in angle, with energy from stored spectrum
const G4double eKE = eMass*G4BetaSpectrumSampler::shoot(npti, cdf, estep);
G4double cosThetaENu = 2.*G4UniformRand() - 1.;
G4double eTE = eMass + eKE;
G4double nuEnergy = ((endpointEnergy - eKE)*(parentMass + nucleusMass - eTE)
- eMomentum*eMomentum)/(parentMass - eTE + eMomentum*cosThetaENu)/2.;
G4double eMomentum = std::sqrt(eKE*(eKE + 2.*eMass));
G4ThreeVector dir = G4RandomDirection();
G4DynamicParticle* dp = new G4DynamicParticle(fLepton, dir, eKE);
products->PushProducts(dp);
/*
G4cout << "G4BetaPlusDecay::DecayIt: " << fPrimaryIon->GetParticleName()
<< " -> " << fResIon->GetParticleName() << " + " << fLepton->GetParticleName()
<< " + " << fNeutrino->GetParticleName() << " Ee(MeV)=" << eKE
<< G4endl;
*/
// Fill G4MT_parent with theParentNucleus (stored by SetParent in ctor)
// Electron 4-vector, isotropic angular distribution
G4double cosTheta = 2.*G4UniformRand() - 1.0;
G4double sinTheta = std::sqrt(1.0 - cosTheta*cosTheta);
// 4-momentum of residual ion and neutrino
G4LorentzVector lv(-eMomentum*dir.x(), -eMomentum*dir.y(), -eMomentum*dir.z(),
parentMass - eKE - eMass);
G4double phi = twopi*G4UniformRand()*rad;
G4double sinPhi = std::sin(phi);
G4double cosPhi = std::cos(phi);
G4double edel = std::max(lv.e() - resMass, 0.0);
if (edel > CLHEP::eV) {
G4ParticleMomentum eDirection(sinTheta*cosPhi, sinTheta*sinPhi, cosTheta);
G4DynamicParticle* dynamicElectron
= new G4DynamicParticle(G4MT_daughters[1], eDirection*eMomentum);
products->PushProducts(dynamicElectron);
// centrum of mass system
G4double M = lv.mag();
// Neutrino 4-vector
G4double sinThetaENu = std::sqrt(1.0 - cosThetaENu*cosThetaENu);
phi = twopi*G4UniformRand()*rad;
G4double sinPhiNu = std::sin(phi);
G4double cosPhiNu = std::cos(phi);
// neutrino
G4double eNu = 0.5*(M - resMass*resMass/M);
G4LorentzVector lvnu(eNu*G4RandomDirection(), eNu);
lvnu.boost(lv.boostVector());
dir = lvnu.vect().unit();
dp = new G4DynamicParticle(fNeutrino, dir, lvnu.e());
products->PushProducts(dp);
G4ParticleMomentum nuDirection;
nuDirection.setX(sinThetaENu*cosPhiNu*cosTheta*cosPhi -
sinThetaENu*sinPhiNu*sinPhi + cosThetaENu*sinTheta*cosPhi);
nuDirection.setY(sinThetaENu*cosPhiNu*cosTheta*sinPhi +
sinThetaENu*sinPhiNu*cosPhi + cosThetaENu*sinTheta*sinPhi);
nuDirection.setZ(-sinThetaENu*cosPhiNu*sinTheta + cosThetaENu*cosTheta);
G4DynamicParticle* dynamicNeutrino
= new G4DynamicParticle(G4MT_daughters[2], nuDirection*nuEnergy);
products->PushProducts(dynamicNeutrino);
// Daughter nucleus 4-vector
// p_D = - p_e - p_nu
G4DynamicParticle* dynamicDaughter =
new G4DynamicParticle(G4MT_daughters[0],
-eDirection*eMomentum - nuDirection*nuEnergy);
products->PushProducts(dynamicDaughter);
// residual
lv -= lvnu;
dir = lv.vect().unit();
G4double ekin = std::max(lv.e() - resMass, 0.0);
dp = new G4DynamicParticle(fResIon, dir, ekin);
products->PushProducts(dp);
} else {
// electron energy below threshold -> no decay
G4DynamicParticle* noDecay =
new G4DynamicParticle(G4MT_parent, G4ThreeVector(0,0,0), 0.0);
products->PushProducts(noDecay);
// neglecting relativistic kinematic and giving all energy to neutrino
dp = new G4DynamicParticle(fNeutrino, G4RandomDirection(), edel);
products->PushProducts(dp);
dp = new G4DynamicParticle(fResIon, G4ThreeVector(0.0,0.0,1.0), 0.0);
products->PushProducts(dp);
}
// Check energy conservation against Q value, not nuclear masses
/*
G4int nProd = products->entries();
G4DynamicParticle* temp = 0;
G4double Esum = 0.0;
for (G4int i = 0; i < nProd; i++) {
temp = products->operator[](i);
// G4cout << temp->GetParticleDefinition()->GetParticleName() << " has "
// << temp->GetTotalEnergy()/keV << " keV " << G4endl;
Esum += temp->GetKineticEnergy();
}
G4double eCons = (endpointEnergy - Esum)/keV;
if (std::abs(eCons) > 0.001) G4cout << " Beta- check: eCons = " << eCons << G4endl;
*/
return products;
}
@@ -164,42 +155,41 @@ G4BetaMinusDecay::SetUpBetaSpectrumSampler(const G4int& daughterZ,
const G4int& daughterA,
const G4BetaDecayType& betaType)
{
G4double e0 = endpointEnergy/CLHEP::electron_mass_c2;
G4BetaDecayCorrections corrections(daughterZ, daughterA);
betaSampler = 0;
cdf[0] = 0.0;
if (e0 > 0) {
// Array to store spectrum pdf
G4int npti = 101;
G4double* pdf = new G4double[npti];
// Check for cases in which Q < 2Me (e.g. z67.a162)
if (maxEnergy > 0.) {
G4BetaDecayCorrections corrections(daughterZ, daughterA);
// Fill array to store cumulative spectrum
G4double ex;
G4double p; // Electron momentum in units of electron mass
G4double f; // Spectral shape function
for (G4int i = 0; i < npti; i++) {
ex = e0*std::max(1.e-6, G4double(i)/G4double(npti-1) );
p = std::sqrt(ex*(ex+2.) );
f = p*(1. + ex)*(e0 - ex)*(e0 - ex);
G4double p; // Positron momentum in units of electron mass
G4double f; // Spectral shape function
G4double sum = 0.0;
for (G4int i = 1; i < npti; ++i) {
ex = estep*i;
p = std::sqrt(ex*(ex + 2.));
f = p*(1. + ex)*(maxEnergy - ex)*(maxEnergy - ex);
// Apply Fermi factor to get allowed shape
f *= corrections.FermiFunction(1. + ex);
// Apply shape factor for forbidden transitions
f *= corrections.ShapeFactor(betaType, p, e0-ex);
pdf[i] = f;
f *= corrections.ShapeFactor(betaType, p, maxEnergy - ex);
sum += f;
cdf[i] = sum;
}
betaSampler = new G4BetaSpectrumSampler(pdf, npti, e0);
delete[] pdf;
} else {
for (G4int i = 1; i < npti; ++i) { cdf[i] = 0.0; }
}
}
void G4BetaMinusDecay::DumpNuclearInfo()
{
G4cout << " G4BetaMinusDecay for parent nucleus " << GetParentName() << G4endl;
G4cout << " decays to " << GetDaughterName(0) << " , " << GetDaughterName(1)
<< " and " << GetDaughterName(2) << " with branching ratio " << GetBR()
<< "% and endpoint energy " << endpointEnergy/keV << " keV " << G4endl;
G4cout << " G4BetaMinusDecay " << fPrimaryIon->GetParticleName()
<< " -> " << fResIon->GetParticleName() << " + " << fLepton->GetParticleName()
<< " + " << fNeutrino->GetParticleName() << " Eemax(MeV)="
<< maxEnergy*eMass << " BR=" << GetBR() << "%" << G4endl;
}
@@ -28,6 +28,8 @@
// File: G4BetaPlusDecay.cc //
// Author: D.H. Wright (SLAC) //
// Date: 14 November 2014 //
// Modifications: //
// 23.08.2023 V.Ivanchenko //
// //
////////////////////////////////////////////////////////////////////////////////
@@ -35,124 +37,115 @@
#include "G4BetaDecayCorrections.hh"
#include "G4IonTable.hh"
#include "G4ThreeVector.hh"
#include "G4LorentzVector.hh"
#include "G4DynamicParticle.hh"
#include "G4DecayProducts.hh"
#include "G4PhysicalConstants.hh"
#include "G4SystemOfUnits.hh"
#include "G4Positron.hh"
#include "G4NeutrinoE.hh"
#include "G4RandomDirection.hh"
#include "G4BetaSpectrumSampler.hh"
#include <iostream>
#include <iomanip>
namespace {
const G4double eMass = CLHEP::electron_mass_c2;
}
G4BetaPlusDecay::G4BetaPlusDecay(const G4ParticleDefinition* theParentNucleus,
const G4double& branch, const G4double& e0,
const G4double& excitationE,
const G4Ions::G4FloatLevelBase& flb,
const G4BetaDecayType& betaType)
: G4NuclearDecay("beta+ decay", BetaPlus, excitationE, flb),
endpointEnergy(e0 - 2.*CLHEP::electron_mass_c2)
maxEnergy((e0 - 2*eMass)/eMass),
estep(maxEnergy/(G4double)(npti - 1))
{
SetParent(theParentNucleus); // Store name of parent nucleus, delete G4MT_parent
SetBR(branch);
SetNumberOfDaughters(3);
G4IonTable* theIonTable =
(G4IonTable*)(G4ParticleTable::GetParticleTable()->GetIonTable());
fPrimaryIon = theParentNucleus;
fLepton = G4Positron::Positron();
fNeutrino = G4NeutrinoE::NeutrinoE();
G4IonTable* theIonTable = G4ParticleTable::GetParticleTable()->GetIonTable();
G4int daughterZ = theParentNucleus->GetAtomicNumber() - 1;
G4int daughterA = theParentNucleus->GetAtomicMass();
SetDaughter(0, theIonTable->GetIon(daughterZ, daughterA, excitationE, flb) );
fResIon = const_cast<const G4ParticleDefinition*>(theIonTable->GetIon(daughterZ, daughterA,
excitationE, flb));
parentMass = theParentNucleus->GetPDGMass();
resMass = fResIon->GetPDGMass();
SetUpBetaSpectrumSampler(daughterZ, daughterA, betaType);
SetDaughter(1, "e+");
SetDaughter(2, "nu_e");
}
SetDaughter(0, fResIon);
SetDaughter(1, fLepton);
SetDaughter(2, fNeutrino);
G4BetaPlusDecay::~G4BetaPlusDecay()
{
delete betaSampler;
}
G4DecayProducts* G4BetaPlusDecay::DecayIt(G4double)
{
// Fill G4MT_parent with theParentNucleus (stored by SetParent in ctor)
CheckAndFillParent();
// Fill G4MT_daughters with e-, nu and residual nucleus (stored by SetDaughter)
CheckAndFillDaughters();
}
G4double parentMass = G4MT_parent->GetPDGMass();
G4double eMass = G4MT_daughters[1]->GetPDGMass();
G4double nucleusMass = G4MT_daughters[0]->GetPDGMass();
G4DecayProducts* G4BetaPlusDecay::DecayIt(G4double)
{
// Set up final state
// parentParticle is set at rest here because boost with correct momentum
// is done later
G4DynamicParticle parentParticle(G4MT_parent, G4ThreeVector(0,0,0), 0.0);
G4DecayProducts* products = new G4DecayProducts(parentParticle);
G4DynamicParticle prim(fPrimaryIon, G4ThreeVector(0,0,1), 0.0);
G4DecayProducts* products = new G4DecayProducts(prim);
if (betaSampler) {
// Generate positron isotropic in angle, with energy from stored spectrum
G4double eKE = endpointEnergy*betaSampler->shoot();
G4double eMomentum = std::sqrt(eKE*(eKE + 2.*eMass) );
// Generate positron isotropic in angle, with energy from stored spectrum
const G4double eKE = eMass*G4BetaSpectrumSampler::shoot(npti, cdf, estep);
G4double cosTheta = 2.*G4UniformRand() - 1.0;
G4double sinTheta = std::sqrt(1.0 - cosTheta*cosTheta);
G4double phi = twopi*G4UniformRand()*rad;
G4double sinPhi = std::sin(phi);
G4double cosPhi = std::cos(phi);
G4double eMomentum = std::sqrt(eKE*(eKE + 2.*eMass));
G4ThreeVector dir = G4RandomDirection();
G4DynamicParticle* dp = new G4DynamicParticle(fLepton, dir, eKE);
products->PushProducts(dp);
/*
G4cout << "G4BetaPlusDecay::DecayIt: " << fPrimaryIon->GetParticleName()
<< " -> " << fResIon->GetParticleName() << " + " << fLepton->GetParticleName()
<< " + " << fNeutrino->GetParticleName() << " Ee(MeV)=" << eKE
<< G4endl;
*/
// 4-momentum of residual ion and neutrino
G4LorentzVector lv(-eMomentum*dir.x(), -eMomentum*dir.y(), -eMomentum*dir.z(),
parentMass - eKE - eMass);
G4ParticleMomentum eDirection(sinTheta*cosPhi, sinTheta*sinPhi, cosTheta);
G4DynamicParticle* dynamicPositron
= new G4DynamicParticle(G4MT_daughters[1], eDirection*eMomentum);
products->PushProducts(dynamicPositron);
G4double edel = std::max(lv.e() - resMass, 0.0);
if (edel > CLHEP::eV) {
// Generate neutrino with angle relative to positron, and energy from
// energy-momentum conservation using endpoint energy of reaction
G4double cosThetaENu = 2.*G4UniformRand() - 1.;
G4double eTE = eMass + eKE;
G4double nuEnergy = ((endpointEnergy - eKE)*(parentMass + nucleusMass - eTE)
- eMomentum*eMomentum)/(parentMass - eTE + eMomentum*cosThetaENu)/2.;
// centrum of mass system
G4double M = lv.mag();
G4double sinThetaENu = std::sqrt(1.0 - cosThetaENu*cosThetaENu);
phi = twopi*G4UniformRand()*rad;
G4double sinPhiNu = std::sin(phi);
G4double cosPhiNu = std::cos(phi);
// neutrino
G4double eNu = 0.5*(M - resMass*resMass/M);
G4LorentzVector lvnu(eNu*G4RandomDirection(), eNu);
lvnu.boost(lv.boostVector());
dir = lvnu.vect().unit();
dp = new G4DynamicParticle(fNeutrino, dir, lvnu.e());
products->PushProducts(dp);
G4ParticleMomentum nuDirection;
nuDirection.setX(sinThetaENu*cosPhiNu*cosTheta*cosPhi -
sinThetaENu*sinPhiNu*sinPhi + cosThetaENu*sinTheta*cosPhi);
nuDirection.setY(sinThetaENu*cosPhiNu*cosTheta*sinPhi +
sinThetaENu*sinPhiNu*cosPhi + cosThetaENu*sinTheta*sinPhi);
nuDirection.setZ(-sinThetaENu*cosPhiNu*sinTheta + cosThetaENu*cosTheta);
G4DynamicParticle* dynamicNeutrino
= new G4DynamicParticle(G4MT_daughters[2], nuDirection*nuEnergy);
products->PushProducts(dynamicNeutrino);
// Generate daughter nucleus from sum of positron and neutrino 4-vectors:
// p_D = - p_e - p_nu
G4DynamicParticle* dynamicDaughter =
new G4DynamicParticle(G4MT_daughters[0],
-eDirection*eMomentum - nuDirection*nuEnergy);
products->PushProducts(dynamicDaughter);
// residual
lv -= lvnu;
dir = lv.vect().unit();
G4double ekin = std::max(lv.e() - resMass, 0.0);
dp = new G4DynamicParticle(fResIon, dir, ekin);
products->PushProducts(dp);
} else {
// positron energy below threshold -> no decay
G4DynamicParticle* noDecay =
new G4DynamicParticle(G4MT_parent, G4ThreeVector(0,0,0), 0.0);
products->PushProducts(noDecay);
// neglecting relativistic kinematic and giving all energy to neutrino
dp = new G4DynamicParticle(fNeutrino, G4RandomDirection(), edel);
products->PushProducts(dp);
dp = new G4DynamicParticle(fResIon, G4ThreeVector(0.0,0.0,1.0), 0.0);
products->PushProducts(dp);
}
// Check energy conservation against endpoint value, not nuclear masses
/*
G4int nProd = products->entries();
G4DynamicParticle* temp = 0;
G4double Esum = 0.0;
for (G4int i = 0; i < nProd; i++) {
temp = products->operator[](i);
Esum += temp->GetKineticEnergy();
}
G4double eCons = (endpointEnergy - Esum)/keV;
if (eCons > 0.001) G4cout << " Beta+ check: eCons (keV) = " << eCons << G4endl;
*/
return products;
}
@@ -162,44 +155,37 @@ G4BetaPlusDecay::SetUpBetaSpectrumSampler(const G4int& daughterZ,
const G4int& daughterA,
const G4BetaDecayType& betaType)
{
G4double e0 = endpointEnergy/CLHEP::electron_mass_c2;
G4BetaDecayCorrections corrections(-daughterZ, daughterA);
betaSampler = 0;
// Check for cases in which Q < 2Me (e.g. z67.a162)
if (e0 > 0.) {
// Array to store spectrum pdf
G4int npti = 101;
G4double* pdf = new G4double[npti];
if (maxEnergy > 0.) {
G4BetaDecayCorrections corrections(-daughterZ, daughterA);
// Fill array to store cumulative spectrum
G4double ex;
G4double p; // Positron momentum in units of electron mass
G4double f; // Spectral shape function
for (G4int i = 0; i < npti; i++) {
ex = e0*std::max(1.e-6, G4double(i)/G4double(npti-1) );
p = std::sqrt(ex*(ex+2.) );
f = p*(1. + ex)*(e0 - ex)*(e0 - ex);
G4double sum = 0.0;
for (G4int i = 0; i < npti; ++i) {
ex = (0 == i) ? maxEnergy*1.e-6 : estep*i;
p = std::sqrt(ex*(ex + 2.));
f = p*(1. + ex)*(maxEnergy - ex)*(maxEnergy - ex);
// Apply Fermi factor to get allowed shape
f *= corrections.FermiFunction(1. + ex);
// Apply shape factor for forbidden transitions
f *= corrections.ShapeFactor(betaType, p, e0-ex);
pdf[i] = f;
f *= corrections.ShapeFactor(betaType, p, maxEnergy - ex);
sum += f;
cdf[i] = sum;
}
betaSampler = new G4BetaSpectrumSampler(pdf, npti, e0);
delete[] pdf;
} else {
for (G4int i = 0; i < npti; ++i) { cdf[i] = 0.0; }
}
}
void G4BetaPlusDecay::DumpNuclearInfo()
{
G4cout << " G4BetaPlusDecay for parent nucleus " << GetParentName() << G4endl;
G4cout << " decays to " << GetDaughterName(0) << " , " << GetDaughterName(1)
<< " and " << GetDaughterName(2) << " with branching ratio " << GetBR()
<< "% and endpoint energy " << endpointEnergy/keV << " keV " << G4endl;
G4cout << " G4BetaPlusDecay " << fPrimaryIon->GetParticleName()
<< " -> " << fResIon->GetParticleName() << " + " << fLepton->GetParticleName()
<< " + " << fNeutrino->GetParticleName() << " Eemax(MeV)="
<< maxEnergy*eMass << " BR=" << GetBR() << "%" << G4endl;
}
@@ -35,64 +35,18 @@
////////////////////////////////////////////////////////////////////////////////
#include "G4BetaSpectrumSampler.hh"
#include "Randomize.hh"
G4BetaSpectrumSampler::
G4BetaSpectrumSampler(const G4double* aPDF, G4int pdfSize, G4double e)
G4double G4BetaSpectrumSampler::shoot(const G4int npoints, const G4double* aCDF,
const G4double estep)
{
pdf.resize(pdfSize);
nBins = pdfSize-1;
cdf.resize(nBins);
eEnd = e;
lowerBinEdge = 0;
upperBinEdge = 1;
for (G4int i = 0; i < pdfSize; i++) pdf[i] = aPDF[i];
// Caclulate binwise CDF using trapezoidal integration
G4double sum = pdf[0]/2.;
for (G4int i = 1; i < pdfSize; i++) {
sum += pdf[i];
cdf[i-1] = sum - pdf[i]/2.;
}
}
G4double G4BetaSpectrumSampler::shoot()
{
G4double rand = G4UniformRand()*cdf[nBins-1];
G4int ibin = 0;
while (rand > cdf[ibin]) ibin++;
G4double x = nBins;
if (ibin < nBins) {
lowerBinEdge = ibin;
upperBinEdge = ibin+1;
x = sampleSlopedLine();
}
return x/nBins;
}
G4double G4BetaSpectrumSampler::sampleSlopedLine()
{
G4double x;
G4double rand = G4UniformRand();
ylower = pdf[lowerBinEdge];
yupper = pdf[upperBinEdge];
if (std::abs(2.*(yupper - ylower)/(yupper + ylower) ) < 1.E-6) {
// Slope is near zero, sample flat
x = lowerBinEdge + rand*(upperBinEdge - lowerBinEdge);
} else {
// Sample incline
x = (yupper*lowerBinEdge - ylower*upperBinEdge +
std::sqrt(ylower*ylower + rand*(yupper*yupper - ylower*ylower) ) )
/(yupper - ylower);
}
G4double prob = aCDF[npoints - 1]*G4UniformRand();
G4int i = 0;
for (; i<npoints; ++i) { if (prob <= aCDF[i]) { break; } }
const G4double p1 = (i > 0) ? aCDF[i - 1] : aCDF[0];
const G4double p2 = aCDF[i];
const G4double delta = p2 - p1;
const G4double x = (delta > 0.0) ? estep*i - estep*(p2 - prob)/delta : estep*i;
return x;
}
@@ -47,57 +47,54 @@
#include "G4PhysicalConstants.hh"
G4ITDecay::G4ITDecay(G4PhotonEvaporation* ptr)
: G4NuclearDecay("IT decay", IT, 0.0, noFloat), photonEvaporation(ptr)
{}
G4ITDecay::G4ITDecay(const G4ParticleDefinition* theParentNucleus,
const G4double& branch, const G4double& Qvalue,
const G4double& excitationE, G4PhotonEvaporation* aPhotoEvap)
: G4NuclearDecay("IT decay", IT, excitationE, noFloat), transitionQ(Qvalue),
applyARM(true), photonEvaporation(aPhotoEvap)
const G4double& branch, const G4double&,
const G4double& excitationE)
: G4NuclearDecay("IT decay", IT, excitationE, noFloat)
{
SetParent(theParentNucleus); // Store name of parent nucleus, delete G4MT_parent
SetBR(branch);
parentZ = theParentNucleus->GetAtomicNumber();
parentA = theParentNucleus->GetAtomicMass();
SetNumberOfDaughters(1);
G4IonTable* theIonTable =
(G4IonTable*)(G4ParticleTable::GetParticleTable()->GetIonTable());
SetDaughter(0, theIonTable->GetIon(parentZ, parentA, excitationE, noFloat) );
SetDaughter(0, theParentNucleus);
SetupDecay(theParentNucleus);
}
G4ITDecay::~G4ITDecay()
{}
void G4ITDecay::SetupDecay(const G4ParticleDefinition* theParentNucleus)
{
theParent = theParentNucleus;
parentZ = theParentNucleus->GetAtomicNumber();
parentA = theParentNucleus->GetAtomicMass();
}
G4DecayProducts* G4ITDecay::DecayIt(G4double)
{
// Fill G4MT_parent with theParentNucleus (stored by SetParent in ctor)
CheckAndFillParent();
// Set up final state
// parentParticle is set at rest here because boost with correct momentum
// is done later
G4LorentzVector atRest(G4MT_parent->GetPDGMass(),
G4ThreeVector(0.,0.,0.) );
G4DynamicParticle parentParticle(G4MT_parent, atRest);
G4LorentzVector atRest(theParent->GetPDGMass(), G4ThreeVector(0.,0.,0.) );
G4DynamicParticle parentParticle(theParent, atRest);
G4DecayProducts* products = new G4DecayProducts(parentParticle);
// Let G4PhotonEvaporation do the decay
G4Fragment parentNucleus(parentA, parentZ, atRest);
// one emission, parent nucleaus become less excited
G4Fragment* eOrGamma = photonEvaporation->EmittedFragment(&parentNucleus);
// Modified nuclide is returned as dynDaughter
G4IonTable* theIonTable =
(G4IonTable*)(G4ParticleTable::GetParticleTable()->GetIonTable() );
auto theIonTable = G4ParticleTable::GetParticleTable()->GetIonTable();
G4ParticleDefinition* daughterIon =
theIonTable->GetIon(parentZ, parentA, parentNucleus.GetExcitationEnergy(),
G4Ions::FloatLevelBase(parentNucleus.GetFloatingLevelNumber()));
G4DynamicParticle* dynDaughter = new G4DynamicParticle(daughterIon,
parentNucleus.GetMomentum());
if (eOrGamma) {
if (nullptr != eOrGamma) {
G4DynamicParticle* eOrGammaDyn =
new G4DynamicParticle(eOrGamma->GetParticleDefinition(),
eOrGamma->GetMomentum() );
@@ -180,9 +177,8 @@ G4DecayProducts* G4ITDecay::DecayIt(G4double)
void G4ITDecay::DumpNuclearInfo()
{
G4cout << " G4ITDecay for parent nucleus " << GetParentName() << G4endl;
G4cout << " decays to " << GetDaughterName(0)
<< " + gammas (or electrons), with branching ratio " << GetBR()
<< "% and Q value " << transitionQ << G4endl;
if (theParent != nullptr) {
G4cout << " G4ITDecay for parent nucleus " << theParent->GetParticleName() << G4endl;
}
}
@@ -39,10 +39,11 @@ G4NuclearDecay::G4NuclearDecay(const G4String& channelName,
const G4double& excitationE,
const G4Ions::G4FloatLevelBase& flb)
: G4VDecayChannel(channelName), theMode(aMode), daughterEx(excitationE),
floatingLevel(flb), halflifeThreshold(nanosecond)
{}
G4NuclearDecay::~G4NuclearDecay()
floatingLevel(flb)
{}
G4bool G4NuclearDecay::IsOKWithParentMass(G4double)
{
return true;
}
@@ -90,8 +90,9 @@
using namespace CLHEP;
G4Radioactivation::G4Radioactivation(const G4String& processName)
: G4RadioactiveDecay(processName)
G4Radioactivation::G4Radioactivation(const G4String& processName,
const G4double timeThresholdForRadioactiveDecays)
: G4RadioactiveDecay(processName, timeThresholdForRadioactiveDecays)
{
#ifdef G4VERBOSE
if (GetVerboseLevel() > 1) {
@@ -100,7 +101,6 @@ G4Radioactivation::G4Radioactivation(const G4String& processName)
}
#endif
// DHW SetProcessSubType(fRadioactiveDecay);
theRadioactivationMessenger = new G4RadioactivationMessenger(this);
// Apply default values.
@@ -123,7 +123,6 @@ G4Radioactivation::G4Radioactivation(const G4String& processName)
halflifethreshold = 1000.*nanosecond;
}
void G4Radioactivation::ProcessDescription(std::ostream& outFile) const
{
outFile << "The G4Radioactivation process performs radioactive decay of\n"
@@ -141,21 +140,6 @@ G4Radioactivation::~G4Radioactivation()
delete theRadioactivationMessenger;
}
G4DecayTable* G4Radioactivation::GetDecayTable1(const G4ParticleDefinition* aNucleus)
{
G4String key = aNucleus->GetParticleName();
DecayTableMap::iterator table_ptr = dkmap->find(key);
G4DecayTable* theDecayTable = 0;
if (table_ptr == dkmap->end() ) { // If table not there,
theDecayTable = LoadDecayTable(*aNucleus); // load from file and
if(theDecayTable) (*dkmap)[key] = theDecayTable; // store in library
} else {
theDecayTable = table_ptr->second;
}
return theDecayTable;
}
G4bool
G4Radioactivation::IsRateTableReady(const G4ParticleDefinition& aParticle)
{
@@ -168,7 +152,6 @@ G4Radioactivation::IsRateTableReady(const G4ParticleDefinition& aParticle)
return false;
}
void
G4Radioactivation::GetChainsFromParent(const G4ParticleDefinition& aParticle)
{
@@ -212,16 +195,16 @@ G4Radioactivation::ConvolveSourceTimeProfile(const G4double t, const G4double ta
"HAD_RDM_100", JustWarning, "While loop count exceeded");
break;
}
nbin++;
++nbin;
}
nbin--;
--nbin;
}
// Use expm1 wherever possible to avoid large cancellation errors in
// 1 - exp(x) for small x
G4double earg = 0.0;
if (nbin > 0) {
for (G4int i = 0; i < nbin; i++) {
for (G4int i = 0; i < nbin; ++i) {
earg = (SBin[i+1] - SBin[i])/tau;
if (earg < 100.) {
convolvedTime += SProfile[i] * std::exp((SBin[i] - t)/tau) *
@@ -267,7 +250,7 @@ G4double G4Radioactivation::GetDecayTime()
while (DProfile[i] < rand) { /* Loop checking, 01.09.2015, D.Wright */
// Entries in DProfile[i] are all between 0 and 1 and arranged in inreaseing order
// Comparison with rand chooses which time bin to sample
i++;
++i;
loop++;
if (loop > 100000) {
G4Exception("G4Radioactivation::GetDecayTime()", "HAD_RDM_100",
@@ -292,7 +275,7 @@ G4int G4Radioactivation::GetDecayTimeBin(const G4double aDecayTime)
G4int loop = 0;
while (aDecayTime > DBin[i] ) { /* Loop checking, 01.09.2015, D.Wright */
i++;
++i;
loop++;
if (loop > 100000) {
G4Exception("G4Radioactivation::GetDecayTimeBin()", "HAD_RDM_100",
@@ -311,21 +294,21 @@ G4int G4Radioactivation::GetDecayTimeBin(const G4double aDecayTime)
////////////////////////////////////////////////////////////////////////////////
G4double G4Radioactivation::GetMeanLifeTime(const G4Track& theTrack,
G4ForceCondition*)
G4ForceCondition* fc)
{
// For variance reduction time is set to 0 so as to force the particle
// to decay immediately.
// In analogue mode it returns the particle's mean-life.
G4double meanlife = 0.;
if (AnalogueMC) meanlife = G4RadioactiveDecay::GetMeanLifeTime(theTrack, 0);
if (AnalogueMC) meanlife = G4RadioactiveDecay::GetMeanLifeTime(theTrack, fc);
return meanlife;
}
void
G4Radioactivation::SetDecayRate(G4int theZ, G4int theA, G4double theE,
G4int theG, std::vector<G4double> theCoefficients,
std::vector<G4double> theTaos)
G4int theG, std::vector<G4double>& theCoefficients,
std::vector<G4double>& theTaos)
// Why not make this a method of G4RadioactiveDecayRate? (e.g. SetParameters)
{
//fill the decay rate vector
@@ -360,10 +343,11 @@ CalculateChainsFromParent(const G4ParticleDefinition& theParentNucleus)
// According to Eq. 4.26 the first coefficient (A_1:1) is -1
Acoeffs.push_back(-1.);
G4int A = ((const G4Ions*)(&theParentNucleus))->GetAtomicMass();
G4int Z = ((const G4Ions*)(&theParentNucleus))->GetAtomicNumber();
G4double E = ((const G4Ions*)(&theParentNucleus))->GetExcitationEnergy();
G4double tao = theParentNucleus.GetPDGLifeTime();
const G4Ions* ion = static_cast<const G4Ions*>(&theParentNucleus);
G4int A = ion->GetAtomicMass();
G4int Z = ion->GetAtomicNumber();
G4double E = ion->GetExcitationEnergy();
G4double tao = ion->GetPDGLifeTime();
if (tao < 0.) tao = 1e-100;
taos.push_back(tao);
G4int nEntry = 0;
@@ -374,11 +358,10 @@ CalculateChainsFromParent(const G4ParticleDefinition& theParentNucleus)
// store the decay rate in decay rate vector
theDecayRateVector.push_back(ratesToDaughter);
nEntry++;
++nEntry;
// Now start treating the secondary generations.
G4bool stable = false;
// G4int i;
G4int j;
G4VDecayChannel* theChannel = 0;
G4NuclearDecay* theNuclearDecayChannel = 0;
@@ -415,8 +398,7 @@ CalculateChainsFromParent(const G4ParticleDefinition& theParentNucleus)
const G4int nMode = G4RadioactiveDecayModeSize;
G4double brs[nMode];
//
theIonTable =
(G4IonTable*)(G4ParticleTable::GetParticleTable()->GetIonTable());
theIonTable = G4ParticleTable::GetParticleTable()->GetIonTable();
G4int loop = 0;
while (!stable) { /* Loop checking, 01.09.2015, D.Wright */
@@ -427,7 +409,7 @@ CalculateChainsFromParent(const G4ParticleDefinition& theParentNucleus)
break;
}
nGeneration++;
for (j = nS; j < nT; j++) {
for (j = nS; j < nT; ++j) {
// First time through, get data for parent nuclide
ZP = theDecayRateVector[j].GetZ();
AP = theDecayRateVector[j].GetA();
@@ -441,11 +423,12 @@ CalculateChainsFromParent(const G4ParticleDefinition& theParentNucleus)
<< G4endl;
}
// G4cout << " Taus = " << G4endl;
// for (G4int ii = 0; ii < TP.size(); ii++) G4cout << TP[ii] << ", " ;
// for (G4int ii = 0; ii < TP.size(); ++ii) G4cout << TP[ii] << ", " ;
// G4cout << G4endl;
aParentNucleus = theIonTable->GetIon(ZP,AP,EP);
parentDecayTable = GetDecayTable1(aParentNucleus);
parentDecayTable = GetDecayTable(aParentNucleus);
if (nullptr == parentDecayTable) { continue; }
G4DecayTable* summedDecayTable = new G4DecayTable();
// This instance of G4DecayTable is for accumulating BRs and decay
@@ -457,15 +440,15 @@ CalculateChainsFromParent(const G4ParticleDefinition& theParentNucleus)
// ratio will not be included in the above sums.
// This instance is not used to perform actual decays.
for (G4int k = 0; k < nMode; k++) brs[k] = 0.0;
for (G4int k = 0; k < nMode; ++k) brs[k] = 0.0;
// Go through the decay table and sum all channels having the same decay mode
for (G4int i = 0; i < parentDecayTable->entries(); i++) {
for (G4int i = 0; i < parentDecayTable->entries(); ++i) {
theChannel = parentDecayTable->GetDecayChannel(i);
theNuclearDecayChannel = static_cast<G4NuclearDecay*>(theChannel);
theDecayMode = theNuclearDecayChannel->GetDecayMode();
daughterExcitation = theNuclearDecayChannel->GetDaughterExcitation();
theDaughterNucleus = theNuclearDecayChannel->GetDaughterNucleus() ;
theDaughterNucleus = theNuclearDecayChannel->GetDaughterNucleus();
AD = ((const G4Ions*)(theDaughterNucleus))->GetAtomicMass();
ZD = ((const G4Ions*)(theDaughterNucleus))->GetAtomicNumber();
const G4LevelManager* levelManager =
@@ -497,13 +480,12 @@ CalculateChainsFromParent(const G4ParticleDefinition& theParentNucleus)
brs[BetaPlus] = brs[BetaPlus]+brs[KshellEC]+brs[LshellEC]+brs[MshellEC]+brs[NshellEC]; // Combine beta+ and EC
brs[KshellEC] = brs[LshellEC] = brs[MshellEC] = brs[NshellEC] = 0.0;
for (G4int i = 0; i < nMode; i++) { // loop over decay modes
for (G4int i = 0; i < nMode; ++i) { // loop over decay modes
if (brs[i] > 0.) {
switch (i) {
case IT:
// Decay mode is isomeric transition
theITChannel = new G4ITDecay(aParentNucleus, brs[IT], 0.0, 0.0,
photonEvaporation);
theITChannel = new G4ITDecay(aParentNucleus, brs[IT], 0.0, 0.0);
summedDecayTable->Insert(theITChannel);
break;
@@ -591,7 +573,7 @@ CalculateChainsFromParent(const G4ParticleDefinition& theParentNucleus)
// loop over all branches in summedDecayTable
//
for (G4int i = 0; i < summedDecayTable->entries(); i++){
for (G4int i = 0; i < summedDecayTable->entries(); ++i){
theChannel = summedDecayTable->GetDecayChannel(i);
theNuclearDecayChannel = static_cast<G4NuclearDecay*>(theChannel);
theBR = theChannel->GetBR();
@@ -608,8 +590,8 @@ CalculateChainsFromParent(const G4ParticleDefinition& theParentNucleus)
if (IsApplicable(*theDaughterNucleus) && theBR > 0.0 &&
aParentNucleus != theDaughterNucleus) {
// need to make sure daughter has decay table
parentDecayTable = GetDecayTable1(theDaughterNucleus);
if (parentDecayTable->entries() ) {
parentDecayTable = GetDecayTable(theDaughterNucleus);
if (nullptr != parentDecayTable && parentDecayTable->entries() > 0) {
A = ((const G4Ions*)(theDaughterNucleus))->GetAtomicMass();
Z = ((const G4Ions*)(theDaughterNucleus))->GetAtomicNumber();
E = ((const G4Ions*)(theDaughterNucleus))->GetExcitationEnergy();
@@ -622,7 +604,7 @@ CalculateChainsFromParent(const G4ParticleDefinition& theParentNucleus)
taos = TP; // load lifetimes of all previous generations
std::size_t k;
//check that TaoPlus differs from other taos from at least 1.e5 relative difference
//for (k = 0; k < TP.size(); k++){
//for (k = 0; k < TP.size(); ++k){
//if (std::abs((TaoPlus-TP[k])/TP[k])<1.e-5 ) TaoPlus=1.00001*TP[k];
//}
taos.push_back(TaoPlus); // add daughter lifetime to list
@@ -633,7 +615,7 @@ CalculateChainsFromParent(const G4ParticleDefinition& theParentNucleus)
Acoeffs.clear();
long double ta1,ta2;
ta2 = (long double)TaoPlus;
for (k = 0; k < RP.size(); k++){
for (k = 0; k < RP.size(); ++k){
ta1 = (long double)TP[k]; // loop over lifetimes of all previous generations
if (ta1 == ta2) {
theRate = 1.e100;
@@ -650,7 +632,7 @@ CalculateChainsFromParent(const G4ParticleDefinition& theParentNucleus)
theRate = 0.;
long double aRate, aRate1;
aRate1 = 0.L;
for (k = 0; k < RP.size(); k++){
for (k = 0; k < RP.size(); ++k){
ta1 = (long double)TP[k];
if (ta1 == ta2 ) {
aRate = 1.e100;
@@ -683,7 +665,7 @@ CalculateChainsFromParent(const G4ParticleDefinition& theParentNucleus)
// fill the first part of the decay rate table
// which is the name of the original particle (isotope)
chainsFromParent.SetIonName(theParentNucleus.GetParticleName());
chainsFromParent.SetIonName(theParentNucleus.GetParticleName());
// now fill the decay table with the newly completed decay rate vector
chainsFromParent.SetItsRates(theDecayRateVector);
@@ -699,7 +681,7 @@ CalculateChainsFromParent(const G4ParticleDefinition& theParentNucleus)
// //
////////////////////////////////////////////////////////////////////////////////
void G4Radioactivation::SetSourceTimeProfile(G4String filename)
void G4Radioactivation::SetSourceTimeProfile(const G4String& filename)
{
std::ifstream infile ( filename, std::ios::in );
if (!infile) {
@@ -748,7 +730,7 @@ void G4Radioactivation::SetSourceTimeProfile(G4String filename)
// //
////////////////////////////////////////////////////////////////////////////////
void G4Radioactivation::SetDecayBias(G4String filename)
void G4Radioactivation::SetDecayBias(const G4String& filename)
{
std::ifstream infile(filename, std::ios::in);
if (!infile) G4Exception("G4Radioactivation::SetDecayBias()", "HAD_RDM_001",
@@ -786,8 +768,8 @@ void G4Radioactivation::SetDecayBias(G4String filename)
}
}
}
for ( i = 1; i<= NDecayBin; i++) DProfile[i] += DProfile[i-1]; // Cumulative flux vs i
for ( i = 0; i<= NDecayBin; i++) DProfile[i] /= DProfile[NDecayBin];
for ( i = 1; i<= NDecayBin; ++i) DProfile[i] += DProfile[i-1]; // Cumulative flux vs i
for ( i = 0; i<= NDecayBin; ++i) DProfile[i] /= DProfile[NDecayBin];
// Normalize so entries increase from 0 to 1
// converted to accumulated probabilities
@@ -861,9 +843,9 @@ G4Radioactivation::DecayIt(const G4Track& theTrack, const G4Step&)
return &fParticleChangeForRadDecay;
}
G4DecayTable* theDecayTable = GetDecayTable1(theParticleDef);
G4DecayTable* theDecayTable = GetDecayTable(theParticleDef);
if (theDecayTable == 0 || theDecayTable->entries() == 0) {
if (theDecayTable == nullptr || theDecayTable->entries() == 0) {
// No data in the decay table. Set particle change parameters
// to indicate this.
#ifdef G4VERBOSE
@@ -886,7 +868,7 @@ G4Radioactivation::DecayIt(const G4Track& theTrack, const G4Step&)
} else {
// Data found. Try to decay nucleus
if (AnalogueMC) {
G4RadioactiveDecay::DecayAnalog(theTrack);
G4RadioactiveDecay::DecayAnalog(theTrack, theDecayTable);
} else {
// Proceed with decay using variance reduction
@@ -901,7 +883,8 @@ G4Radioactivation::DecayIt(const G4Track& theTrack, const G4Step&)
G4ParticleDefinition* parentNucleus;
// Get decay chains for the given nuclide
if (!IsRateTableReady(*theParticleDef)) CalculateChainsFromParent(*theParticleDef);
if (!IsRateTableReady(*theParticleDef))
CalculateChainsFromParent(*theParticleDef);
GetChainsFromParent(*theParticleDef);
// Declare some of the variables required in the implementation
@@ -927,7 +910,7 @@ G4Radioactivation::DecayIt(const G4Track& theTrack, const G4Step&)
ptime.clear();
// Now apply the nucleus splitting
for (G4int n = 0; n < NSplit; n++) {
for (G4int n = 0; n < NSplit; ++n) {
// Get the decay time following the decay probability function
// supplied by user
G4double theDecayTime = GetDecayTime();
@@ -949,7 +932,7 @@ G4Radioactivation::DecayIt(const G4Track& theTrack, const G4Step&)
// loop over all the possible secondaries of the nucleus
// the first one is itself.
for (i = 0; i < theDecayRateVector.size(); i++) {
for (i = 0; i < theDecayRateVector.size(); ++i) {
PZ = theDecayRateVector[i].GetZ();
PA = theDecayRateVector[i].GetA();
PE = theDecayRateVector[i].GetE();
@@ -1002,7 +985,7 @@ G4Radioactivation::DecayIt(const G4Track& theTrack, const G4Step&)
// For each nuclide, calculate all the decay chains which can reach
// the parent nuclide
decayRate = 0.L;
for (G4int j = 0; j < G4int(PT.size() ); j++) {
for (G4int j = 0; j < G4int(PT.size() ); ++j) {
taotime = ConvolveSourceTimeProfile(theDecayTime,PT[j]);
decayRate -= PR[j] * (long double)taotime; // PRs are Acoeffs, taotime is inverse time
// Eq.4.23 of of the TN
@@ -1039,26 +1022,28 @@ G4Radioactivation::DecayIt(const G4Track& theTrack, const G4Step&)
// Create a temprary products buffer.
// Its contents to be transfered to the products at the end of the loop
G4DecayProducts* tempprods = 0;
G4DecayProducts* tempprods = nullptr;
// Decide whether to apply branching ratio bias or not
if (BRBias) {
G4DecayTable* decayTable = GetDecayTable1(parentNucleus);
ndecaych = G4int(decayTable->entries()*G4UniformRand());
G4VDecayChannel* theDecayChannel = decayTable->GetDecayChannel(ndecaych);
G4DecayTable* decayTable = GetDecayTable(parentNucleus);
G4VDecayChannel* theDecayChannel = nullptr;
if (nullptr != decayTable) {
ndecaych = G4int(decayTable->entries()*G4UniformRand());
theDecayChannel = decayTable->GetDecayChannel(ndecaych);
}
if (theDecayChannel == 0) {
if (theDecayChannel == nullptr) {
// Decay channel not found.
if (GetVerboseLevel() > 0) {
G4cout << " G4RadioactiveDecay::DoIt : cannot determine decay channel ";
G4cout << " for this nucleus; decay as if no biasing active. ";
G4cout << G4endl;
decayTable ->DumpInfo();
if (nullptr != decayTable) { decayTable ->DumpInfo(); }
}
tempprods = DoDecay(*parentNucleus); // DHW 6 Dec 2010 - do decay as if no biasing
// to avoid deref of temppprods = 0
// DHW 6 Dec 2010 - do decay as if no biasing to avoid deref of temppprods
tempprods = DoDecay(*parentNucleus, theDecayTable);
} else {
// A decay channel has been identified, so execute the DecayIt.
G4double tempmass = parentNucleus->GetPDGMass();
@@ -1066,7 +1051,7 @@ G4Radioactivation::DecayIt(const G4Track& theTrack, const G4Step&)
weight *= (theDecayChannel->GetBR())*(decayTable->entries());
}
} else {
tempprods = DoDecay(*parentNucleus);
tempprods = DoDecay(*parentNucleus, theDecayTable);
}
// save the secondaries for buffers
@@ -1131,8 +1116,8 @@ G4Radioactivation::AddDeexcitationSpectrumForBiasMode(G4ParticleDefinition* apar
G4ITDecay* anITChannel = 0;
while (life_time < halflifethreshold && elevel > 0.) {
anITChannel = new G4ITDecay(apartDef, 100., elevel, elevel, photonEvaporation);
G4DecayProducts* pevap_products = anITChannel->DecayIt(0.);
decayIT->SetupDecay(apartDef);
G4DecayProducts* pevap_products = decayIT->DecayIt(0.);
G4int nb_pevapSecondaries = pevap_products->entries();
G4DynamicParticle* a_pevap_secondary = 0;
@@ -86,92 +86,108 @@
#include "G4PhotonEvaporation.hh"
#include "G4HadronicParameters.hh"
#include "G4PhysicsModelCatalog.hh"
#include "G4AutoLock.hh"
#include <vector>
#include <sstream>
#include <algorithm>
#include <fstream>
#include "G4PhysicsModelCatalog.hh"
using namespace CLHEP;
const G4double G4RadioactiveDecay::levelTolerance = 10.0*eV;
const G4double G4RadioactiveDecay::levelTolerance = 10.0*CLHEP::eV;
const G4ThreeVector G4RadioactiveDecay::origin(0.,0.,0.);
#ifdef G4MULTITHREADED
#include "G4AutoLock.hh"
G4Mutex G4RadioactiveDecay::radioactiveDecayMutex = G4MUTEX_INITIALIZER;
DecayTableMap* G4RadioactiveDecay::master_dkmap = 0;
DecayTableMap* G4RadioactiveDecay::master_dkmap = nullptr;
std::map<G4int, G4String>* G4RadioactiveDecay::theUserRDataFiles = nullptr;
G4String G4RadioactiveDecay::dirPath = "";
G4int& G4RadioactiveDecay::NumberOfInstances()
namespace
{
static G4int numberOfInstances = 0;
return numberOfInstances;
G4Mutex radioactiveDecayMutex = G4MUTEX_INITIALIZER;
}
#endif
G4RadioactiveDecay::G4RadioactiveDecay(const G4String& processName)
: G4VRestDiscreteProcess(processName, fDecay), isInitialised(false),
forceDecayDirection(0.,0.,0.), forceDecayHalfAngle(0.*deg), dirPath(""),
verboseLevel(1),
fThresholdForVeryLongDecayTime( 1.0e+27*CLHEP::nanosecond ) // Longer than twice Universe's age
G4RadioactiveDecay::G4RadioactiveDecay(const G4String& processName,
const G4double timeThreshold)
: G4VRestDiscreteProcess(processName, fDecay),
fThresholdForVeryLongDecayTime( 1.0*CLHEP::year )
{
#ifdef G4VERBOSE
if (GetVerboseLevel() > 1) {
G4cout << "G4RadioactiveDecay constructor: processName = " << processName
<< G4endl;
}
#endif
SetProcessSubType(fRadioactiveDecay);
theRadioactiveDecayMessenger = new G4RadioactiveDecayMessenger(this);
pParticleChange = &fParticleChangeForRadDecay;
// Check data directory
if (dirPath.empty()) {
const char* path_var = G4FindDataDir("G4RADIOACTIVEDATA");
if (nullptr == path_var) {
G4Exception("G4RadioactiveDecay()", "HAD_RDM_200", FatalException,
"Environment variable G4RADIOACTIVEDATA is not set");
} else {
dirPath = path_var; // convert to string
std::ostringstream os;
os << dirPath << "/z1.a3"; // used as a dummy
std::ifstream testFile;
testFile.open(os.str() );
if ( !testFile.is_open() )
G4Exception("G4RadioactiveDecay()","HAD_RDM_201",FatalException,
"Environment variable G4RADIOACTIVEDATA is set, but does not point to correct directory");
}
}
// Set up photon evaporation for use in G4ITDecay
photonEvaporation = new G4PhotonEvaporation();
photonEvaporation->RDMForced(true);
photonEvaporation->SetICM(true);
// DHW G4DeexPrecoParameters* deex = G4NuclearLevelData::GetInstance()->GetParameters();
// DHW deex->SetCorrelatedGamma(true);
// Check data directory
const char* path_var = G4FindDataDir("G4RADIOACTIVEDATA");
if (!path_var) {
G4Exception("G4RadioactiveDecay()","HAD_RDM_200",FatalException,
"Environment variable G4RADIOACTIVEDATA is not set");
} else {
dirPath = path_var; // convert to string
std::ostringstream os;
os << dirPath << "/z1.a3"; // used as a dummy
std::ifstream testFile;
testFile.open(os.str() );
if (!testFile.is_open() )
G4Exception("G4RadioactiveDecay()","HAD_RDM_201",FatalException,
"Environment variable G4RADIOACTIVEDATA is set, but does not point to correct directory");
}
// Reset the list of user defined data files
theUserRadioactiveDataFiles.clear();
decayIT = new G4ITDecay(photonEvaporation);
// Instantiate the map of decay tables
#ifdef G4MULTITHREADED
G4AutoLock lk(&G4RadioactiveDecay::radioactiveDecayMutex);
NumberOfInstances()++;
if(!master_dkmap) master_dkmap = new DecayTableMap;
#endif
dkmap = new DecayTableMap;
// Apply default values
applyARM = true;
if (nullptr == master_dkmap) {
master_dkmap = new DecayTableMap();
}
if (nullptr == theUserRDataFiles) {
theUserRDataFiles = new std::map<G4int, G4String>;
}
// RDM applies to all logical volumes by default
isAllVolumesMode = true;
SelectAllVolumes();
G4HadronicProcessStore::Instance()->RegisterExtraProcess(this);
// The time threshold for radioactive decays can be set in 3 ways:
// 1. Via C++ interface: G4HadronicParameters::Instance()->SetTimeThresholdForRadioactiveDecay(value)
// 2. Via the second parameter of the G4RadioactiveDecay constructor
// 3. Via UI command: /process/had/rdm/thresholdForVeryLongDecayTime value
// If both 1. and 2. are specified (at the moment when the G4RadioactiveDecay constructor is called),
// then we take the larger value, to be conservative.
// If, later on (after invoking the G4RadioactiveDecay constructor) 3. is specified,
// then this value is used (and the eventual values 1. and/or 2. are ignored).
G4double timeThresholdBis = G4HadronicParameters::Instance()->GetTimeThresholdForRadioactiveDecay();
if ( timeThreshold > 0.0 || timeThresholdBis > 0.0 ) {
if ( timeThreshold > timeThresholdBis ) timeThresholdBis = timeThreshold;
fThresholdForVeryLongDecayTime = timeThresholdBis;
}
}
G4VParticleChange* G4RadioactiveDecay::AtRestDoIt(const G4Track& theTrack,
const G4Step& theStep)
{
return DecayIt(theTrack, theStep);
}
G4VParticleChange* G4RadioactiveDecay::PostStepDoIt(const G4Track& theTrack,
const G4Step& theStep)
{
return DecayIt(theTrack, theStep);
}
void G4RadioactiveDecay::ProcessDescription(std::ostream& outFile) const
{
outFile << "The radioactive decay process (G4RadioactiveDecay) handles the\n"
@@ -186,59 +202,68 @@ G4RadioactiveDecay::~G4RadioactiveDecay()
{
delete theRadioactiveDecayMessenger;
delete photonEvaporation;
for (DecayTableMap::iterator i = dkmap->begin(); i != dkmap->end(); i++) {
delete i->second;
}
dkmap->clear();
delete dkmap;
#ifdef G4MULTITHREADED
G4AutoLock lk(&G4RadioactiveDecay::radioactiveDecayMutex);
--NumberOfInstances();
if(NumberOfInstances()==0)
{
for (DecayTableMap::iterator i = master_dkmap->begin(); i != master_dkmap->end(); i++) {
delete i->second;
delete decayIT;
if (nullptr != master_dkmap) {
G4AutoLock lk(&radioactiveDecayMutex);
if (nullptr != master_dkmap) {
for (auto const & i : *master_dkmap) {
delete i.second;
}
master_dkmap->clear();
delete master_dkmap;
master_dkmap = nullptr;
}
master_dkmap->clear();
delete master_dkmap;
delete theUserRDataFiles;
theUserRDataFiles = nullptr;
lk.unlock();
}
#endif
}
G4bool G4RadioactiveDecay::IsApplicable(const G4ParticleDefinition& aParticle)
{
const G4String& pname = aParticle.GetParticleName();
if (pname == "GenericIon" || pname == "triton") { return true; }
// All particles other than G4Ions, are rejected by default
if (((const G4Ions*)(&aParticle))->GetExcitationEnergy() > 0.) {return true;}
if (aParticle.GetParticleName() == "GenericIon") {
return true;
} else if (!(aParticle.GetParticleType() == "nucleus")
|| aParticle.GetPDGLifeTime() < 0. ) {
const G4Ions* p = dynamic_cast<const G4Ions*>(&aParticle);
if (nullptr == p) { return false; }
// excited isomere may decay via gamma evaporation
if (p->GetExcitationEnergy() > 0.0) { return true; }
// Check on life time
G4double lifeTime = p->GetPDGLifeTime();
if (lifeTime < 0.0 || lifeTime > fThresholdForVeryLongDecayTime) {
return false;
}
// Determine whether the nuclide falls into the correct A and Z range
G4int A = ((const G4Ions*) (&aParticle))->GetAtomicMass();
G4int Z = ((const G4Ions*) (&aParticle))->GetAtomicNumber();
G4int A = p->GetAtomicMass();
G4int Z = p->GetAtomicNumber();
if (A > theNucleusLimits.GetAMax() || A < theNucleusLimits.GetAMin() ||
Z > theNucleusLimits.GetZMax() || Z < theNucleusLimits.GetZMin()) {
return false;
}
if (A > theNucleusLimits.GetAMax() || A < theNucleusLimits.GetAMin())
{return false;}
else if (Z > theNucleusLimits.GetZMax() || Z < theNucleusLimits.GetZMin())
{return false;}
return true;
}
G4DecayTable* G4RadioactiveDecay::GetDecayTable(const G4ParticleDefinition* aNucleus)
{
G4String key = aNucleus->GetParticleName();
DecayTableMap::iterator table_ptr = dkmap->find(key);
auto ptr = master_dkmap->find(key);
G4DecayTable* theDecayTable = 0;
if (table_ptr == dkmap->end() ) { // If table not there,
theDecayTable = LoadDecayTable(*aNucleus); // load from file and
if(theDecayTable) (*dkmap)[key] = theDecayTable; // store in library
G4DecayTable* theDecayTable = nullptr;
if ( ptr == master_dkmap->end() ) {
// Load new file if table not there
const G4Ions* ion = dynamic_cast<const G4Ions*>(aNucleus);
if (nullptr != ion) {
theDecayTable = LoadDecayTable(ion);
}
} else {
theDecayTable = table_ptr->second;
theDecayTable = ptr->second;
}
return theDecayTable;
}
@@ -346,35 +371,42 @@ void G4RadioactiveDecay::DeselectAllVolumes()
////////////////////////////////////////////////////////////////////////////////
G4double G4RadioactiveDecay::GetMeanLifeTime(const G4Track& theTrack,
G4ForceCondition*)
G4ForceCondition*)
{
G4double meanlife = 0.;
const G4DynamicParticle* theParticle = theTrack.GetDynamicParticle();
const G4ParticleDefinition* theParticleDef = theParticle->GetDefinition();
G4double meanlife = DBL_MAX;
const G4ParticleDefinition* theParticleDef = theTrack.GetParticleDefinition();
if (!IsApplicable(*theParticleDef)) { return meanlife; }
G4double theLife = theParticleDef->GetPDGLifeTime();
#ifdef G4VERBOSE
if (GetVerboseLevel() > 2) {
G4cout << "G4RadioactiveDecay::GetMeanLifeTime() " << G4endl;
G4cout << "KineticEnergy: " << theParticle->GetKineticEnergy()/GeV
<< " GeV, Mass: " << theParticle->GetMass()/GeV
<< " GeV, Life time: " << theLife/ns << " ns " << G4endl;
G4cout << "G4RadioactiveDecay::GetMeanLifeTime() for "
<< theParticleDef->GetParticleName() << G4endl;
G4cout << "KineticEnergy(GeV)=" << theTrack.GetKineticEnergy()/CLHEP::GeV
<< " Mass(GeV)=" << theParticleDef->GetPDGMass()/CLHEP::GeV
<< " LifeTime(ns)=" << theLife/CLHEP::ns << G4endl;
}
#endif
if (theParticleDef->GetPDGStable()) {meanlife = DBL_MAX;}
else if (theLife < 0.0) {meanlife = DBL_MAX;}
else {meanlife = theLife;}
// Set meanlife to zero for excited istopes which are not in the
// RDM database
if (((const G4Ions*)(theParticleDef))->GetExcitationEnergy() > 0. &&
meanlife == DBL_MAX) {meanlife = 0.;}
if (theLife >= 0.0 && theLife <= fThresholdForVeryLongDecayTime) {
meanlife = theLife;
}
if (meanlife == DBL_MAX) {
const G4Ions* ion = dynamic_cast<const G4Ions*>(theParticleDef);
if (nullptr != ion && ion->GetExcitationEnergy() > 0.0) {
meanlife = 0.0;
}
}
#ifdef G4VERBOSE
if (GetVerboseLevel() > 2)
G4cout << " mean life time: " << meanlife/s << " s " << G4endl;
G4cout << "G4RadioactiveDecay::GetMeanLifeTime: "
<< meanlife/CLHEP::s << " second " << G4endl;
#endif
return meanlife;
}
////////////////////////////////////////////////////////////////////////////////
// //
// GetMeanFreePath for decay in flight //
@@ -382,62 +414,27 @@ G4double G4RadioactiveDecay::GetMeanLifeTime(const G4Track& theTrack,
////////////////////////////////////////////////////////////////////////////////
G4double G4RadioactiveDecay::GetMeanFreePath(const G4Track& aTrack, G4double,
G4ForceCondition*)
G4ForceCondition* fc)
{
const G4DynamicParticle* aParticle = aTrack.GetDynamicParticle();
const G4ParticleDefinition* aParticleDef = aParticle->GetDefinition();
G4double tau = aParticleDef->GetPDGLifeTime();
G4double aMass = aParticle->GetMass();
#ifdef G4VERBOSE
if (GetVerboseLevel() > 2) {
G4cout << "G4RadioactiveDecay::GetMeanFreePath() " << G4endl;
G4cout << " KineticEnergy: " << aParticle->GetKineticEnergy()/GeV
<< " GeV, Mass: " << aMass/GeV << " GeV, tau: " << tau << " ns "
<< G4endl;
}
#endif
G4double pathlength = DBL_MAX;
if (tau != -1) {
// Ion can decay
if (tau < -1000.0) {
pathlength = DBL_MIN; // nuclide had very short lifetime or wasn't in table
} else if (tau < 0.0) {
G4cout << aParticleDef->GetParticleName() << " has lifetime " << tau << G4endl;
G4ExceptionDescription ed;
ed << "Ion has negative lifetime " << tau
<< " but is not stable. Setting mean free path to DBL_MAX" << G4endl;
G4Exception("G4RadioactiveDecay::GetMeanFreePath()", "HAD_RDM_011",
JustWarning, ed);
pathlength = DBL_MAX;
} else {
// Calculate mean free path
G4double betaGamma = aParticle->GetTotalMomentum()/aMass;
pathlength = c_light*tau*betaGamma;
if (pathlength < DBL_MIN) {
pathlength = DBL_MIN;
#ifdef G4VERBOSE
if (GetVerboseLevel() > 2) {
G4cout << "G4Decay::GetMeanFreePath: "
<< aParticleDef->GetParticleName()
<< " stops, kinetic energy = "
<< aParticle->GetKineticEnergy()/keV <<" keV " << G4endl;
}
#endif
}
}
G4double res = DBL_MAX;
G4double lifeTime = GetMeanLifeTime(aTrack, fc);
if (lifeTime > 0.0 && lifeTime < DBL_MAX) {
auto dParticle = aTrack.GetDynamicParticle();
res = lifeTime*dParticle->GetTotalEnergy()*aTrack.GetVelocity()/dParticle->GetMass();
} else {
res = lifeTime;
}
#ifdef G4VERBOSE
if (GetVerboseLevel() > 2) {
G4cout << "mean free path: "<< pathlength/m << " m" << G4endl;
G4cout << "G4RadioactiveDecay::GetMeanFreePath() for "
<< aTrack.GetDefinition()->GetParticleName() << G4endl;
G4cout << " kinEnergy(GeV)=" << aTrack.GetKineticEnergy()/CLHEP::GeV
<< " lifeTime(ns)=" << lifeTime
<< " mean free path(cm)=" << res/CLHEP::cm << G4endl;
}
#endif
return pathlength;
return res;
}
////////////////////////////////////////////////////////////////////////////////
@@ -446,17 +443,21 @@ G4double G4RadioactiveDecay::GetMeanFreePath(const G4Track& aTrack, G4double,
// //
////////////////////////////////////////////////////////////////////////////////
void G4RadioactiveDecay::BuildPhysicsTable(const G4ParticleDefinition&)
void G4RadioactiveDecay::BuildPhysicsTable(const G4ParticleDefinition& p)
{
if (!isInitialised) {
isInitialised = true;
#ifdef G4VERBOSE
if(G4HadronicParameters::Instance()->GetVerboseLevel() > 0 &&
G4Threading::IsMasterThread()) { StreamInfo(G4cout, "\n"); }
#endif
if (isInitialised) { return; }
isInitialised = true;
if (G4HadronicParameters::Instance()->GetVerboseLevel() > 0 &&
G4Threading::IsMasterThread() && "GenericIon" == p.GetParticleName()) {
StreamInfo(G4cout, "\n");
}
G4HadronicProcessStore::
Instance()->RegisterParticleForExtraProcess(this,G4GenericIon::GenericIon());
photonEvaporation->Initialise();
photonEvaporation->RDMForced(true);
photonEvaporation->SetICM(true);
decayIT->SetARM(applyARM);
G4HadronicProcessStore::Instance()->RegisterParticleForExtraProcess(this, &p);
G4HadronicProcessStore::Instance()->PrintInfo(&p);
}
////////////////////////////////////////////////////////////////////////////////
@@ -514,38 +515,38 @@ G4RadioactiveDecay::StreamInfo(std::ostream& os, const G4String& endline)
////////////////////////////////////////////////////////////////////////////////
// //
// LoadDecayTable loads the decay scheme from the RadioactiveDecay database //
// LoadDecayTable loads the decay scheme from the RadioactiveDecay database //
// for the parent nucleus. //
// //
////////////////////////////////////////////////////////////////////////////////
G4DecayTable*
G4RadioactiveDecay::LoadDecayTable(const G4ParticleDefinition& theParentNucleus)
G4DecayTable* G4RadioactiveDecay::LoadDecayTable(const G4Ions* theIon)
{
G4AutoLock lk(&radioactiveDecayMutex);
const G4String key = theIon->GetParticleName();
auto dtptr = master_dkmap->find(key);
if (dtptr != master_dkmap->end()) {
lk.unlock();
return dtptr->second;
}
// Generate input data file name using Z and A of the parent nucleus
// file containing radioactive decay data.
G4int A = ((const G4Ions*)(&theParentNucleus))->GetAtomicMass();
G4int Z = ((const G4Ions*)(&theParentNucleus))->GetAtomicNumber();
G4int A = theIon->GetAtomicMass();
G4int Z = theIon->GetAtomicNumber();
G4double levelEnergy = ((const G4Ions*)(&theParentNucleus))->GetExcitationEnergy();
G4Ions::G4FloatLevelBase floatingLevel =
((const G4Ions*)(&theParentNucleus))->GetFloatLevelBase();
//G4cout << "LoadDecayTable for " << key << " Z=" << Z << " A=" << A << G4endl;
#ifdef G4MULTITHREADED
G4AutoLock lk(&G4RadioactiveDecay::radioactiveDecayMutex);
G4String key = theParentNucleus.GetParticleName();
DecayTableMap::iterator master_table_ptr = master_dkmap->find(key);
if (master_table_ptr != master_dkmap->end() ) { // If table is there
return master_table_ptr->second;
}
#endif
G4double levelEnergy = theIon->GetExcitationEnergy();
G4Ions::G4FloatLevelBase floatingLevel = theIon->GetFloatLevelBase();
//Check if data have been provided by the user
G4String file = theUserRadioactiveDataFiles[1000*A+Z];
if (file == "") {
G4String file;
G4int ke = 1000*A + Z;
auto ptr = theUserRDataFiles->find(ke);
if (ptr != theUserRDataFiles->end()) {
file = ptr->second;
} else {
std::ostringstream os;
os << dirPath << "/z" << Z << ".a" << A << '\0';
file = os.str();
@@ -563,7 +564,7 @@ G4RadioactiveDecay::LoadDecayTable(const G4ParticleDefinition& theParentNucleus)
const G4int nMode = G4RadioactiveDecayModeSize;
G4double modeTotalBR[nMode] = {0.0};
G4double modeSumBR[nMode];
for (G4int i = 0; i < nMode; i++) {
for (G4int i = 0; i < nMode; ++i) {
modeSumBR[i] = 0.0;
}
@@ -588,7 +589,8 @@ G4RadioactiveDecay::LoadDecayTable(const G4ParticleDefinition& theParentNucleus)
G4bool complete(false); // bool insures only one set of values read for any
// given parent energy level
G4int loop = 0;
while (!complete && !DecaySchemeFile.getline(inputChars, 120).eof()) { /* Loop checking, 01.09.2015, D.Wright */
/* Loop checking, 01.09.2015, D.Wright */
while (!complete && !DecaySchemeFile.getline(inputChars, 120).eof()) {
loop++;
if (loop > 100000) {
G4Exception("G4RadioactiveDecay::LoadDecayTable()", "HAD_RDM_100",
@@ -627,15 +629,12 @@ G4RadioactiveDecay::LoadDecayTable(const G4ParticleDefinition& theParentNucleus)
// Store for later the total decay probability for each decay mode
if (inputLine.length() < 72) {
tmpStream >> theDecayMode >> dummy >> decayModeTotal;
switch (theDecayMode) {
case IT:
{
G4ITDecay* anITChannel = new G4ITDecay(&theParentNucleus, decayModeTotal,
0.0, 0.0, photonEvaporation);
// anITChannel->SetHLThreshold(halflifethreshold);
anITChannel->SetARM(applyARM);
theDecayTable->Insert(anITChannel);
// anITChannel->DumpNuclearInfo();
G4ITDecay* anITChannel = new G4ITDecay(theIon, decayModeTotal, 0.0, 0.0);
theDecayTable->Insert(anITChannel);
}
break;
case BetaMinus:
@@ -698,34 +697,31 @@ G4RadioactiveDecay::LoadDecayTable(const G4ParticleDefinition& theParentNucleus)
case BetaMinus:
{
G4BetaMinusDecay* aBetaMinusChannel =
new G4BetaMinusDecay(&theParentNucleus, b, c*MeV, a*MeV,
new G4BetaMinusDecay(theIon, b, c*MeV, a*MeV,
daughterFloatLevel, betaType);
// aBetaMinusChannel->DumpNuclearInfo();
// aBetaMinusChannel->SetHLThreshold(halflifethreshold);
//aBetaMinusChannel->DumpNuclearInfo();
theDecayTable->Insert(aBetaMinusChannel);
modeSumBR[BetaMinus] += b;
modeSumBR[BetaMinus] += b;
}
break;
case BetaPlus:
{
G4BetaPlusDecay* aBetaPlusChannel =
new G4BetaPlusDecay(&theParentNucleus, b, c*MeV, a*MeV,
new G4BetaPlusDecay(theIon, b, c*MeV, a*MeV,
daughterFloatLevel, betaType);
// aBetaPlusChannel->DumpNuclearInfo();
// aBetaPlusChannel->SetHLThreshold(halflifethreshold);
//aBetaPlusChannel->DumpNuclearInfo();
theDecayTable->Insert(aBetaPlusChannel);
modeSumBR[BetaPlus] += b;
modeSumBR[BetaPlus] += b;
}
break;
case KshellEC: // K-shell electron capture
{
G4ECDecay* aKECChannel =
new G4ECDecay(&theParentNucleus, b, c*MeV, a*MeV,
new G4ECDecay(theIon, b, c*MeV, a*MeV,
daughterFloatLevel, KshellEC);
// aKECChannel->DumpNuclearInfo();
// aKECChannel->SetHLThreshold(halflifethreshold);
//aKECChannel->DumpNuclearInfo();
aKECChannel->SetARM(applyARM);
theDecayTable->Insert(aKECChannel);
modeSumBR[KshellEC] += b;
@@ -735,10 +731,9 @@ G4RadioactiveDecay::LoadDecayTable(const G4ParticleDefinition& theParentNucleus)
case LshellEC: // L-shell electron capture
{
G4ECDecay* aLECChannel =
new G4ECDecay(&theParentNucleus, b, c*MeV, a*MeV,
new G4ECDecay(theIon, b, c*MeV, a*MeV,
daughterFloatLevel, LshellEC);
// aLECChannel->DumpNuclearInfo();
// aLECChannel->SetHLThreshold(halflifethreshold);
aLECChannel->SetARM(applyARM);
theDecayTable->Insert(aLECChannel);
modeSumBR[LshellEC] += b;
@@ -748,10 +743,9 @@ G4RadioactiveDecay::LoadDecayTable(const G4ParticleDefinition& theParentNucleus)
case MshellEC: // M-shell electron capture
{
G4ECDecay* aMECChannel =
new G4ECDecay(&theParentNucleus, b, c*MeV, a*MeV,
new G4ECDecay(theIon, b, c*MeV, a*MeV,
daughterFloatLevel, MshellEC);
// aMECChannel->DumpNuclearInfo();
// aMECChannel->SetHLThreshold(halflifethreshold);
aMECChannel->SetARM(applyARM);
theDecayTable->Insert(aMECChannel);
modeSumBR[MshellEC] += b;
@@ -761,10 +755,9 @@ G4RadioactiveDecay::LoadDecayTable(const G4ParticleDefinition& theParentNucleus)
case NshellEC: // N-shell electron capture
{
G4ECDecay* aNECChannel =
new G4ECDecay(&theParentNucleus, b, c*MeV, a*MeV,
new G4ECDecay(theIon, b, c*MeV, a*MeV,
daughterFloatLevel, NshellEC);
// aNECChannel->DumpNuclearInfo();
// aNECChannel->SetHLThreshold(halflifethreshold);
aNECChannel->SetARM(applyARM);
theDecayTable->Insert(aNECChannel);
modeSumBR[NshellEC] += b;
@@ -774,10 +767,9 @@ G4RadioactiveDecay::LoadDecayTable(const G4ParticleDefinition& theParentNucleus)
case Alpha:
{
G4AlphaDecay* anAlphaChannel =
new G4AlphaDecay(&theParentNucleus, b, c*MeV, a*MeV,
new G4AlphaDecay(theIon, b, c*MeV, a*MeV,
daughterFloatLevel);
// anAlphaChannel->DumpNuclearInfo();
// anAlphaChannel->SetHLThreshold(halflifethreshold);
theDecayTable->Insert(anAlphaChannel);
modeSumBR[Alpha] += b;
}
@@ -786,10 +778,9 @@ G4RadioactiveDecay::LoadDecayTable(const G4ParticleDefinition& theParentNucleus)
case Proton:
{
G4ProtonDecay* aProtonChannel =
new G4ProtonDecay(&theParentNucleus, b, c*MeV, a*MeV,
new G4ProtonDecay(theIon, b, c*MeV, a*MeV,
daughterFloatLevel);
// aProtonChannel->DumpNuclearInfo();
// aProtonChannel->SetHLThreshold(halflifethreshold);
theDecayTable->Insert(aProtonChannel);
modeSumBR[Proton] += b;
}
@@ -798,10 +789,9 @@ G4RadioactiveDecay::LoadDecayTable(const G4ParticleDefinition& theParentNucleus)
case Neutron:
{
G4NeutronDecay* aNeutronChannel =
new G4NeutronDecay(&theParentNucleus, b, c*MeV, a*MeV,
new G4NeutronDecay(theIon, b, c*MeV, a*MeV,
daughterFloatLevel);
// aNeutronChannel->DumpNuclearInfo();
// aNeutronChannel->SetHLThreshold(halflifethreshold);
theDecayTable->Insert(aNeutronChannel);
modeSumBR[Neutron] += b;
}
@@ -810,9 +800,7 @@ G4RadioactiveDecay::LoadDecayTable(const G4ParticleDefinition& theParentNucleus)
case SpFission:
{
G4SFDecay* aSpontFissChannel =
// new G4SFDecay(&theParentNucleus, decayModeTotal, 0.0, 0.0);
new G4SFDecay(&theParentNucleus, b, c*MeV, a*MeV,
daughterFloatLevel);
new G4SFDecay(theIon, b, c*MeV, a*MeV, daughterFloatLevel);
theDecayTable->Insert(aSpontFissChannel);
modeSumBR[SpFission] += b;
}
@@ -850,13 +838,10 @@ G4RadioactiveDecay::LoadDecayTable(const G4ParticleDefinition& theParentNucleus)
case Triton:
{
G4TritonDecay* aTritonChannel =
new G4TritonDecay(&theParentNucleus, b, c*MeV, a*MeV,
daughterFloatLevel);
// anAlphaChannel->DumpNuclearInfo();
// anAlphaChannel->SetHLThreshold(halflifethreshold);
theDecayTable->Insert(aTritonChannel);
modeSumBR[Triton] += b;
G4TritonDecay* aTritonChannel =
new G4TritonDecay(theIon, b, c*MeV, a*MeV, daughterFloatLevel);
theDecayTable->Insert(aTritonChannel);
modeSumBR[Triton] += b;
}
break;
@@ -879,7 +864,7 @@ G4RadioactiveDecay::LoadDecayTable(const G4ParticleDefinition& theParentNucleus)
G4String mode = "";
G4double theBR = 0.0;
for (G4int i = 0; i < theDecayTable->entries(); i++) {
for (G4int i = 0; i < theDecayTable->entries(); ++i) {
theChannel = theDecayTable->GetDecayChannel(i);
theNuclearDecayChannel = static_cast<G4NuclearDecay*>(theChannel);
theDecayMode = theNuclearDecayChannel->GetDecayMode();
@@ -896,32 +881,29 @@ G4RadioactiveDecay::LoadDecayTable(const G4ParticleDefinition& theParentNucleus)
if (!found && levelEnergy > 0) {
// Case where IT cascade for excited isotopes has no entries in RDM database
// Decay mode is isomeric transition.
G4ITDecay* anITChannel = new G4ITDecay(&theParentNucleus, 1.0, 0.0, 0.0,
photonEvaporation);
// anITChannel->SetHLThreshold(halflifethreshold);
anITChannel->SetARM(applyARM);
G4ITDecay* anITChannel = new G4ITDecay(theIon, 1.0, 0.0, 0.0);
theDecayTable->Insert(anITChannel);
}
if (theDecayTable && GetVerboseLevel() > 1) {
if (GetVerboseLevel() > 1) {
theDecayTable->DumpInfo();
}
#ifdef G4MULTITHREADED
//(*master_dkmap)[key] = theDecayTable; // store in master library
#endif
// store in master library
(*master_dkmap)[theIon->GetParticleName()] = theDecayTable;
lk.unlock();
return theDecayTable;
}
void
G4RadioactiveDecay::AddUserDecayDataFile(G4int Z, G4int A, G4String filename)
void G4RadioactiveDecay::AddUserDecayDataFile(G4int Z, G4int A,
const G4String& filename)
{
if (Z < 1 || A < 2) G4cout << "Z and A not valid!" << G4endl;
std::ifstream DecaySchemeFile(filename);
if (DecaySchemeFile) {
G4int ID_ion = A*1000 + Z;
theUserRadioactiveDataFiles[ID_ion] = filename;
(*theUserRDataFiles)[ID_ion] = filename;
} else {
G4ExceptionDescription ed;
ed << filename << " does not exist! " << G4endl;
@@ -955,9 +937,9 @@ G4RadioactiveDecay::DecayIt(const G4Track& theTrack, const G4Step&)
<< theTrack.GetVolume()->GetLogicalVolume()->GetName()
<< " is not selected for the RDM"<< G4endl;
G4cout << " There are " << ValidVolumes.size() << " volumes" << G4endl;
G4cout << " The Valid volumes are " << G4endl;
for (std::size_t i = 0; i< ValidVolumes.size(); ++i)
G4cout << ValidVolumes[i] << G4endl;
G4cout << " The Valid volumes are: ";
for (auto const & vol : ValidVolumes) { G4cout << vol << " " << G4endl; }
G4cout << G4endl;
}
#endif
fParticleChangeForRadDecay.SetNumberOfSecondaries(0);
@@ -971,14 +953,14 @@ G4RadioactiveDecay::DecayIt(const G4Track& theTrack, const G4Step&)
}
// Now check if particle is valid for RDM
if (!(IsApplicable(*theParticleDef) ) ) {
G4DecayTable* theDecayTable = GetDecayTable(theParticleDef);
if ( theDecayTable == nullptr || theDecayTable->entries() == 0) {
// Particle is not an ion or is outside the nucleuslimits for decay
#ifdef G4VERBOSE
if (GetVerboseLevel() > 1) {
G4cout << "G4RadioactiveDecay::DecayIt : "
<< theParticleDef->GetParticleName()
<< " is not an ion or is outside (Z,A) limits set for the decay. "
<< " Set particle change accordingly. "
<< " is outside (Z,A) limits set for the decay or has no decays."
<< G4endl;
}
#endif
@@ -990,129 +972,26 @@ G4RadioactiveDecay::DecayIt(const G4Track& theTrack, const G4Step&)
ClearNumberOfInteractionLengthLeft();
return &fParticleChangeForRadDecay;
}
//G4cout << "DecayIt for " << theParticleDef->GetParticleName()
// << " isAllVolumesMode:" << isAllVolumesMode
// << " decayTable=" << theDecayTable << G4endl;
G4DecayTable* theDecayTable = GetDecayTable(theParticleDef);
if (theDecayTable == 0 || theDecayTable->entries() == 0) {
// No data in the decay table. Set particle change parameters
// to indicate this.
#ifdef G4VERBOSE
if (GetVerboseLevel() > 1) {
G4cout << "G4RadioactiveDecay::DecayIt : "
<< "decay table not defined for "
<< theParticleDef->GetParticleName()
<< ". Set particle change accordingly. "
<< G4endl;
}
#endif
fParticleChangeForRadDecay.SetNumberOfSecondaries(0);
// Kill the parent particle.
fParticleChangeForRadDecay.ProposeTrackStatus(fStopAndKill) ;
fParticleChangeForRadDecay.ProposeLocalEnergyDeposit(0.0);
ClearNumberOfInteractionLengthLeft();
return &fParticleChangeForRadDecay;
} else {
// Data found. Try to decay nucleus
/*
G4double energyDeposit = 0.0;
G4double finalGlobalTime = theTrack.GetGlobalTime();
G4double finalLocalTime = theTrack.GetLocalTime();
G4int index;
G4ThreeVector currentPosition;
currentPosition = theTrack.GetPosition();
G4DecayProducts* products = DoDecay(*theParticleDef);
// If the product is the same as the input kill the track if
// necessary to prevent infinite loop (11/05/10, F.Lei)
if (products->entries() == 1) {
fParticleChangeForRadDecay.SetNumberOfSecondaries(0);
fParticleChangeForRadDecay.ProposeTrackStatus(fStopAndKill);
fParticleChangeForRadDecay.ProposeLocalEnergyDeposit(0.0);
ClearNumberOfInteractionLengthLeft();
return &fParticleChangeForRadDecay;
}
// Get parent particle information and boost the decay products to the
// laboratory frame based on this information.
// The Parent Energy used for the boost should be the total energy of
// the nucleus of the parent ion without the energy of the shell electrons
// (correction for bug 1359 by L. Desorgher)
G4double ParentEnergy = theParticle->GetKineticEnergy()
+ theParticle->GetParticleDefinition()->GetPDGMass();
G4ThreeVector ParentDirection(theParticle->GetMomentumDirection());
if (theTrack.GetTrackStatus() == fStopButAlive) {
// This condition seems to be always True, further investigation is needed
// (L.Desorgher)
// The particle is decayed at rest.
// since the time is still for rest particle in G4 we need to add the
// additional time lapsed between the particle come to rest and the
// actual decay. This time is simply sampled with the mean-life of
// the particle. But we need to protect the case PDGTime < 0.
// (F.Lei 11/05/10)
G4double temptime = -std::log( G4UniformRand())
*theParticleDef->GetPDGLifeTime();
if (temptime < 0.) temptime = 0.;
finalGlobalTime += temptime;
finalLocalTime += temptime;
energyDeposit += theParticle->GetKineticEnergy();
}
products->Boost(ParentEnergy, ParentDirection);
// Add products in theParticleChangeForRadDecay.
G4int numberOfSecondaries = products->entries();
fParticleChangeForRadDecay.SetNumberOfSecondaries(numberOfSecondaries);
#ifdef G4VERBOSE
if (GetVerboseLevel()>1) {
G4cout <<"G4RadioactiveDecay::DecayIt : Decay vertex :";
G4cout <<" Time: " <<finalGlobalTime/ns <<"[ns]";
G4cout <<" X:" <<(theTrack.GetPosition()).x() /cm <<"[cm]";
G4cout <<" Y:" <<(theTrack.GetPosition()).y() /cm <<"[cm]";
G4cout <<" Z:" <<(theTrack.GetPosition()).z() /cm <<"[cm]";
G4cout << G4endl;
G4cout <<"G4Decay::DecayIt : decay products in Lab. Frame" <<G4endl;
products->DumpInfo();
products->IsChecked();
}
#endif
for (index=0; index < numberOfSecondaries; index++) {
G4Track* secondary = new G4Track(products->PopProducts(),
finalGlobalTime, currentPosition);
secondary->SetGoodForTrackingFlag();
secondary->SetTouchableHandle(theTrack.GetTouchableHandle());
fParticleChangeForRadDecay.AddSecondary(secondary);
}
delete products;
// Kill the parent particle
fParticleChangeForRadDecay.ProposeTrackStatus(fStopAndKill) ;
fParticleChangeForRadDecay.ProposeLocalEnergyDeposit(energyDeposit);
fParticleChangeForRadDecay.ProposeLocalTime(finalLocalTime);
// Reset NumberOfInteractionLengthLeft.
ClearNumberOfInteractionLengthLeft();
*/
// Decay without variance reduction
DecayAnalog(theTrack);
return &fParticleChangeForRadDecay ;
}
// Data found. Decay nucleus without variance reduction.
DecayAnalog(theTrack, theDecayTable);
return &fParticleChangeForRadDecay;
}
void G4RadioactiveDecay::DecayAnalog(const G4Track& theTrack)
void G4RadioactiveDecay::DecayAnalog(const G4Track& theTrack,
G4DecayTable* decayTable)
{
const G4DynamicParticle* theParticle = theTrack.GetDynamicParticle();
const G4ParticleDefinition* theParticleDef = theParticle->GetDefinition();
G4DecayProducts* products = DoDecay(*theParticleDef);
//G4cout << "DecayIt for " << theParticleDef->GetParticleName() << G4endl;
G4DecayProducts* products = DoDecay(*theParticleDef, decayTable);
// Check if the product is the same as input and kill the track if
// necessary to prevent infinite loop (11/05/10, F.Lei)
if (products->entries() == 1) {
if (nullptr == products || products->entries() == 1) {
fParticleChangeForRadDecay.SetNumberOfSecondaries(0);
fParticleChangeForRadDecay.ProposeTrackStatus(fStopAndKill);
fParticleChangeForRadDecay.ProposeLocalEnergyDeposit(0.0);
@@ -1225,10 +1104,10 @@ void G4RadioactiveDecay::DecayAnalog(const G4Track& theTrack)
G4DecayProducts*
G4RadioactiveDecay::DoDecay(const G4ParticleDefinition& theParticleDef)
G4RadioactiveDecay::DoDecay(const G4ParticleDefinition& theParticleDef,
G4DecayTable* theDecayTable)
{
G4DecayProducts* products = 0;
G4DecayTable* theDecayTable = GetDecayTable(&theParticleDef);
G4DecayProducts* products = nullptr;
// Choose a decay channel.
// G4DecayTable::SelectADecayChannel checks to see if sum of daughter masses
@@ -1237,7 +1116,7 @@ G4RadioactiveDecay::DoDecay(const G4ParticleDefinition& theParticleDef)
G4double parentPlusQ = theParticleDef.GetPDGMass() + 30.*MeV;
G4VDecayChannel* theDecayChannel = theDecayTable->SelectADecayChannel(parentPlusQ);
if (theDecayChannel == 0) {
if (theDecayChannel == nullptr) {
// Decay channel not found.
G4ExceptionDescription ed;
ed << " Cannot determine decay channel for " << theParticleDef.GetParticleName() << G4endl;
@@ -1251,8 +1130,16 @@ G4RadioactiveDecay::DoDecay(const G4ParticleDefinition& theParticleDef)
<< theDecayChannel << G4endl;
}
#endif
theRadDecayMode = (static_cast<G4NuclearDecay*>(theDecayChannel))->GetDecayMode();
products = theDecayChannel->DecayIt(theParticleDef.GetPDGMass() );
theRadDecayMode = static_cast<G4NuclearDecay*>(theDecayChannel)->GetDecayMode();
// for IT decay use local G4ITDecay class
if (theRadDecayMode == IT) {
decayIT->SetupDecay(&theParticleDef);
products = decayIT->DecayIt(0.0);
} else {
// for others decayes use shared class
products = theDecayChannel->DecayIt(theParticleDef.GetPDGMass());
}
// Apply directional bias if requested by user
CollimateDecay(products);
@@ -1263,7 +1150,6 @@ G4RadioactiveDecay::DoDecay(const G4ParticleDefinition& theParticleDef)
// Apply directional bias for "visible" daughters (e+-, gamma, n, p, alpha)
void G4RadioactiveDecay::CollimateDecay(G4DecayProducts* products) {
if (origin == forceDecayDirection) return; // No collimation requested
@@ -1280,17 +1166,19 @@ void G4RadioactiveDecay::CollimateDecay(G4DecayProducts* products) {
static const G4ParticleDefinition* neutron = G4Neutron::Definition();
static const G4ParticleDefinition* gamma = G4Gamma::Definition();
static const G4ParticleDefinition* alpha = G4Alpha::Definition();
static const G4ParticleDefinition* triton = G4Triton::Definition();
static const G4ParticleDefinition* triton = G4Triton::Definition();
static const G4ParticleDefinition* proton = G4Proton::Definition();
G4ThreeVector newDirection; // Re-use to avoid memory churn
for (G4int i=0; i<products->entries(); i++) {
for (G4int i=0; i<products->entries(); ++i) {
G4DynamicParticle* daughter = (*products)[i];
const G4ParticleDefinition* daughterType =
daughter->GetParticleDefinition();
if (daughterType == electron || daughterType == positron ||
daughterType == neutron || daughterType == gamma ||
daughterType == alpha || daughterType == triton || daughterType == proton) CollimateDecayProduct(daughter);
daughterType == alpha || daughterType == triton || daughterType == proton) {
CollimateDecayProduct(daughter);
}
}
}