Import Geant4 11.2.0 source tree
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user