Import Geant4 11.2.0 source tree

This commit is contained in:
Gabriele Cosmo
2023-12-08 10:43:34 +01:00
parent dd1f179cda
commit 860a2b92bf
3962 changed files with 139318 additions and 164259 deletions
@@ -6,6 +6,67 @@ It must **not** be used as a substitute for writing good git commit messages!
-------------------------------------------------------------------------------
## 2023-11-16 Alberto Ribon (radioactive_decay-V11-01-09)
- G4RadioactiveDecay, G4Radioactivation : added an extra parameter in the
constructor of these classes, to be able to set, directly at the level
of class constructor, the threshold for the time beyond which radioactive
decays are ignored. This is meant for custom physics lists.
Moreover, the constructor of these classes have been modified to offer
also a C++ interface - via the singleton G4HadronicParameters - to set
the same time threshold for radioactive decays. This is meant for
reference physics lists.
Note that, in the unlikely and weird scenario that two time thresholds
are specified - one via G4HadronicParameters, and one via the constructor
parameter - the larger of the two is considered, to be conservative.
In all cases, an eventual time threshold specified via UI command
(i.e. /process/had/rdm/thresholdForVeryLongDecayTime value)
prevails on everything else.
## 2023-11-07 Alberto Ribon (radioactive_decay-V11-01-08)
- G4RadioactiveDecay : changed default threshold for the time beyond which
radioactive decays are ignored - from twice the age of the Universe to
1 year.
( Reminder: this threshold can be changed via the UI command,
e.g. to set it to 1000 years:
/process/had/rdm/thresholdForVeryLongDecayTime 1000.0 year
)
## 2023-10-05 Vladimir Ivantchenko (radioactive_decay-V11-01-07)
- G4RadioactiveDecay - removed debug printout
## 2023-09-28 Vladimir Ivantchenko (radioactive_decay-V11-01-06)
- G4Radioactivation - fixed another Coverity report
## 2023-08-29 Vladimir Ivantchenko (radioactive_decay-V11-01-05)
- G4Radioactivation - fixed Coverity reports
## 2023-08-23 Vladimir Ivantchenko (radioactive_decay-V11-01-04)
- G4RadioactiveDecay - only one table of radioactive decay channels,
removed not needed ifdef for MULTITHREADED; removed lock from
class constructor, added use only lock in the method LoadDecayTable(..)
after the check if the table is already downloaded, added explicit
unlock in this method; removed counter of instances of the class;
all virtual methods maked override and implementations are moved to
the source; DecayIt(..) method is declaired virtual, removed unused
methods; use reference instead of values in method signatures for
complex objects; added G4ITDecay object local for each thread to perform
sampling of radioactive decays with a possibility to sample correlated
gamma emission
- G4Radioactivation - all virtual methods marked as
override and implementations are moved to the source; DecayIt(..)
is marked as override; removed methods GetDecayTable1, AtRestDoIt,
PostStepDoIt instead base class method are used.
- G4BetaMinusDecay, G4BetaPlusDecay, G4BetaSpectrumSampler - implemented
thread safe sampling method
- G4NuclearDecay - implement virtual method IsOKWithParentMass which
alwys return 'true', make access methods 'const' where possible
- G4ITDecay - added method SetupDecay, which allows this class to be used
inside local thread
## 2023-07-16 Vladimir Ivantchenko (radioactive_decay-V11-01-03)
- G4RadioactiveDecay - fixed initialisation printout: correct place
for triton printout;
## 2023-06-17 Vladimir Ivantchenko (radioactive_decay-V11-01-02)
- G4RadioactiveDecay, G4BetaSpectrumSampler - fixed Coverity reports on
non-initialized class members
@@ -30,6 +30,9 @@
// Date: 25 October 2014 //
// Description: performs beta- decay of radioactive nuclei, and returns //
// daughter particles in rest frame of parent nucleus //
// Modifications: //
// 23.08.2023 V.Ivanchenko make it thread safe using static utility //
// G4BetaSpectrumSampler //
// //
////////////////////////////////////////////////////////////////////////////////
@@ -38,7 +41,6 @@
#include "G4NuclearDecay.hh"
#include "G4BetaDecayType.hh"
#include "G4BetaSpectrumSampler.hh"
class G4BetaMinusDecay : public G4NuclearDecay
@@ -49,18 +51,30 @@ class G4BetaMinusDecay : public G4NuclearDecay
const G4double& ex, const G4Ions::G4FloatLevelBase& flb,
const G4BetaDecayType& type);
virtual ~G4BetaMinusDecay();
~G4BetaMinusDecay() override = default;
virtual G4DecayProducts* DecayIt(G4double);
G4DecayProducts* DecayIt(G4double) override;
virtual void DumpNuclearInfo();
void DumpNuclearInfo() override;
private:
void SetUpBetaSpectrumSampler(const G4int& parentZ, const G4int& parentA,
const G4BetaDecayType& type);
const G4double endpointEnergy;
G4BetaSpectrumSampler* betaSampler;
const G4double maxEnergy; // in eMass units
const G4double estep; // in eMass units
G4double parentMass;
G4double resMass;
const G4ParticleDefinition* fPrimaryIon;
const G4ParticleDefinition* fResIon;
const G4ParticleDefinition* fLepton;
const G4ParticleDefinition* fNeutrino;
static const G4int npti{101};
G4double cdf[npti];
};
#endif
@@ -30,6 +30,9 @@
// Date: 14 November 2014 //
// Description: performs beta+ decay of radioactive nuclei, and returns //
// daughter particles in rest frame of parent nucleus //
// Modifications: //
// 23.08.2023 V.Ivanchenko make it thread safe using static utility //
// G4BetaSpectrumSampler //
// //
////////////////////////////////////////////////////////////////////////////////
@@ -38,8 +41,6 @@
#include "G4NuclearDecay.hh"
#include "G4BetaDecayType.hh"
#include "G4BetaSpectrumSampler.hh"
class G4BetaPlusDecay : public G4NuclearDecay
{
@@ -49,18 +50,30 @@ class G4BetaPlusDecay : public G4NuclearDecay
const G4double& ex, const G4Ions::G4FloatLevelBase& flb,
const G4BetaDecayType& type);
virtual ~G4BetaPlusDecay();
~G4BetaPlusDecay() override = default;
virtual G4DecayProducts* DecayIt(G4double);
G4DecayProducts* DecayIt(G4double) override;
virtual void DumpNuclearInfo();
void DumpNuclearInfo() override;
private:
void SetUpBetaSpectrumSampler(const G4int& parentZ, const G4int& parentA,
const G4BetaDecayType& type);
const G4double endpointEnergy;
G4BetaSpectrumSampler* betaSampler;
const G4double maxEnergy; // in eMass units
const G4double estep; // in eMass units
G4double parentMass;
G4double resMass;
const G4ParticleDefinition* fPrimaryIon;
const G4ParticleDefinition* fResIon;
const G4ParticleDefinition* fLepton;
const G4ParticleDefinition* fNeutrino;
static const G4int npti{101};
G4double cdf[npti];
};
#endif
@@ -38,30 +38,17 @@
#define G4BetaSpectrumSampler_h 1
#include "globals.hh"
#include "Randomize.hh"
#include <vector>
class G4BetaSpectrumSampler
{
public:
G4BetaSpectrumSampler(const G4double* aPDF, G4int pdfSize, G4double e);
public:
~G4BetaSpectrumSampler() = default;
// sampling of any spectra using cumulative PDF function
// energy stepts are uniform starting from zero
// no check on array size is performed
static G4double shoot(const G4int npoints, const G4double* aCDF,
const G4double estep);
G4double shoot();
private:
G4double sampleSlopedLine(); // Method to sample under sloped line
std::vector<double> pdf; // Spectrum shape
std::vector<double> cdf; // Cumulative distribution function
G4double eEnd; // Endpoint energy of spectrum
G4int nBins; // Number of lower bin edges in spectrum
G4int lowerBinEdge; // Index of lower bin edge
G4int upperBinEdge; // Index of upper bin edge
G4double ylower{0.0}; // Value at lower bin edge
G4double yupper{0.0}; // Value at upper bin edge
};
#endif
@@ -44,26 +44,34 @@ class G4PhotonEvaporation;
class G4ITDecay : public G4NuclearDecay
{
public:
G4ITDecay(const G4ParticleDefinition* theParentNucleus,
const G4double& theBR, const G4double& Qvalue,
const G4double& excitation, G4PhotonEvaporation* aPhotonEvap);
public:
virtual ~G4ITDecay();
// constructor for sampling of radiaoctive decay in a thread
G4ITDecay(G4PhotonEvaporation* aPhotonEvap);
virtual G4DecayProducts* DecayIt(G4double);
// constructor to define decay channels in the shared decay table
G4ITDecay(const G4ParticleDefinition* theParentNucleus,
const G4double& theBR, const G4double& Qvalue,
const G4double& excitation);
virtual void DumpNuclearInfo();
~G4ITDecay() override = default;
void SetARM(G4bool onoff) {applyARM = onoff;}
void SetupDecay(const G4ParticleDefinition*);
G4DecayProducts* DecayIt(G4double) override;
void DumpNuclearInfo() override;
void SetARM(G4bool onoff) {applyARM = onoff;}
private:
const G4double transitionQ;
G4int parentZ;
G4int parentA;
G4bool applyARM;
private:
G4PhotonEvaporation* photonEvaporation;
G4int parentZ{0};
G4int parentA{0};
G4bool applyARM{true};
G4PhotonEvaporation* photonEvaporation{nullptr};
const G4ParticleDefinition* theParent{nullptr};
};
#endif
@@ -48,29 +48,29 @@ class G4NuclearDecay : public G4VDecayChannel
const G4double& excitation,
const G4Ions::G4FloatLevelBase& floatingLevel);
virtual ~G4NuclearDecay();
~G4NuclearDecay() override = default;
G4RadioactiveDecayMode GetDecayMode() {return theMode;}
G4bool IsOKWithParentMass(G4double parentMass) override;
G4double GetDaughterExcitation() {return daughterEx;}
G4RadioactiveDecayMode GetDecayMode() const {return theMode;}
G4Ions::G4FloatLevelBase GetFloatingLevel() {return floatingLevel;}
G4double GetDaughterExcitation() const {return daughterEx;}
G4Ions::G4FloatLevelBase GetFloatingLevel() const {return floatingLevel;}
G4ParticleDefinition* GetDaughterNucleus() {return GetDaughter(0);}
void SetHLThreshold(G4double HLT) {halflifeThreshold = HLT;}
G4double GetHLThreshold() {return halflifeThreshold;}
virtual void DumpNuclearInfo() = 0;
protected:
const G4RadioactiveDecayMode theMode;
private:
// Needed for variance reduction mode
const G4double daughterEx;
const G4Ions::G4FloatLevelBase floatingLevel;
G4double halflifeThreshold;
};
#endif
@@ -51,26 +51,26 @@ typedef std::vector<G4RadioactiveDecayChainsFromParent> G4RadioactiveDecayParent
typedef std::vector<G4RadioactiveDecayRatesToDaughter> G4RadioactiveDecayRates;
typedef std::map<G4String, G4DecayTable*> DecayTableMap;
class G4Radioactivation : public G4RadioactiveDecay
{
public: // with description
G4Radioactivation(const G4String& processName="Radioactivation");
~G4Radioactivation();
G4Radioactivation(const G4String& processName="Radioactivation",
const G4double timeThresholdForRadioactiveDecays=-1.0);
~G4Radioactivation() override;
virtual void ProcessDescription(std::ostream& outFile) const;
G4VParticleChange* DecayIt(const G4Track& theTrack,
const G4Step& theStep) override;
// Return decay table if it exists, if not, load it from file
G4DecayTable* GetDecayTable1(const G4ParticleDefinition*);
void ProcessDescription(std::ostream& outFile) const override;
// Set the decay biasing scheme using the data in "filename"
void SetDecayBias(G4String filename);
void SetDecayBias(const G4String& filename);
// Set the half-life threshold for isomer production
void SetHLThreshold(G4double hl) {halflifethreshold = hl;}
void SetSourceTimeProfile(G4String filename);
void SetSourceTimeProfile(const G4String& filename);
// Set source exposure function using histograms in "filename"
G4bool IsRateTableReady(const G4ParticleDefinition &);
@@ -90,12 +90,12 @@ class G4Radioactivation : public G4RadioactiveDecay
// and place it in "chainsFromParent".
// used in VR decay mode only
void SetDecayRate(G4int,G4int,G4double, G4int, std::vector<G4double>,
std::vector<G4double>);
void SetDecayRate(G4int,G4int,G4double, G4int, std::vector<G4double>&,
std::vector<G4double>&);
// Sets "theDecayRate" with data supplied in the arguements.
// used in VR decay mode only
std::vector<G4RadioactivityTable*> GetTheRadioactivityTables()
std::vector<G4RadioactivityTable*>& GetTheRadioactivityTables()
{return theRadioactivityTables;}
// Return vector of G4Radioactivity map - should be used in VR mode only
@@ -103,9 +103,8 @@ class G4Radioactivation : public G4RadioactiveDecay
// Controls whether G4Radioactivation runs in analogue mode or
// variance reduction mode. SetBRBias, SetSplitNuclei and
// SetSourceTimeProfile all turn off analogue mode and use VR mode
inline void SetAnalogueMonteCarlo (G4bool r ) {
inline void SetAnalogueMonteCarlo (G4bool r) {
AnalogueMC = r;
if (!AnalogueMC) halflifethreshold = 1e-6*CLHEP::s;
}
// Returns true if the simulation is an analogue Monte Carlo, and false if
@@ -127,8 +126,8 @@ class G4Radioactivation : public G4RadioactiveDecay
// Returns the nuclear splitting number
inline G4int GetSplitNuclei () {return NSplit;}
G4VParticleChange* DecayIt(const G4Track& theTrack,
const G4Step& theStep);
G4Radioactivation(const G4Radioactivation& right) = delete;
G4Radioactivation& operator=(const G4Radioactivation& right) = delete;
protected:
@@ -137,7 +136,7 @@ class G4Radioactivation : public G4RadioactiveDecay
G4int GetDecayTimeBin(const G4double aDecayTime);
G4double GetMeanLifeTime(const G4Track& theTrack,
G4ForceCondition* condition);
G4ForceCondition* condition) override;
//Add gamma,Xray,conversion,and auger electrons for bias mode
void AddDeexcitationSpectrumForBiasMode(G4ParticleDefinition* apartDef,
@@ -147,10 +146,9 @@ class G4Radioactivation : public G4RadioactiveDecay
std::vector<double>& times_v,
std::vector<G4DynamicParticle*>& secondaries_v);
G4RadioactivationMessenger* theRadioactivationMessenger;
private:
G4RadioactivationMessenger* theRadioactivationMessenger;
G4bool AnalogueMC;
G4bool BRBias;
G4int NSplit;
@@ -172,14 +170,6 @@ class G4Radioactivation : public G4RadioactiveDecay
// for the radioactivity tables
std::vector<G4RadioactivityTable*> theRadioactivityTables;
G4int decayWindows[100];
inline
G4VParticleChange* AtRestDoIt(const G4Track& theTrack, const G4Step& theStep)
{return DecayIt(theTrack, theStep);}
inline
G4VParticleChange* PostStepDoIt(const G4Track& theTrack, const G4Step& theStep)
{return DecayIt(theTrack, theStep);}
};
#endif
@@ -50,12 +50,14 @@
#include "G4NucleusLimits.hh"
#include "G4ThreeVector.hh"
#include "G4Threading.hh"
#include "G4RadioactiveDecayMode.hh"
class G4Fragment;
class G4RadioactiveDecayMessenger;
class G4PhotonEvaporation;
class G4Ions;
class G4DecayTable;
class G4ITDecay;
typedef std::map<G4String, G4DecayTable*> DecayTableMap;
@@ -74,16 +76,28 @@ class G4RadioactiveDecay : public G4VRestDiscreteProcess
public: // with description
G4RadioactiveDecay(const G4String& processName="RadioactiveDecay");
~G4RadioactiveDecay();
G4RadioactiveDecay(const G4String& processName="RadioactiveDecay",
const G4double timeThreshold=-1.0);
~G4RadioactiveDecay() override;
virtual void ProcessDescription(std::ostream& outFile) const;
G4bool IsApplicable(const G4ParticleDefinition&);
G4bool IsApplicable(const G4ParticleDefinition&) override;
// Return true if the specified isotope is
// 1) defined as "nucleus" and
// 2) it is within theNucleusLimit
G4VParticleChange* AtRestDoIt(const G4Track& theTrack,
const G4Step& theStep) override;
G4VParticleChange* PostStepDoIt(const G4Track& theTrack,
const G4Step& theStep) override;
void BuildPhysicsTable(const G4ParticleDefinition &) override;
void ProcessDescription(std::ostream& outFile) const override;
virtual G4VParticleChange* DecayIt(const G4Track& theTrack,
const G4Step& theStep);
// Return decay table if it exists, if not, load it from file
G4DecayTable* GetDecayTable(const G4ParticleDefinition*);
@@ -102,19 +116,13 @@ class G4RadioactiveDecay : public G4VRestDiscreteProcess
// Enable/disable ARM
void SetARM(G4bool arm) {applyARM = arm;}
G4DecayTable* LoadDecayTable(const G4ParticleDefinition& theParentNucleus);
G4DecayTable* LoadDecayTable(const G4Ions*);
// Load the decay data of isotope theParentNucleus
void AddUserDecayDataFile(G4int Z, G4int A,G4String filename);
void AddUserDecayDataFile(G4int Z, G4int A, const G4String& filename);
// Allow the user to replace the radio-active decay data provided in Geant4
// by its own data file for a given isotope
inline void SetVerboseLevel(G4int value) {verboseLevel = value;}
// Sets the VerboseLevel which controls duggering display
inline G4int GetVerboseLevel() const {return verboseLevel;}
// Returns the VerboseLevel which controls level of debugging output
inline void SetNucleusLimits(G4NucleusLimits theNucleusLimits1)
{theNucleusLimits = theNucleusLimits1 ;}
// Sets theNucleusLimits which specifies the range of isotopes
@@ -152,105 +160,68 @@ class G4RadioactiveDecay : public G4VRestDiscreteProcess
}
inline G4double GetThresholdForVeryLongDecayTime() const {return fThresholdForVeryLongDecayTime;}
void BuildPhysicsTable(const G4ParticleDefinition &);
void StreamInfo(std::ostream& os, const G4String& endline);
G4VParticleChange* DecayIt(const G4Track& theTrack,
const G4Step& theStep);
G4RadioactiveDecay(const G4RadioactiveDecay& right) = delete;
G4RadioactiveDecay& operator=(const G4RadioactiveDecay& right) = delete;
protected:
void DecayAnalog(const G4Track& theTrack);
G4double GetMeanFreePath(const G4Track& theTrack, G4double previousStepSize,
G4ForceCondition* condition) override;
G4DecayProducts* DoDecay(const G4ParticleDefinition& theParticleDef);
G4double GetMeanLifeTime(const G4Track& theTrack,
G4ForceCondition* condition) override;
// sampling of products
void DecayAnalog(const G4Track& theTrack, G4DecayTable*);
// sampling products at rest
G4DecayProducts* DoDecay(const G4ParticleDefinition&, G4DecayTable*);
// Apply directional bias for "visible" daughters (e+-, gamma, n, p, alpha)
void CollimateDecay(G4DecayProducts* products);
void CollimateDecayProduct(G4DynamicParticle* product);
G4ThreeVector ChooseCollimationDirection() const;
G4double GetMeanFreePath(const G4Track& theTrack, G4double previousStepSize,
G4ForceCondition* condition);
G4double GetMeanLifeTime(const G4Track& theTrack,
G4ForceCondition* condition);
// ParticleChange for decay process
G4ParticleChangeForRadDecay fParticleChangeForRadDecay;
G4RadioactiveDecayMessenger* theRadioactiveDecayMessenger;
G4PhotonEvaporation* photonEvaporation;
G4ITDecay* decayIT;
std::vector<G4String> ValidVolumes;
bool isAllVolumesMode;
bool isAllVolumesMode{true};
static const G4double levelTolerance;
// Library of decay tables
DecayTableMap* dkmap;
#ifdef G4MULTITHREADED
static DecayTableMap* master_dkmap;
#endif
private:
void StreamInfo(std::ostream& os, const G4String& endline);
G4RadioactiveDecay(const G4RadioactiveDecay& right);
G4RadioactiveDecay& operator=(const G4RadioactiveDecay& right);
G4NucleusLimits theNucleusLimits;
G4bool isInitialised;
G4bool applyARM;
G4bool isInitialised{false};
G4bool applyARM{true};
// Parameters for pre-collimated (biased) decay products
G4ThreeVector forceDecayDirection;
G4double forceDecayHalfAngle;
G4ThreeVector forceDecayDirection{G4ThreeVector(0., 0., 0.)};
G4double forceDecayHalfAngle{0.0};
static const G4ThreeVector origin; // (0,0,0) for convenience
// Radioactive decay database directory path
G4String dirPath;
static G4String dirPath;
//User define radioactive decay data files replacing some files in the G4RADECAY database
std::map<G4int, G4String> theUserRadioactiveDataFiles;
//The last RadDecayMode
G4RadioactiveDecayMode theRadDecayMode{G4RadioactiveDecayMode::IT};
// Remainder of life time at rest
G4double fRemainderLifeTime{0.0};
G4int verboseLevel;
// User define radioactive decay data files replacing some files in the G4RADECAY database
static std::map<G4int, G4String>* theUserRDataFiles;
// The last RadDecayMode
G4RadioactiveDecayMode theRadDecayMode{G4RadioactiveDecayMode::IT};
// Ignore radioactive decays at rest of nuclides happening after this (very long) time threshold
G4double fThresholdForVeryLongDecayTime;
// inline implementations
inline
G4double AtRestGetPhysicalInteractionLength(const G4Track& track,
G4ForceCondition* condition)
{
fRemainderLifeTime =
G4VRestDiscreteProcess::AtRestGetPhysicalInteractionLength(track, condition);
return fRemainderLifeTime;
}
inline
G4VParticleChange* AtRestDoIt(const G4Track& theTrack,
const G4Step& theStep)
{return DecayIt(theTrack, theStep);}
inline
G4VParticleChange* PostStepDoIt(const G4Track& theTrack,
const G4Step& theStep)
{return DecayIt(theTrack, theStep);}
#ifdef G4MULTITHREADED
public:
static G4Mutex radioactiveDecayMutex;
protected:
G4int& NumberOfInstances();
#endif
};
#endif
@@ -57,7 +57,6 @@ geant4_add_module(G4hadronic_radioactivedecay
geant4_module_link_libraries(G4hadronic_radioactivedecay
PUBLIC
G4globman
G4heprandom
G4intercoms
G4partman
G4procman
@@ -74,6 +73,7 @@ geant4_module_link_libraries(G4hadronic_radioactivedecay
G4hadronic_mgt
G4hadronic_util
G4hepgeometry
G4heprandom
G4ions
G4leptons
G4materials)
@@ -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);
}
}
}