Import Geant4 11.4.0.beta source tree

This commit is contained in:
Gabriele Cosmo
2025-06-26 09:17:29 +02:00
parent 20a218bbe1
commit a499fb82e9
1941 changed files with 203285 additions and 95593 deletions
@@ -1,127 +0,0 @@
//
// ********************************************************************
// * License and Disclaimer *
// * *
// * The Geant4 software is copyright of the Copyright Holders of *
// * the Geant4 Collaboration. It is provided under the terms and *
// * conditions of the Geant4 Software License, included in the file *
// * LICENSE and available at http://cern.ch/geant4/license . These *
// * include a list of copyright holders. *
// * *
// * Neither the authors of this software system, nor their employing *
// * institutes,nor the agencies providing financial support for this *
// * work make any representation or warranty, express or implied, *
// * regarding this software system or assume any liability for its *
// * use. Please see the license in the file LICENSE and URL above *
// * for the full disclaimer and the limitation of liability. *
// * *
// * This code implementation is the result of the scientific and *
// * technical work of the GEANT4 collaboration. *
// * By using, copying, modifying or distributing the software (or *
// * any work based on the software) you agree to acknowledge its *
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
//
// Created by ngoc hoang tran on 03/08/2023.
//
#include "G4ChemEquilibrium.hh"
#include "G4DNAMolecularReactionTable.hh"
G4ChemEquilibrium::G4ChemEquilibrium(const G4int& type, const G4double& time)
: fEquilibriumDuration(time), fRectionType(type)
{}
void G4ChemEquilibrium::Initialize()
{
MolType H2O =
G4MoleculeTable::Instance()->GetConfiguration("H2O");
MolType H3OpB =
G4MoleculeTable::Instance()->GetConfiguration("H3Op(B)");
MolType OHmB =
G4MoleculeTable::Instance()->GetConfiguration("OHm(B)");
const auto& reactionList = G4DNAMolecularReactionTable::Instance()->
GetVectorOfReactionData();
for(const auto& it : reactionList)
{
if(it->GetReactionType()==fRectionType)
{
if(it->GetReactant1() != H2O
&& it->GetReactant1() != H3OpB
&& it->GetReactant1() != OHmB)
{
fReactant1 = it->GetReactant1();
fReactantB1 = it->GetReactant2();
}else
{
fReactant1 = it->GetReactant2();
fReactantB1 = it->GetReactant1();
}
for(const auto& itt : *(it->GetProducts()))
{
if(itt != H3OpB
&& itt != OHmB)
{
fReactant2 = itt;
}else
{
fReactantB2 = itt;
}
}
if(fVerbose > 1) {
G4cout << "Equilibrium processes(ID) " << fRectionType << " : " << fReactant1->GetName()
<< " <=> " << fReactant2->GetName()
<< " Time to Equilibrium : " << fEquilibriumDuration / CLHEP::us
<< " Initial status : " << fAddEquilibrium << G4endl;
}
break ;
}
}
}
void G4ChemEquilibrium::PrintInfo() const
{
G4cout<<"Equilibrium reactions : "<<fReactant1->GetName()
<<" + "<<fReactantB1->GetName()
<<" <=> "<<fReactant2->GetName()
<<" + "<<fReactantB2->GetName()
<<" Status : "<<fAddEquilibrium
<<" from "<<G4BestUnit(fEquilibriumTime,"Time")<<" to "
<<G4BestUnit(fEquilibriumTime + fEquilibriumDuration,"Time")<<G4endl;
}
void G4ChemEquilibrium::SetEquilibrium(Reaction pReaction)
{
if(pReaction->GetReactionType() != fRectionType)
{
std::vector<MolType> molVector;
molVector.push_back(pReaction->GetReactant1());
molVector.push_back(pReaction->GetReactant2());
const G4int nbProducts = pReaction->GetNbProducts();
if (nbProducts) {
for (G4int j = 0; j < nbProducts; ++j) {
auto product = pReaction->GetProduct(j);
molVector.push_back(product);
}
}
for(const auto& it : molVector)
{
if(it == fReactant1 || it == fReactant2 )
{
fAddEquilibrium = true;
fEquilibriumTime = fGlobalTime;
if(fVerbose >1) {
G4cout << "Reaction type : " << pReaction->GetReactionType() << " : "
<< pReaction->GetReactant1()->GetName() << " + "
<< pReaction->GetReactant2()->GetName() << G4endl;
G4cout << "SetEquilibrium : on " << fRectionType << " fEquilibriumTime : "
<< G4BestUnit(fEquilibriumTime, "Time")<<G4endl;
}
break;
}
}
}
}
@@ -0,0 +1,386 @@
//
// ********************************************************************
// * License and Disclaimer *
// * *
// * The Geant4 software is copyright of the Copyright Holders of *
// * the Geant4 Collaboration. It is provided under the terms and *
// * conditions of the Geant4 Software License, included in the file *
// * LICENSE and available at http://cern.ch/geant4/license . These *
// * include a list of copyright holders. *
// * *
// * Neither the authors of this software system, nor their employing *
// * institutes,nor the agencies providing financial support for this *
// * work make any representation or warranty, express or implied, *
// * regarding this software system or assume any liability for its *
// * use. Please see the license in the file LICENSE and URL above *
// * for the full disclaimer and the limitation of liability. *
// * *
// * This code implementation is the result of the scientific and *
// * technical work of the GEANT4 collaboration. *
// * By using, copying, modifying or distributing the software (or *
// * any work based on the software) you agree to acknowledge its *
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
#include "G4DNABornIonisationModel.hh"
#include "G4PhysicalConstants.hh"
#include "G4SystemOfUnits.hh"
#include "G4VAtomDeexcitation.hh"
#include "G4UAtomicDeexcitation.hh"
#include "G4LossTableManager.hh"
#include "G4EmParameters.hh"
#include "G4NistManager.hh"
#include "G4DNACrossSectionDataSet.hh"
#include "G4DNAChemistryManager.hh"
#include "G4DNAMolecularMaterial.hh"
#include "G4DNABornAngle.hh"
#include "G4DNASamplingTable.hh"
#include "G4LogLogInterpolation.hh"
#include "G4DeltaAngle.hh"
#include "G4Log.hh"
#include "G4Exp.hh"
#include "G4Electron.hh"
#include "G4Proton.hh"
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4DNACrossSectionDataSet* G4DNABornIonisationModel::xsdata_e = nullptr;
G4DNACrossSectionDataSet* G4DNABornIonisationModel::xsdata_p = nullptr;
G4DNASamplingTable* G4DNABornIonisationModel::sampling_e = nullptr;
G4DNASamplingTable* G4DNABornIonisationModel::sampling_p = nullptr;
const std::vector<G4double>* G4DNABornIonisationModel::fpWaterDensity = nullptr;
namespace
{
G4double scaleFactor = (1.e-22 / 3.343) * CLHEP::m*CLHEP::m;
G4double tolerance = 10*CLHEP::eV;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4DNABornIonisationModel::G4DNABornIonisationModel(const G4ParticleDefinition*,
const G4String& nam) :
G4VEmModel(nam)
{
SetDeexcitationFlag(true);
// Define default angular generator
SetAngularDistribution(new G4DNABornAngle());
fasterCode = G4EmParameters::Instance()->DNAFast();
if (nullptr == xsdata_p) {
isFirst = true;
LoadData();
}
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4DNABornIonisationModel::~G4DNABornIonisationModel()
{
if (isFirst) {
delete xsdata_e;
xsdata_e = nullptr;
delete xsdata_p;
xsdata_p = nullptr;
delete sampling_e;
sampling_e = nullptr;
delete sampling_p;
sampling_p = nullptr;
}
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4DNABornIonisationModel::LoadData()
{
// initialisation of static data once
G4String fileElectron("dna/sigma_ionisation_e_born");
xsdata_e = new G4DNACrossSectionDataSet(new G4LogLogInterpolation, CLHEP::eV, scaleFactor);
xsdata_e->LoadData(fileElectron);
G4String fileProton("dna/sigma_ionisation_p_born");
xsdata_p = new G4DNACrossSectionDataSet(new G4LogLogInterpolation, CLHEP::eV, scaleFactor);
xsdata_p->LoadData(fileProton);
// to avoid possible threading problem fill this vector only once
auto water = G4NistManager::Instance()->FindMaterial("G4_WATER");
fpWaterDensity =
G4DNAMolecularMaterial::Instance()->GetNumMolPerVolTableFor(water);
G4bool verb = true;
sampling_e = new G4DNASamplingTable(100);
sampling_p = new G4DNASamplingTable(100);
if (fasterCode) {
G4String eb = "/dna/sigmadiff_cumulated_ionisation_e_born.dat";
sampling_e->LoadData(eb, CLHEP::eV, 1.0, verb);
G4String pb = "/dna/sigmadiff_cumulated_ionisation_p_born.dat";
sampling_p->LoadData(pb, CLHEP::eV, 1.0, verb);
} else {
G4String eb = "/dna/sigmadiff_ionisation_e_born.dat";
sampling_e->LoadData(eb, CLHEP::eV, scaleFactor, verb);
G4String pb = "/dna/sigmadiff_ionisation_p_born.dat";
sampling_p->LoadData(pb, CLHEP::eV, scaleFactor, verb);
}
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4DNABornIonisationModel::Initialise(const G4ParticleDefinition* p,
const G4DataVector&)
{
if (isInitialised) { return; }
fParticleChangeForGamma = GetParticleChangeForGamma();
isInitialised = true;
if (p == G4Electron::Electron()) {
fParticle = p;
xsdata = xsdata_e;
sampling = sampling_e;
fLowEnergy = 8*CLHEP::eV;
fHighEnergy = 1*CLHEP::MeV;
feLimitEnergy = 19*CLHEP::eV;
fAbsorptionEnergy = 6*CLHEP::eV;
fMass = CLHEP::electron_mass_c2;
isElectron = true;
} else if (p == G4Proton::Proton()) {
fParticle = p;
xsdata = xsdata_p;
sampling = sampling_p;
fLowEnergy = 100*CLHEP::keV;
fHighEnergy = 100*CLHEP::MeV;
fpLimitEnergy = 70*CLHEP::MeV;
fAbsorptionEnergy = 50*CLHEP::eV;
fMass = CLHEP::proton_mass_c2;
isElectron = false;
} else {
G4ExceptionDescription ed;
ed << "Born ionisation model is used for " << p->GetParticleName();
G4Exception("G4DNABornIonisationModel::Initialise","em0003",
FatalException, ed, " it is not available.");
}
verbose = G4EmParameters::Instance()->WorkerVerbose();
// defined stationary mode
statCode = G4EmParameters::Instance()->DNAStationary();
// initialise atomic de-excitation
if (!statCode)
fAtomDeexcitation = G4LossTableManager::Instance()->AtomDeexcitation();
// chemistry
auto chem = G4DNAChemistryManager::Instance();
if (chem->IsChemistryActivated()) {
fChemistry = chem;
}
InitialiseIntegrator(0.1, 0.25, 1.05, 1*CLHEP::eV, 0.2*CLHEP::eV, 10*CLHEP::keV);
if (verbose > 1) {
G4cout << "Born ionisation model is initialized for "
<< fParticle->GetParticleName() << G4endl;
}
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4DNABornIonisationModel::StartTracking(G4Track* track)
{
fTrack = track;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4double G4DNABornIonisationModel::CrossSectionPerVolume(const G4Material* material,
const G4ParticleDefinition*,
G4double ekin, G4double, G4double)
{
// check if model is applicable for given material
G4double density = (material->GetIndex() < fpWaterDensity->size())
? (*fpWaterDensity)[material->GetIndex()] : 0.0;
if (0.0 == density) { return 0.0; }
// check on kinetic energy (not scaled energy) to stop low-energy ion
const G4double xSecMax = 1.e+10*CLHEP::barn;
if (ekin < fAbsorptionEnergy) { return xSecMax; }
G4double e = std::min(ekin, fHighEnergy);
G4double sigma = (e > fLowEnergy) ? xsdata->FindValue(e)
: xsdata->FindValue(fLowEnergy) * e / fLowEnergy;
sigma *= density;
// ICRU49 electronic SP scaling - ZF, SI
if (!isElectron && spScaling && e < fpLimitEnergy) {
const G4double A = 1.39241700556072800000e-9;
const G4double B = -8.52610412942622630000e-2;
sigma *= G4Exp(A*(ekin/CLHEP::eV) + B);
}
if (verbose > 1) {
G4cout << "G4DNABornIonisationModel for " << fParticle->GetParticleName()
<< " Ekin(keV)=" << ekin/CLHEP::keV
<< " sigma(cm^2)=" << sigma/CLHEP::cm2 << G4endl;
}
return sigma;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4DNABornIonisationModel::SampleSecondaries(std::vector<G4DynamicParticle*>* fvect,
const G4MaterialCutsCouple* couple,
const G4DynamicParticle* dynParticle,
G4double, G4double)
{
fPrimaryEnergy = dynParticle->GetKineticEnergy();
// proton shoud be stopped - check on kinetic energy
// electrons never have such low energy
if (fPrimaryEnergy <= fAbsorptionEnergy) {
fParticleChangeForGamma->SetProposedKineticEnergy(0.);
fParticleChangeForGamma->ProposeTrackStatus(fStopButAlive);
fParticleChangeForGamma->ProposeLocalEnergyDeposit(fPrimaryEnergy);
return;
}
fSelectedShell = SelectShell();
G4double bindingEnergy = waterStructure.IonisationEnergy(fSelectedShell);
//SI: additional protection if tcs interpolation method is modified
if (fPrimaryEnergy < bindingEnergy) { return; }
// compute max energy
if (isElectron) {
fMaxEnergy = 0.5*(fPrimaryEnergy - bindingEnergy);
} else {
G4double tau = fPrimaryEnergy/fMass;
fMaxEnergy = 2.0*CLHEP::electron_mass_c2*tau*(tau + 2.0);
}
// SI: The following protection is necessary to avoid infinite loops :
// e- ionisation cross section has non zero partial xs at 18 eV for shell 2.
// e- has zero cumulated partial xs at 18 eV for shell 2.
// This is due to the fact that the max allowed transfered energy is
// (18+10.79)/2=17.025 eV and only transfered energies strictly above this
// value have non zero partial cross section starting at transition energy 17.12 eV.
if (fasterCode && isElectron && 2 == fSelectedShell && fPrimaryEnergy < feLimitEnergy) {
do {
fSelectedShell = SelectShell();
} while (2 == fSelectedShell);
}
G4double esec = fasterCode ? SampleCumulative() : SampleDifferential();
G4double esum = 0.0;
// sample deexcitation
// here we assume that H2O electronic levels are the same as Oxygen.
// this can be considered true with a rough 10% error in energy on K-shell,
G4int Z = 8;
G4ThreeVector deltaDir =
GetAngularDistribution()->SampleDirectionForShell(dynParticle, esec, Z,
fSelectedShell,
couple->GetMaterial());
// SI: only atomic deexcitation from K shell is considered
if (fAtomDeexcitation != nullptr && fSelectedShell == 4) {
auto as = G4AtomicShellEnumerator(0);
auto ashell = fAtomDeexcitation->GetAtomicShell(Z, as);
fAtomDeexcitation->GenerateParticles(fvect, ashell, Z, 0, 0);
// compute energy sum from de-excitation
for (auto const & ptr : *fvect) {
esum += ptr->GetKineticEnergy();
}
}
// check energy balance
// remaining excitation energy of water molecule
G4double exc = std::max(bindingEnergy - esum, 0.0);
// remaining projectile energy
G4double scatteredEnergy = fPrimaryEnergy - bindingEnergy - esec;
if (scatteredEnergy < -tolerance || exc < -tolerance) {
G4cout << "G4DNABornIonisationModel::SampleSecondaries: "
<< "final E(keV)=" << scatteredEnergy/CLHEP::keV << " Ein(keV)="
<< fPrimaryEnergy/CLHEP::keV << " " << fParticle->GetParticleName()
<< " Edelta(keV)=" << esec/CLHEP::keV << " MeV, Exc(keV)=" << exc/CLHEP::keV
<< G4endl;
}
scatteredEnergy = std::max(scatteredEnergy, 0.0);
// projectile
if (!statCode) {
fParticleChangeForGamma->SetProposedKineticEnergy(scatteredEnergy);
fParticleChangeForGamma->ProposeLocalEnergyDeposit(exc);
} else {
fParticleChangeForGamma->SetProposedKineticEnergy(fPrimaryEnergy);
fParticleChangeForGamma->ProposeLocalEnergyDeposit(fPrimaryEnergy - scatteredEnergy);
}
// delta-electron
auto dp = new G4DynamicParticle(G4Electron::Electron(), deltaDir, esec);
fvect->push_back(dp);
// create radical
if (nullptr != fChemistry) {
fChemistry->CreateWaterMolecule(eIonizedMolecule, fSelectedShell, fTrack);
}
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4int G4DNABornIonisationModel::SelectShell()
{
G4double sum = 0.0;
G4double xs;
G4double e = std::min(fPrimaryEnergy, fHighEnergy);
for (G4int i=0; i<5; ++i) {
auto ptr = xsdata->GetComponent(i);
xs = (e > fLowEnergy) ? ptr->FindValue(e)
: ptr->FindValue(fLowEnergy) * e/fLowEnergy;
sum += xs;
fTemp[i] = sum;
}
sum *= G4UniformRand();
for (G4int i=0; i<5; ++i) {
if (sum <= fTemp[i]) { return i; }
}
return 0;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4double G4DNABornIonisationModel::SampleCumulative()
{
G4double e = sampling->SampleCumulative(fPrimaryEnergy, fSelectedShell);
if (verbose > 1) {
G4cout << "G4DNABornIonisationModel::SampleCumulative: "
<< fParticle->GetParticleName()
<< " Ekin(keV)=" << fPrimaryEnergy/CLHEP::keV
<< " Ee(keV)=" << e/CLHEP::keV << G4endl;
}
return e;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4double G4DNABornIonisationModel::SampleDifferential()
{
G4double xs = ComputeIntegral(0.0, fMaxEnergy);
G4double e = (xs > 0.0) ? SampleValue() : G4UniformRand()*fMaxEnergy;
if (verbose > 1) {
G4cout << "G4DNABornIonisationModel::SampleDifferential: "
<< fParticle->GetParticleName()
<< " Ekin(keV)=" << fPrimaryEnergy/CLHEP::keV
<< " Ee(keV)=" << e/CLHEP::keV << G4endl;
}
return e;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4double G4DNABornIonisationModel::ProbabilityDensityFunction(G4double ekin)
{
return sampling->GetValue(fPrimaryEnergy, ekin, fSelectedShell);
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
@@ -29,6 +29,7 @@
#include "G4PhysicalConstants.hh"
#include "G4SystemOfUnits.hh"
#include "G4UAtomicDeexcitation.hh"
#include "G4EmParameters.hh"
#include "G4LossTableManager.hh"
#include "G4DNAChemistryManager.hh"
#include "G4DNAMolecularMaterial.hh"
@@ -68,17 +69,7 @@ G4VEmModel(nam)
// Define default angular generator
SetAngularDistribution(new G4DNABornAngle());
// Selection of computation method
fasterCode = false;
// Selection of stationary mode
statCode = false;
// Selection of SP scaling
spScaling = true;
fasterCode = G4EmParameters::Instance()->DNAFast();
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
@@ -123,7 +114,7 @@ void G4DNABornIonisationModel1::Initialise(const G4ParticleDefinition* particle,
G4String proton;
G4double scaleFactor = (1.e-22 / 3.343) * m*m;
const char *path = G4FindDataDir("G4LEDATA");
// *** ELECTRON
@@ -295,25 +286,36 @@ void G4DNABornIonisationModel1::Initialise(const G4ParticleDefinition* particle,
<< G4endl;
}
// Initialize water density pointer
if (isInitialised) { return; }
fParticleChangeForGamma = GetParticleChangeForGamma();
// Initialize water density pointer
fpMolWaterDensity = G4DNAMolecularMaterial::Instance()->
GetNumMolPerVolTableFor(G4Material::GetMaterial("G4_WATER"));
// AD
statCode = G4EmParameters::Instance()->DNAStationary();
fAtomDeexcitation = G4LossTableManager::Instance()->AtomDeexcitation();
// AD
if (!statCode)
fAtomDeexcitation = G4LossTableManager::Instance()->AtomDeexcitation();
//
if (isInitialised)
{ return;}
fParticleChangeForGamma = GetParticleChangeForGamma();
// chemistry
auto chem = G4DNAChemistryManager::Instance();
if (chem->IsChemistryActivated()) {
fChemistry = chem;
}
isInitialised = true;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4DNABornIonisationModel1::StartTracking(G4Track* track)
{
fTrack = track;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4double G4DNABornIonisationModel1::CrossSectionPerVolume(const G4Material* material,
const G4ParticleDefinition* particleDefinition,
G4double ekin,
@@ -450,20 +452,19 @@ void G4DNABornIonisationModel1::SampleSecondaries(std::vector<G4DynamicParticle*
G4int ionizationShell = 0;
if (!fasterCode) ionizationShell = RandomSelect(k,particleName);
// SI: The following protection is necessary to avoid infinite loops :
// sigmadiff_ionisation_e_born.dat has non zero partial xs at 18 eV for shell 3 (ionizationShell ==2)
// sigmadiff_cumulated_ionisation_e_born.dat has zero cumulated partial xs at 18 eV for shell 3 (ionizationShell ==2)
// this is due to the fact that the max allowed transfered energy is (18+10.79)/2=17.025 eV and only transfered energies
// strictly above this value have non zero partial xs in sigmadiff_ionisation_e_born.dat (starting at trans = 17.12 eV)
if (fasterCode)
do
{
if (!fasterCode) {
ionizationShell = RandomSelect(k,particleName);
} while (k<19*eV && ionizationShell==2 && particle->GetDefinition()==G4Electron::ElectronDefinition());
} else {
do {
ionizationShell = RandomSelect(k,particleName);
} while (k<19*eV && ionizationShell==2 && particle->GetDefinition()==G4Electron::ElectronDefinition());
}
G4double bindingEnergy = 0;
bindingEnergy = waterStructure.IonisationEnergy(ionizationShell);
@@ -481,8 +482,6 @@ void G4DNABornIonisationModel1::SampleSecondaries(std::vector<G4DynamicParticle*
{
secondaryKinetic = RandomizeEjectedElectronEnergyFromCumulatedDcs(particle->GetDefinition(),k,ionizationShell);
}
//
G4int Z = 8;
G4ThreeVector deltaDirection =
@@ -587,17 +586,10 @@ void G4DNABornIonisationModel1::SampleSecondaries(std::vector<G4DynamicParticle*
fParticleChangeForGamma->ProposeLocalEnergyDeposit(k-scatteredEnergy);
}
// TEST //////////////////////////
// if (secondaryKinetic<0) abort();
// if (scatteredEnergy<0) abort();
// if (k-scatteredEnergy-secondaryKinetic-deexSecEnergy<0) abort();
// if (k-scatteredEnergy<0) abort();
/////////////////////////////////
const G4Track * theIncomingTrack = fParticleChangeForGamma->GetCurrentTrack();
G4DNAChemistryManager::Instance()->CreateWaterMolecule(eIonizedMolecule,
ionizationShell,
theIncomingTrack);
// create radical
if (nullptr != fChemistry) {
fChemistry->CreateWaterMolecule(eIonizedMolecule, ionizationShell, fTrack);
}
}
}
@@ -696,50 +688,6 @@ G4double G4DNABornIonisationModel1::RandomizeEjectedElectronEnergy(G4ParticleDef
return 0;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
// The following section is not used anymore but is kept for memory
// GetAngularDistribution()->SampleDirectionForShell is used instead
/*
void G4DNABornIonisationModel1::RandomizeEjectedElectronDirection(G4ParticleDefinition* particleDefinition,
G4double k,
G4double secKinetic,
G4double & cosTheta,
G4double & phi )
{
if (particleDefinition == G4Electron::ElectronDefinition())
{
phi = twopi * G4UniformRand();
if (secKinetic < 50.*eV) cosTheta = (2.*G4UniformRand())-1.;
else if (secKinetic <= 200.*eV)
{
if (G4UniformRand() <= 0.1) cosTheta = (2.*G4UniformRand())-1.;
else cosTheta = G4UniformRand()*(std::sqrt(2.)/2);
}
else
{
G4double sin2O = (1.-secKinetic/k) / (1.+secKinetic/(2.*electron_mass_c2));
cosTheta = std::sqrt(1.-sin2O);
}
}
else if (particleDefinition == G4Proton::ProtonDefinition())
{
G4double maxSecKinetic = 4.* (electron_mass_c2 / proton_mass_c2) * k;
phi = twopi * G4UniformRand();
// cosTheta = std::sqrt(secKinetic / maxSecKinetic);
// Restriction below 100 eV from Emfietzoglou (2000)
if (secKinetic>100*eV) cosTheta = std::sqrt(secKinetic / maxSecKinetic);
else cosTheta = (2.*G4UniformRand())-1.;
}
}
*/
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4double G4DNABornIonisationModel1::DifferentialCrossSection(G4ParticleDefinition * particleDefinition,
G4double k,
@@ -32,6 +32,7 @@
#include "G4LossTableManager.hh"
#include "G4DNAChemistryManager.hh"
#include "G4DNAMolecularMaterial.hh"
#include "G4EmParameters.hh"
#include "G4DNABornAngle.hh"
#include "G4DeltaAngle.hh"
#include "G4Exp.hh"
@@ -91,13 +92,7 @@ G4VEmModel(nam)
G4DNABornIonisationModel2::~G4DNABornIonisationModel2()
{
// Cross section
delete fTableData;
// Final state
delete fTableData;
fVecm.clear();
}
@@ -248,13 +243,14 @@ void G4DNABornIonisationModel2::Initialise(const G4ParticleDefinition* particle,
fpMolWaterDensity = G4DNAMolecularMaterial::Instance()->
GetNumMolPerVolTableFor(G4Material::GetMaterial("G4_WATER"));
// AD
fAtomDeexcitation = G4LossTableManager::Instance()->AtomDeexcitation();
if (isInitialised)
{ return;}
fParticleChangeForGamma = GetParticleChangeForGamma();
statCode = G4EmParameters::Instance()->DNAStationary();
if (!statCode)
fAtomDeexcitation = G4LossTableManager::Instance()->AtomDeexcitation();
isInitialised = true;
}
@@ -44,79 +44,58 @@ G4DNAEventScheduler::G4DNAEventScheduler()
, fpUpdateSystem(new G4DNAUpdateSystemModel())
{}
void G4DNAEventScheduler::ClearAndReChargeCounter()
{
fCounterMap.clear();
if(fTimeToRecord.empty())
{
G4String WarMessage = "fTimeToRecord is empty ";
G4Exception("G4DNAEventScheduler::ClearAndReChargeCounter()",
"TimeToRecord is empty", JustWarning, WarMessage);
}
fLastRecoredTime = fTimeToRecord.begin();
if(G4VMoleculeCounter::Instance()->InUse()) // copy from MoleculeCounter
{
G4MoleculeCounter::RecordedMolecules species;
species = G4MoleculeCounter::Instance()->GetRecordedMolecules();
if(species.get() == nullptr)
{
return;
}
if(species->empty())
{
G4MoleculeCounter::Instance()->ResetCounter();
return;
}
for(auto time_mol : fTimeToRecord)
{
if(time_mol > fStartTime)
{
continue;
}
for(auto molecule : *species)
{
G4int n_mol = G4MoleculeCounter::Instance()->GetNMoleculesAtTime(
molecule, time_mol);
if(n_mol < 0)
{
G4cerr << "G4DNAEventScheduler::ClearAndReChargeCounter() ::N "
"molecules not valid < 0 "
<< G4endl;
G4Exception("", "N<0", FatalException, "");
}
fCounterMap[time_mol][molecule] = n_mol;
}
fLastRecoredTime++;
}
G4MoleculeCounter::Instance()->ResetCounter(); // reset
G4MoleculeCounter::Instance()->Use(false); // no more used
}
else
{
G4ExceptionDescription exceptionDescription;
exceptionDescription << "G4VMoleculeCounter is not used";
G4Exception("G4DNAEventScheduler::ClearAndReChargeCounter()",
"G4DNAEventScheduler010", JustWarning, exceptionDescription);
}
}
[[maybe_unused]] void G4DNAEventScheduler::AddTimeToRecord(const G4double& time)
{
if(fTimeToRecord.find(time) == fTimeToRecord.end())
{
fTimeToRecord.insert(time);
}
fLastRecoredTime = fTimeToRecord.begin();
}
G4DNAEventScheduler::~G4DNAEventScheduler() = default;
void G4DNAEventScheduler::Voxelizing()
void G4DNAEventScheduler::Voxelizing(const G4DNABoundingBox& boundingBox)
{
auto pMainList = G4ITTrackHolder::Instance()->GetMainList();
std::map<G4VDNAMesh::Index, MapList> TrackKeyMap;
if(fpMesh == nullptr){
fpMesh = std::make_unique<G4DNAMesh>(boundingBox, fPixel);
}else
{
auto newMesh = new G4DNAMesh(fpMesh->GetBoundingBox(), fPixel);
auto begin = fpMesh->begin();//old mesh, should be homogeneous
auto end = fpMesh->end();
for(; begin != end; begin++)
{
auto numberOfBoxes = fPixel*fPixel*fPixel;
const auto& mapData = std::get<2>(*begin);
for(auto it : mapData)
{
if(it.second == 0) continue;
G4int base_mol = std::floor((G4double)it.second / numberOfBoxes);
G4int remainder = (G4int)it.second % numberOfBoxes;
for(G4int i = 0; i < remainder; i++)
{
auto oldIndex = std::get<0>(*begin);
auto idx = newMesh->GetRandomIndex(oldIndex, fpMesh->GetResolution());
TrackKeyMap[idx][it.first] += base_mol + 1;
}
}
}
fpMesh.reset(newMesh);
}
if(!CheckingReactionRadius(fpMesh->GetResolution()))
{
G4String WarMessage = "resolution is not good : " +
std::to_string(fpMesh->GetResolution() / nm);
G4Exception("G4DNAEventScheduler::InitializeInMesh()", "WrongResolution",
JustWarning, WarMessage);
}
auto pMainList = G4ITTrackHolder::Instance()->GetMainList();
for(auto track : *pMainList)
{
auto molType = GetMolecule(track)->GetMolecularConfiguration();
@@ -146,7 +125,9 @@ void G4DNAEventScheduler::Voxelizing()
{
TrackKeyMap[key][molType] = 1;
}
track->SetTrackStatus(fStopAndKill);//kill the track
}
G4ITReactionSet::Instance()->CleanAllReaction();
for(auto& it : TrackKeyMap)
{
@@ -212,9 +193,12 @@ void G4DNAEventScheduler::Reset()
fRunning = true;
fReactionNumber = 0;
fJumpingNumber = 0;
fpEventSet->RemoveEventSet();
fpMesh->Reset();
if(fpMesh != nullptr) {
fpMesh->Reset();
fpMesh.reset();
//reset for each event
}
fpGillespieReaction->ResetEquilibrium();
}
@@ -224,16 +208,6 @@ void G4DNAEventScheduler::Initialize(const G4DNABoundingBox& boundingBox,
if(!fInitialized)
{
fPixel = pixel;
fpMesh = std::make_unique<G4DNAMesh>(boundingBox, pixel);
if(!CheckingReactionRadius(fpMesh->GetResolution()))
{
G4String WarMessage = "resolution is not good : " +
std::to_string(fpMesh->GetResolution() / nm);
G4Exception("G4DNAEventScheduler::InitializeInMesh()", "WrongResolution",
JustWarning, WarMessage);
}
// Scavenger();
auto pScavengerMaterial = dynamic_cast<G4DNAScavengerMaterial*>(
@@ -250,14 +224,17 @@ void G4DNAEventScheduler::Initialize(const G4DNABoundingBox& boundingBox,
}
}
Voxelizing();
Voxelizing(boundingBox);
fEndTime = std::min(G4ITTrackHolder::Instance()->GetNextTime(), G4Scheduler::Instance()->GetEndTime()-1*ps);
//G4cout<<"fEndTime" <<fEndTime<<" G4ITTrackHolder::Instance()->GetNextTime() : "<<G4ITTrackHolder::Instance()->GetNextTime()<<G4endl;
fpGillespieReaction->SetVoxelMesh(*fpMesh);
fpGillespieReaction->SetEventSet(fpEventSet.get());
fpGillespieReaction->SetTimeStep(0);// reset fTimeStep = 0 in fpGillespieReaction
fpGillespieReaction->Initialize();
fpGillespieReaction->CreateEvents();
fpUpdateSystem->SetMesh(fpMesh.get());
ClearAndReChargeCounter();
fInitialized = true;
}
@@ -305,6 +282,8 @@ void G4DNAEventScheduler::ResetInMesh()
G4double G4DNAEventScheduler::GetStartTime() const { return fStartTime; }
G4double G4DNAEventScheduler::GetGlobalTime() const { return fGlobalTime; }
G4double G4DNAEventScheduler::GetEndTime() const { return fEndTime; }
[[maybe_unused]] G4double G4DNAEventScheduler::GetTimeStep() const
@@ -338,6 +317,7 @@ void G4DNAEventScheduler::Run()
{
RunInMesh();
}
fInitialized = false;
if(fVerbose > 2)
{
if(!fRunning)
@@ -361,7 +341,6 @@ void G4DNAEventScheduler::Run()
}
G4cout << " Computing Time : " << localtimer << G4endl;
}
Reset();
}
void G4DNAEventScheduler::RunInMesh()
@@ -377,7 +356,7 @@ void G4DNAEventScheduler::RunInMesh()
<< " the Mesh has " << fPixel << " x " << fPixel << " x " << fPixel
<< " voxels with Resolution " << G4BestUnit(resolution, "Length")
<< " during next "
<< G4BestUnit(resolution * resolution * C / (6 * D), "Time")
<< G4BestUnit(fGlobalTime + resolution * resolution * C / (6 * D), "Time")
<< G4endl;
}
@@ -501,6 +480,8 @@ void G4DNAEventScheduler::Stepping() // this event loop
// get selected time step
fTimeStep = (*selected)->GetTime();
if(fTimeStep + fStartTime >fEndTime){ return;}
// selected data
auto pJumping = (*selected)->GetJumpingData();
auto pReaction = (*selected)->GetReactionData();
@@ -564,9 +545,15 @@ void G4DNAEventScheduler::SetEndTime(const G4double& endTime)
void G4DNAEventScheduler::RecordTime()
{
if(fLastRecoredTime == fTimeToRecord.end())
{
return;
}
auto recordTime = *fLastRecoredTime;
if(fGlobalTime >= recordTime && fCounterMap[recordTime].empty())
{
if(fpMesh == nullptr) return;
//G4cout<<"recordTime for meso: "<<recordTime<<" fGlobalTime : "<<fGlobalTime<<G4endl;
auto begin = fpMesh->begin();
auto end = fpMesh->end();
for(; begin != end; begin++)
@@ -671,4 +658,63 @@ void G4DNAEventScheduler::LastRegisterForCounter()
}
}
}
void G4DNAEventScheduler::ParticleBasedCounter() {
if(fLastRecoredTime == fTimeToRecord.end())
{
return;
}
auto recordTime = *fLastRecoredTime;
if (recordTime < G4Scheduler::Instance()->GetGlobalTime()) {
//check meso if exist
if(fpMesh != nullptr){
//G4cout<<"there is a mesh"<<G4endl;
auto begin = fpMesh->begin();
auto end = fpMesh->end();
for(; begin != end; begin++)
{
const auto& mapData = std::get<2>(*begin);
if(mapData.empty())
{
continue;
}
for(const auto& it : mapData)
{
fCounterMap[recordTime][it.first] += it.second;
}
}
}
//then particle based
auto pMainList = G4ITTrackHolder::Instance()->GetMainList();
for (auto track: *pMainList) {
auto molType = GetMolecule(track)->GetMolecularConfiguration();
auto pScavengerMaterial =
dynamic_cast<G4DNAScavengerMaterial *>(G4Scheduler::Instance()->GetScavengerMaterial());
if (pScavengerMaterial != nullptr
&& pScavengerMaterial->find(molType)) // avoid voxelize the scavenger
{
continue;
}
fCounterMap[recordTime][molType]++;
}
fLastRecoredTime++;
//PrintRecordTime();
}
}
void G4DNAEventScheduler::ResetCounter()
{
fCounterMap.clear();
if(fTimeToRecord.empty())
{
G4String WarMessage = "fTimeToRecord is empty ";
G4Exception("G4DNAEventScheduler::ClearAndReChargeCounter()",
"TimeToRecord is empty", JustWarning, WarMessage);
}
fLastRecoredTime = fTimeToRecord.begin();
}
@@ -44,6 +44,7 @@
#include "G4ITTrackHolder.hh"
#include "G4ITReaction.hh"
#include "G4Scheduler.hh"
#include "G4MoleculeCounterManager.hh"
using namespace std;
@@ -399,7 +400,10 @@ std::unique_ptr<G4ITReactionChange> G4DNAIRT::MakeReaction(const G4Track& trackA
const auto pMoleculeA = GetMolecule(trackA)->GetMolecularConfiguration();
const auto pMoleculeB = GetMolecule(trackB)->GetMolecularConfiguration();
const auto pReactionData = fMolReactionTable->GetReactionData(pMoleculeA, pMoleculeB);
// Notify molecule (reaction) counter
if (G4MoleculeCounterManager::Instance()->GetIsActive()) {
G4MoleculeCounterManager::Instance()->RecordReaction(pReactionData, trackA.GetGlobalTime());
}
G4double globalTime = G4Scheduler::Instance()->GetGlobalTime();
G4double effectiveReactionRadius = pReactionData->GetEffectiveReactionRadius();
@@ -45,10 +45,11 @@ using namespace std;
using namespace CLHEP;
G4DNAIndependentReactionTimeStepper::Utils::Utils(const G4Track& trackA, const G4Track& trackB)
: fTrackA(trackA), fTrackB(trackB)
: fpTrackA(const_cast<G4Track*>(&trackA)), fpTrackB(const_cast<G4Track*>(&trackB))
{
fpMoleculeA = GetMolecule(trackA);
fpMoleculeB = GetMolecule(trackA);
fpMoleculeB = GetMolecule(trackB);
fUserMinTimeStep = 1 * CLHEP::ps;
}
G4DNAIndependentReactionTimeStepper::G4DNAIndependentReactionTimeStepper()
@@ -58,30 +59,31 @@ G4DNAIndependentReactionTimeStepper::G4DNAIndependentReactionTimeStepper()
void G4DNAIndependentReactionTimeStepper::Prepare()
{
G4VITTimeStepComputer::Prepare();
fSampledPositions.clear();
BuildChemicalMoleculeFinder()
//fVerbose = G4Scheduler::Instance()->GetVerbose();
if (G4Scheduler::Instance()->IsInteractionStep()) {
fReactionSet->CleanAllReaction();
fIsInitialized = false;
fSampledPositions.clear();
fSecondaries.clear();
InitializeForNewTrack();
}
}
void G4DNAIndependentReactionTimeStepper::InitializeForNewTrack()
{
if (fReactants != nullptr) {
fReactants.reset();
}
fSampledMinTimeStep = DBL_MAX;
fHasAlreadyReachedNullTime = false;
fCheckedTracks.clear();
BuildChemicalMoleculeFinder()
}
G4double G4DNAIndependentReactionTimeStepper::CalculateStep(const G4Track& trackA,
const G4double& userMinTimeStep)
const G4double& /*userMinTimeStep*/)
{
auto pMoleculeA = GetMolecule(trackA);
InitializeForNewTrack();
fUserMinTimeStep = userMinTimeStep;
fSampledMinTimeStep = DBL_MAX;
fCheckedTracks.insert(trackA.GetTrackID());
#ifdef G4VERBOSE
if (fVerbose != 0) {
if (fVerbose > 1) {
G4cout << "________________________________________________________________"
"_______"
<< G4endl;
@@ -96,7 +98,7 @@ G4double G4DNAIndependentReactionTimeStepper::CalculateStep(const G4Track& track
const auto pReactantList = fMolecularReactionTable->CanReactWith(pMolConfA);
if (pReactantList == nullptr) {
if(fVerbose > 1) {
if (fVerbose > 1) {
G4ExceptionDescription msg;
msg << "G4DNAIndependentReactionTimeStepper::CalculateStep will return infinity "
"for the reaction because the molecule "
@@ -111,7 +113,7 @@ G4double G4DNAIndependentReactionTimeStepper::CalculateStep(const G4Track& track
auto nbReactives = (G4int)pReactantList->size();
if (nbReactives == 0) {
if(fVerbose != 0){
if (fVerbose > 1) {
G4ExceptionDescription msg;
msg << "G4DNAIndependentReactionTimeStepper::CalculateStep will "
"return infinity "
@@ -125,13 +127,10 @@ G4double G4DNAIndependentReactionTimeStepper::CalculateStep(const G4Track& track
}
return DBL_MAX;
}
fReactants = std::make_shared<vector<G4Track*>>();
fReactionModel->Initialise(pMolConfA, trackA);
for (G4int i = 0; i < nbReactives; ++i) {
auto pMoleculeB = (*pReactantList)[i];
G4int key = pMoleculeB->GetMoleculeID();
// fRCutOff = G4IRTUtils::GetRCutOff(1 * ps);
fRCutOff = G4IRTUtils::GetRCutOff();
//______________________________________________________________
// Retrieve reaction range
@@ -157,115 +156,107 @@ G4double G4DNAIndependentReactionTimeStepper::CalculateStep(const G4Track& track
"::CalculateStep()",
"G4DNAIndependentReactionTimeStepper007", FatalException, exceptionDescription);
}
if (fCheckedTracks.find(pTrackB->GetTrackID()) != fCheckedTracks.end()) {
continue;
}
Utils utils(trackA, *pTrackB);
auto pMolB = GetMolecule(pTrackB);
auto pMolConfB = pMolB->GetMolecularConfiguration();
G4double distance = (trackA.GetPosition() - pTrackB->GetPosition()).mag();
if (distance * distance < Reff * Reff) {
auto reactionData = fMolecularReactionTable->GetReactionData(pMolConfA, pMolConfB);
if (G4Scheduler::Instance()->GetGlobalTime() == G4Scheduler::Instance()->GetStartTime()) {
if (reactionData->GetProbability() > G4UniformRand()) {
fSampledMinTimeStep = 0.;
}
}
}
else {
if (fCheckedTracks.find(pTrackB->GetTrackID()) != fCheckedTracks.end()) {
G4double tempMinET = GetTimeToEncounter(trackA, *pTrackB);
if (tempMinET < 0 || tempMinET > G4Scheduler::Instance()->GetEndTime()) {
continue;
}
Utils utils(trackA, *pTrackB);
auto pMolB = GetMolecule(pTrackB);
auto pMolConfB = pMolB->GetMolecularConfiguration();
G4double distance = (trackA.GetPosition() - pTrackB->GetPosition()).mag();
if (distance * distance < Reff * Reff) {
auto reactionData = fMolecularReactionTable->GetReactionData(pMolConfA, pMolConfB);
if (G4Scheduler::Instance()->GetGlobalTime() == G4Scheduler::Instance()->GetStartTime()) {
if (reactionData->GetProbability() > G4UniformRand()) {
if (!fHasAlreadyReachedNullTime) {
fReactants->clear();
fHasAlreadyReachedNullTime = true;
}
fSampledMinTimeStep = 0.;
CheckAndRecordResults(utils);
}
}
}
else {
G4double tempMinET = GetTimeToEncounter(trackA, *pTrackB);
if (tempMinET < 0 || tempMinET > G4Scheduler::Instance()->GetEndTime()) {
continue;
}
if (tempMinET >= fSampledMinTimeStep) {
continue;
}
fSampledMinTimeStep = tempMinET;
fReactants->clear();
CheckAndRecordResults(utils);
fSampledMinTimeStep = tempMinET;
if (tempMinET < fUserMinTimeStep) {
fSampledMinTimeStep = fUserMinTimeStep;
}
}
CheckAndRecordResults(fSampledMinTimeStep, utils);
}
}
#ifdef G4VERBOSE
if (fVerbose != 0) {
G4cout << "G4DNAIndependentReactionTimeStepper::CalculateStep will finally "
"return :"
<< G4BestUnit(fSampledMinTimeStep, "Time") << G4endl;
if (fVerbose > 1) {
G4cout << "Selected reactants for trackA: " << pMoleculeA->GetName() << " ("
<< trackA.GetTrackID() << ") are: ";
vector<G4Track*>::iterator it;
for (it = fReactants->begin(); it != fReactants->end(); it++) {
G4Track* trackB = *it;
G4cout << GetMolecule(trackB)->GetName() << " (" << trackB->GetTrackID() << ") \t ";
}
G4cout << G4endl;
}
}
#endif
return fSampledMinTimeStep;
}
void G4DNAIndependentReactionTimeStepper::CheckAndRecordResults(const Utils& utils)
void G4DNAIndependentReactionTimeStepper::CheckAndRecordResults(G4double reactionTime,
const Utils& utils)
{
if (utils.fTrackB.GetTrackStatus() != fAlive) {
if (utils.fpTrackB->GetTrackStatus() != fAlive) {
return;
}
if (&utils.fTrackB == &utils.fTrackA) {
if (&utils.fpTrackB == &utils.fpTrackA) {
G4ExceptionDescription msg;
msg << "A track is reacting with itself"
" (which is impossible) ie fpTrackA == trackB"
<< G4endl;
" (which is impossible) ie fpTrackA == trackB"
<< G4endl;
msg << "Molecule A is of type : " << utils.fpMoleculeA->GetName()
<< " with trackID : " << utils.fTrackA.GetTrackID()
<< " and B : " << utils.fpMoleculeB->GetName()
<< " with trackID : " << utils.fTrackB.GetTrackID() << G4endl;
<< " with trackID : " << utils.fpTrackA->GetTrackID()
<< " and B : " << utils.fpMoleculeB->GetName()
<< " with trackID : " << utils.fpTrackB->GetTrackID() << G4endl;
G4Exception("G4DNAIndependentReactionTimeStepper::RetrieveResults",
"G4DNAIndependentReactionTimeStepper003", FatalErrorInArgument,
msg);
"G4DNAIndependentReactionTimeStepper003", FatalErrorInArgument, msg);
}
if (fabs(utils.fTrackB.GetGlobalTime() - utils.fTrackA.GetGlobalTime())
> utils.fTrackA.GetGlobalTime() * (1. - 1. / 100))
if (fabs(utils.fpTrackB->GetGlobalTime() - utils.fpTrackA->GetGlobalTime())
> utils.fpTrackA->GetGlobalTime() * (1. - 1. / 100))
{
// DEBUG
G4ExceptionDescription msg;
msg << "The interacting tracks are not synchronized in time" << G4endl;
msg << "trackB->GetGlobalTime() != fpTrackA.GetGlobalTime()" << G4endl;
msg << "fpTrackA : trackID : " << utils.fTrackA.GetTrackID()
<< "\t Name :" << utils.fpMoleculeA->GetName()
<< "\t fpTrackA->GetGlobalTime() = "
<< G4BestUnit(utils.fTrackA.GetGlobalTime(), "Time") << G4endl;
msg << "fpTrackA : trackID : " << utils.fpTrackA->GetTrackID()
<< "\t Name :" << utils.fpMoleculeA->GetName()
<< "\t fpTrackA->GetGlobalTime() = " << G4BestUnit(utils.fpTrackA->GetGlobalTime(), "Time")
<< G4endl;
msg << "trackB : trackID : " << utils.fTrackB.GetTrackID()
<< "\t Name :" << utils.fpMoleculeB->GetName()
<< "\t trackB->GetGlobalTime() = "
<< G4BestUnit(utils.fTrackB.GetGlobalTime(), "Time") << G4endl;
msg << "trackB : trackID : " << utils.fpTrackB->GetTrackID()
<< "\t Name :" << utils.fpMoleculeB->GetName()
<< "\t trackB->GetGlobalTime() = " << G4BestUnit(utils.fpTrackB->GetGlobalTime(), "Time")
<< G4endl;
G4Exception("G4DNAIndependentReactionTimeStepper::RetrieveResults",
"G4DNAIndependentReactionTimeStepper004", FatalErrorInArgument,
msg);
"G4DNAIndependentReactionTimeStepper004", FatalErrorInArgument, msg);
}
fReactants->push_back(const_cast<G4Track*>(&utils.fTrackB));
if (reactionTime < 0) {
// DEBUG
G4ExceptionDescription msg;
msg << "The interacting tracks are not in good time" << G4endl;
msg << "fpTrackA : trackID : " << utils.fpTrackA->GetTrackID()
<< "\t Name :" << utils.fpMoleculeA->GetName()
<< "\t fpTrackA->GetGlobalTime() = " << G4BestUnit(utils.fpTrackA->GetGlobalTime(), "Time")
<< G4endl;
msg << "trackB : trackID : " << utils.fpTrackB->GetTrackID()
<< "\t Name :" << utils.fpMoleculeB->GetName()
<< "\t trackB->GetGlobalTime() = " << G4BestUnit(utils.fpTrackB->GetGlobalTime(), "Time")
<< G4endl;
G4Exception("G4DNAIndependentReactionTimeStepper::CheckAndRecordResults",
"G4DNAIndependentReactionTimeStepper1", FatalErrorInArgument, msg);
}
G4double globalTime = G4Scheduler::Instance()->GetGlobalTime();
fReactionSet->AddReaction(reactionTime + globalTime, utils.fpTrackA, utils.fpTrackB);
fSampledPositions[utils.fpTrackA->GetTrackID()] = utils.fpTrackA->GetPosition();
fSampledPositions[utils.fpTrackB->GetTrackID()] = utils.fpTrackB->GetPosition();
}
std::unique_ptr<G4ITReactionChange> G4DNAIndependentReactionTimeStepper::FindReaction(
G4ITReactionSet* pReactionSet, const G4double& currentStepTime,
const G4double& /*previousStepTime*/, const G4bool& /*reachedUserStepTimeLimit*/)
G4ITReactionSet* pReactionSet, G4double& currentStepTime, const G4double globalTime)
{
if (pReactionSet == nullptr) {
return nullptr;
@@ -278,16 +269,13 @@ std::unique_ptr<G4ITReactionChange> G4DNAIndependentReactionTimeStepper::FindRea
for (auto reaction_i = reactionPerTime.begin(); reaction_i != reactionPerTime.end();
reaction_i = reactionPerTime.begin())
{
if ((*reaction_i)->GetTime() > currentStepTime) {
fReactionSet->CleanAllReaction();
return nullptr;
}
G4Track* pTrackA = (*reaction_i)->GetReactants().first;
currentStepTime = DBL_MAX;
if (pTrackA->GetTrackStatus() == fStopAndKill) {
continue;
}
G4Track* pTrackB = (*reaction_i)->GetReactant(pTrackA);
currentStepTime = DBL_MAX;
if (pTrackB->GetTrackStatus() == fStopAndKill) {
continue;
}
@@ -295,24 +283,27 @@ std::unique_ptr<G4ITReactionChange> G4DNAIndependentReactionTimeStepper::FindRea
if (pTrackB == pTrackA) {
G4ExceptionDescription msg;
msg << "The IT reaction process sent back a reaction "
"between trackA and trackB. ";
"between trackA and trackB. ";
msg << "The problem is trackA == trackB";
G4Exception("G4DNAIndependentReactionTimeStepper::FindReaction",
"G4DNAIndependentReactionTimeStepper02", FatalErrorInArgument,
msg);
"G4DNAIndependentReactionTimeStepper02", FatalErrorInArgument, msg);
}
G4double reactionTime = (*reaction_i)->GetTime();
currentStepTime = reactionTime - globalTime;
if(fVerbose > 1)
G4cout << " reaction Time : " << reactionTime << " currentStepTime : " << currentStepTime
<< " globalTime : " << globalTime << " " << pTrackA->GetTrackID() << " + "
<< pTrackB->GetTrackID() << G4endl;
pReactionSet->SelectThisReaction(*reaction_i);
if (fpReactionProcess != nullptr
&& fpReactionProcess->TestReactibility(*pTrackA, *pTrackB, currentStepTime, false))
{
if (fpReactionProcess != nullptr) {
if ((fSampledPositions.find(pTrackA->GetTrackID()) == fSampledPositions.end()
&& (fSampledPositions.find(pTrackB->GetTrackID()) == fSampledPositions.end())))
{
G4ExceptionDescription msg;
msg << "The positions of trackA and trackB have no counted ";
G4Exception("G4DNAIndependentReactionTimeStepper::FindReaction",
"G4DNAIndependentReactionTimeStepper0001", FatalErrorInArgument,
msg);
"G4DNAIndependentReactionTimeStepper0001", FatalErrorInArgument, msg);
}
pTrackA->SetPosition(fSampledPositions[pTrackA->GetTrackID()]);
@@ -321,6 +312,13 @@ std::unique_ptr<G4ITReactionChange> G4DNAIndependentReactionTimeStepper::FindRea
if (pReactionChange == nullptr) {
return nullptr;
}
G4int nbSecondaries = pReactionChange->GetNumberOfSecondaries();
if (nbSecondaries > 0) {
const std::vector<G4Track*>* productsVector = pReactionChange->GetfSecondary();
for (const auto& it : *productsVector) {
fSecondaries.push_back(it);
}
}
return pReactionChange;
}
}
@@ -354,19 +352,44 @@ void G4DNAIndependentReactionTimeStepper::SetReactionProcess(G4VITReactionProces
{
fpReactionProcess = pReactionProcess;
}
G4double G4DNAIndependentReactionTimeStepper::CalculateMinTimeStep(G4double /*currentGlobalTime*/,
G4double definedMinTimeStep)
G4double G4DNAIndependentReactionTimeStepper::CalculateMinTimeStep(G4double currentGlobalTime,
G4double /*definedMinTimeStep*/)
{
G4double fTSTimeStep = DBL_MAX;
fCheckedTracks.clear();
// fUserMinTimeStep = definedMinTimeStep;
if (!fIsInitialized) {
InitializeReactions(currentGlobalTime);
}
G4int nbPreviousSecondaries = (G4int)fSecondaries.size();
if (nbPreviousSecondaries > 0) {
InitializeForNewTrack();
for (const auto& it : fSecondaries) {
CalculateStep(*it, fUserMinTimeStep);
}
fSecondaries.clear();
}
fTSTimeStep = GetNextReactionTime() - currentGlobalTime;
if (fTSTimeStep < 0) {
G4ExceptionDescription msg;
msg << "fTSTimeStep < 0" << ": fTSTimeStep : " << fTSTimeStep
<< " GetNextReactionTime() : " << GetNextReactionTime()
<< " currentGlobalTime : " << currentGlobalTime << G4endl;
G4Exception("G4DNAIndependentReactionTimeStepper::CalculateMinTimeStep",
"G4DNAIndependentReactionTimeStepper002", FatalErrorInArgument, msg);
}
return fTSTimeStep;
}
void G4DNAIndependentReactionTimeStepper::InitializeReactions(G4double /*currentGlobalTime*/)
{
fCheckedTracks.clear();
for (auto pTrack : *fpTrackContainer->GetMainList()) {
if (pTrack == nullptr) {
G4ExceptionDescription msg;
msg << "No track found.";
G4Exception("G4DNAIndependentReactionTimeStepper::CalculateMinTimeStep",
"G4DNAIndependentReactionTimeStepper006", FatalErrorInArgument,
msg);
G4Exception("G4DNAIndependentReactionTimeStepper::InitializeReactions",
"G4DNAIndependentReactionTimeStepper030", FatalErrorInArgument, msg);
continue;
}
@@ -374,36 +397,32 @@ G4double G4DNAIndependentReactionTimeStepper::CalculateMinTimeStep(G4double /*cu
if (trackStatus == fStopAndKill || trackStatus == fStopButAlive) {
continue;
}
G4double sampledMinTimeStep = CalculateStep(*pTrack, definedMinTimeStep);
G4TrackVectorHandle reactants = GetReactants();
if (sampledMinTimeStep < fTSTimeStep) {
fTSTimeStep = sampledMinTimeStep;
if (reactants) {
fReactionSet->AddReactions(fTSTimeStep, const_cast<G4Track*>(pTrack), std::move(reactants));
fSampledPositions[pTrack->GetTrackID()] = pTrack->GetPosition();
for (const auto& it : *fReactants) {
auto pTrackB = it;
fSampledPositions[pTrackB->GetTrackID()] = pTrackB->GetPosition();
}
ResetReactants();
}
}
else if (fTSTimeStep == sampledMinTimeStep && G4bool(reactants)) {
fReactionSet->AddReactions(fTSTimeStep, const_cast<G4Track*>(pTrack), std::move(reactants));
fSampledPositions[pTrack->GetTrackID()] = pTrack->GetPosition();
for (const auto& it : *fReactants) {
auto pTrackB = it;
fSampledPositions[pTrackB->GetTrackID()] = pTrackB->GetPosition();
}
ResetReactants();
}
else if (reactants) {
ResetReactants();
}
CalculateStep(*pTrack, fUserMinTimeStep);
}
return fTSTimeStep;
if (fVerbose > 0)
G4cout << "InitializeReactions : reaction events : "
<< fReactionSet->GetReactionsPerTime().size() << ". The previous time step : "
<< G4BestUnit(G4Scheduler::Instance()->GetPreviousTimeStep(), "Time") << G4endl;
fIsInitialized = true;
}
G4double G4DNAIndependentReactionTimeStepper::GetNextReactionTime()
{
G4double output = DBL_MAX;
auto nextReaction = GetNextReaction();
if (nextReaction != nullptr) {
output = GetNextReaction()->GetTime();
}
return output;
}
const G4ITReaction* G4DNAIndependentReactionTimeStepper::GetNextReaction()
{
G4ITReaction* output = nullptr;
G4ITReactionPerTime& reactionPerTime = fReactionSet->GetReactionsPerTime();
auto reaction_i = reactionPerTime.begin();
if (reaction_i != reactionPerTime.end()) {
output = (reaction_i->get());
}
return output;
}
@@ -37,6 +37,8 @@
#include "G4DNAIndependentReactionTimeStepper.hh"
#include "G4Scheduler.hh"
#include "G4UnitsTable.hh"
#include "G4DNAScavengerMaterial.hh"
#include "G4MoleculeCounterManager.hh"
G4DNAMakeReaction::G4DNAMakeReaction()
:
@@ -45,6 +47,8 @@ G4DNAMakeReaction::G4DNAMakeReaction()
, fpTimeStepper(nullptr)
, fTimeStep(0)
{
fpScavengerMaterial = dynamic_cast<G4DNAScavengerMaterial*>(
G4Scheduler::Instance()->GetScavengerMaterial());
}
G4DNAMakeReaction::G4DNAMakeReaction(G4VDNAReactionModel* pReactionModel)
@@ -83,6 +87,10 @@ G4DNAMakeReaction::MakeReaction(const G4Track &trackA,
const auto pReactionData = fMolReactionTable->GetReactionData(pMoleculeA, pMoleculeB);
const G4int nbProducts = pReactionData->GetNbProducts();
// Notify molecule (reaction) counter
if (G4MoleculeCounterManager::Instance()->GetIsActive()) {
G4MoleculeCounterManager::Instance()->RecordReaction(pReactionData, trackA.GetGlobalTime());
}
if (nbProducts != 0)
{
const G4double D1 = pMoleculeA->GetDiffusionCoefficient();
@@ -98,7 +106,18 @@ G4DNAMakeReaction::MakeReaction(const G4Track &trackA,
for (G4int j = 0; j < nbProducts; ++j)
{
auto pProduct = new G4Molecule(pReactionData->GetProduct(j));
auto product = pReactionData->GetProduct(j);
if(fpScavengerMaterial != nullptr) {
auto isScavenger = fpScavengerMaterial->find(product);
if (isScavenger) {
fpScavengerMaterial->AddNumberMoleculePerVolumeUnitForMaterialConf(
product, trackA.GetGlobalTime());
continue;
}
}
auto pProduct = new G4Molecule(product);
auto pProductTrack = pProduct->BuildTrack(trackA.GetGlobalTime(), (reactionSite + randP)/2);
pProductTrack->SetTrackStatus(fAlive);
G4ITTrackHolder::Instance()->Push(pProductTrack);
@@ -181,27 +200,30 @@ void G4DNAMakeReaction::UpdatePositionForReaction(G4Track& trackA,
}
}
std::vector<std::unique_ptr<G4ITReactionChange>>
G4DNAMakeReaction::FindReaction(G4ITReactionSet* pReactionSet,
const G4double currentStepTime,
const G4double /*globalTime*/,
const G4double globalTime,
const G4bool /*reachedUserStepTimeLimit*/)
{
std::vector<std::unique_ptr<G4ITReactionChange>> ReactionInfo;
ReactionInfo.clear();
auto stepper = dynamic_cast<G4DNAIndependentReactionTimeStepper*>(fpTimeStepper);
if(stepper == nullptr){
return ReactionInfo;
}else
{
do{
auto pReactionChange = stepper->
FindReaction(pReactionSet,currentStepTime);
if (pReactionChange != nullptr)
{
ReactionInfo.push_back(std::move(pReactionChange));
}
}while (!pReactionSet->GetReactionsPerTime().empty());
}
std::vector<std::unique_ptr<G4ITReactionChange>> ReactionInfo;
auto stepper = dynamic_cast<G4DNAIndependentReactionTimeStepper*>(fpTimeStepper);
if (stepper == nullptr) {
return ReactionInfo;
}else {
G4double StepTime = 0;
do {
auto pReactionChange = stepper->FindReaction(pReactionSet, StepTime, globalTime);
if (pReactionChange != nullptr) {
// G4cout<<" time : "<<globalTime<<" "<<pReactionChange->GetTrackA()->GetTrackID()
// <<" + "<<pReactionChange->GetTrackB()->GetTrackID()<<G4endl;
ReactionInfo.push_back(std::move(pReactionChange));
}
else{
break;
}
}while(StepTime == currentStepTime);
}
return ReactionInfo;
}
@@ -45,6 +45,7 @@
#include "G4ITReaction.hh"
#include "G4ITTrackHolder.hh"
#include "G4MoleculeCounterManager.hh"
G4DNAMolecularReaction::G4DNAMolecularReaction()
:
@@ -91,7 +92,10 @@ std::unique_ptr<G4ITReactionChange> G4DNAMolecularReaction::MakeReaction(const G
const auto pMoleculeB = GetMolecule(trackB)->GetMolecularConfiguration();
const auto pReactionData = fMolReactionTable->GetReactionData(pMoleculeA, pMoleculeB);
// Notify molecule (reaction) counter
if (G4MoleculeCounterManager::Instance()->GetIsActive()) {
G4MoleculeCounterManager::Instance()->RecordReaction(pReactionData, trackA.GetGlobalTime());
}
const G4int nbProducts = pReactionData->GetNbProducts();
if (nbProducts != 0)
@@ -0,0 +1,556 @@
//
// ********************************************************************
// * License and Disclaimer *
// * *
// * The Geant4 software is copyright of the Copyright Holders of *
// * the Geant4 Collaboration. It is provided under the terms and *
// * conditions of the Geant4 Software License, included in the file *
// * LICENSE and available at http://cern.ch/geant4/license . These *
// * include a list of copyright holders. *
// * *
// * Neither the authors of this software system, nor their employing *
// * institutes,nor the agencies providing financial support for this *
// * work make any representation or warranty, express or implied, *
// * regarding this software system or assume any liability for its *
// * use. Please see the license in the file LICENSE and URL above *
// * for the full disclaimer and the limitation of liability. *
// * *
// * This code implementation is the result of the scientific and *
// * technical work of the GEANT4 collaboration. *
// * By using, copying, modifying or distributing the software (or *
// * any work based on the software) you agree to acknowledge its *
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
// Created 11.02.2025 V.Ivanchenko & M. Vologzhin
// on base of previous Rudd models
//
// Russian Goverment grant No 075-15-2024-667 23.08.2024
//
#include "G4DNARuddIonisationDynamicModel.hh"
#include "G4PhysicalConstants.hh"
#include "G4SystemOfUnits.hh"
#include "G4VAtomDeexcitation.hh"
#include "G4UAtomicDeexcitation.hh"
#include "G4LossTableManager.hh"
#include "G4NistManager.hh"
#include "G4DNAChemistryManager.hh"
#include "G4DNAMolecularMaterial.hh"
#include "G4LogLogInterpolation.hh"
#include "G4ProductionCutsTable.hh"
#include "G4DNAGenericIonsManager.hh"
#include "G4DNACrossSectionDataSet.hh"
#include "G4NistManager.hh"
#include "G4IonTable.hh"
#include "G4DNARuddAngle.hh"
#include "G4DeltaAngle.hh"
#include "G4Exp.hh"
#include "G4Log.hh"
#include "G4Pow.hh"
#include "G4Alpha.hh"
#include "G4Proton.hh"
#include "G4Electron.hh"
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4DNACrossSectionDataSet* G4DNARuddIonisationDynamicModel::xsdata_hydrogen = nullptr;
G4DNACrossSectionDataSet* G4DNARuddIonisationDynamicModel::xsdata_helium = nullptr;
G4DNACrossSectionDataSet* G4DNARuddIonisationDynamicModel::xsdata_p = nullptr;
const std::vector<G4double>* G4DNARuddIonisationDynamicModel::fpWaterDensity = nullptr;
namespace
{
const G4double scaleFactor = CLHEP::m*CLHEP::m;
const G4double tolerance = 1*CLHEP::eV;
const G4double Ry = 13.6*CLHEP::eV;
// Following values provided by M. Dingfelder (priv. comm)
const G4double Bj[5] = {12.60*CLHEP::eV, 14.70*CLHEP::eV, 18.40*CLHEP::eV,
32.20*CLHEP::eV, 539*CLHEP::eV};
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4DNARuddIonisationDynamicModel::G4DNARuddIonisationDynamicModel(const G4ParticleDefinition*,
const G4String& nam)
: G4VEmModel(nam)
{
fGpow = G4Pow::GetInstance();
fLowestEnergy = 100*CLHEP::eV;
fAbsorptionEnergy = 50*CLHEP::eV;
// Mark this model as "applicable" for atomic deexcitation
SetDeexcitationFlag(true);
// Define default angular generator
SetAngularDistribution(new G4DNARuddAngle());
if (nullptr == xsdata_p) {
isFirst = true;
LoadData();
}
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4DNARuddIonisationDynamicModel::~G4DNARuddIonisationDynamicModel()
{
if (isFirst) {
delete xsdata_p;
delete xsdata_hydrogen;
delete xsdata_helium;
}
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4DNARuddIonisationDynamicModel::LoadData()
{
// initialisation of static data once
G4String filename = "dna/sigma_ionisation_p_rudd";
xsdata_p = new G4DNACrossSectionDataSet(new G4LogLogInterpolation, CLHEP::eV, scaleFactor);
xsdata_p->LoadData(filename);
filename = "dna/sigma_ionisation_h_rudd";
xsdata_hydrogen = new G4DNACrossSectionDataSet(new G4LogLogInterpolation, CLHEP::eV, scaleFactor);
xsdata_hydrogen->LoadData(filename);
filename = "dna/sigma_ionisation_he_rudd";
xsdata_helium = new G4DNACrossSectionDataSet(new G4LogLogInterpolation, CLHEP::eV, scaleFactor);
xsdata_helium->LoadData(filename);
// to avoid possible threading problem fill this vector only once
auto water = G4NistManager::Instance()->FindMaterial("G4_WATER");
fpWaterDensity =
G4DNAMolecularMaterial::Instance()->GetNumMolPerVolTableFor(water);
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4DNARuddIonisationDynamicModel::Initialise(const G4ParticleDefinition* p,
const G4DataVector&)
{
if (p != fParticle) { SetParticle(p); }
// particle change object may be externally set
if (nullptr == fParticleChangeForGamma) {
fParticleChangeForGamma = GetParticleChangeForGamma();
}
const G4String& pname = p->GetParticleName();
// the same definition of generic ion as in G4VEmProcess class
if (p->GetParticleType() == "nucleus" && p->GetParticleSubType() == "generic") {
if (pname != "deuteron" && pname != "triton" &&
pname != "He3" && pname != "alpha" && pname != "alpha+" &&
pname != "helium" && pname != "hydrogen") {
isIon = true;
}
}
// initialisation once in each thread
if (!isInitialised) {
isInitialised = true;
xsdata = xsdata_p;
if (pname == "helium") {
isHelium = true;
xsdata = xsdata_helium;
slaterEffectiveCharge[0]=1.7;
slaterEffectiveCharge[1]=1.15;
slaterEffectiveCharge[2]=1.15;
sCoefficient[0]=0.5;
sCoefficient[1]=0.25;
sCoefficient[2]=0.25;
fLowestEnergy = 1*CLHEP::keV;
} else if (pname == "alpha+") {
isHelium = true;
// The following values are provided by M. Dingfelder (priv. comm)
slaterEffectiveCharge[0]=2.0;
slaterEffectiveCharge[1]=2.0;
slaterEffectiveCharge[2]=2.0;
sCoefficient[0]=0.7;
sCoefficient[1]=0.15;
sCoefficient[2]=0.15;
} else if (pname == "hydrogen") {
xsdata = xsdata_hydrogen;
}
// defined stationary mode
statCode = G4EmParameters::Instance()->DNAStationary();
// initialise atomic de-excitation
if (!statCode)
fAtomDeexcitation = G4LossTableManager::Instance()->AtomDeexcitation();
// chemistry
auto chem = G4DNAChemistryManager::Instance();
if (chem->IsChemistryActivated()) {
fChemistry = chem;
}
InitialiseIntegrator(0.1, 0.25, 1.05, 1*CLHEP::eV, 0.2*CLHEP::eV, 10*CLHEP::keV);
if (verbose > 0) {
G4cout << "### G4DNARuddIonisationDynamicModel::Initialise(..) "
<< fParticle->GetParticleName() << G4endl;
}
}
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4DNARuddIonisationDynamicModel::SetParticle(const G4ParticleDefinition* p)
{
fParticle = p;
fMass = p->GetPDGMass();
fMassRate = CLHEP::proton_mass_c2/fMass;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4DNARuddIonisationDynamicModel::StartTracking(G4Track* track)
{
fTrack = track;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4double
G4DNARuddIonisationDynamicModel::CrossSectionPerVolume(const G4Material* material,
const G4ParticleDefinition* part,
G4double kinE,
G4double, G4double)
{
// check if model is applicable for given material
G4double density = (material->GetIndex() < fpWaterDensity->size())
? (*fpWaterDensity)[material->GetIndex()] : 0.0;
if (0.0 == density) { return 0.0; }
// check on kinetic energy (not scaled energy) to stop low-energy ion
if (kinE < fAbsorptionEnergy) { return DBL_MAX; }
// ion may be different
if (fParticle != part) { SetParticle(part); }
G4double q = fTrack->GetDynamicParticle()->GetCharge()*inveplus;
// cross section for scaled energy
G4double e = kinE*fMassRate;
auto xs = xsdata;
if (0.0 == q) { xs = isHelium ? xsdata_helium : xsdata_hydrogen; }
G4double sigma = (e > fLowestEnergy) ? xs->FindValue(e)
: xs->FindValue(fLowestEnergy) * e / fLowestEnergy;
sigma *= density;
if (q > 1.5) { sigma *= q * q; }
if (verbose > 1) {
G4cout << "G4DNARuddIonisationDynamicModel for " << part->GetParticleName()
<< " Ekin(keV)=" << kinE/CLHEP::keV
<< " sigma(cm^2)=" << sigma/CLHEP::cm2 << G4endl;
}
return sigma;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void
G4DNARuddIonisationDynamicModel::SampleSecondaries(std::vector<G4DynamicParticle*>* fvect,
const G4MaterialCutsCouple* couple,
const G4DynamicParticle* dpart,
G4double, G4double)
{
const G4ParticleDefinition* pd = dpart->GetDefinition();
if (fParticle != pd) { SetParticle(pd); }
// stop ion with energy below low energy limit
G4double kinE = dpart->GetKineticEnergy();
// ion shoud be stopped - check on kinetic energy and not scaled energy
if (kinE <= fAbsorptionEnergy) {
fParticleChangeForGamma->SetProposedKineticEnergy(0.);
fParticleChangeForGamma->ProposeTrackStatus(fStopButAlive);
fParticleChangeForGamma->ProposeLocalEnergyDeposit(kinE);
return;
}
fScaledEnergy = kinE*fMassRate;
fSelectedShell = SelectShell();
G4double bindingEnergy = (useDNAWaterStructure)
? waterStructure.IonisationEnergy(fSelectedShell) : Bj[fSelectedShell];
//Si: additional protection if tcs interpolation method is modified
if (kinE < bindingEnergy) { return; }
G4double esec = SampleElectronEnergy();
G4double esum = 0.0;
// sample deexcitation
// here we assume that H2O electronic levels are the same as Oxygen.
// this can be considered true with a rough 10% error in energy on K-shell,
G4int Z = 8;
G4ThreeVector deltaDir =
GetAngularDistribution()->SampleDirectionForShell(dpart, esec, Z,
fSelectedShell,
couple->GetMaterial());
// SI: only atomic deexcitation from K shell is considered
if (fAtomDeexcitation != nullptr && fSelectedShell == 4) {
auto as = G4AtomicShellEnumerator(0);
auto ashell = fAtomDeexcitation->GetAtomicShell(Z, as);
fAtomDeexcitation->GenerateParticles(fvect, ashell, Z, 0, 0);
// compute energy sum from de-excitation
for (auto const & ptr : *fvect) {
esum += ptr->GetKineticEnergy();
}
}
// check energy balance
// remaining excitation energy of water molecule
G4double exc = std::max(bindingEnergy - esum, 0.0);
// remaining projectile energy
G4double scatteredEnergy = kinE - bindingEnergy - esec;
if(scatteredEnergy < -tolerance || exc < -tolerance) {
G4cout << "G4DNARuddIonisationDynamicModel::SampleSecondaries: "
<< "negative final E(keV)=" << scatteredEnergy/CLHEP::keV << " Ein(keV)="
<< kinE/CLHEP::keV << " " << pd->GetParticleName()
<< " Edelta(keV)=" << esec/CLHEP::keV << " MeV, Exc(keV)=" << exc/CLHEP::keV
<< G4endl;
}
scatteredEnergy = std::max(scatteredEnergy, 0.0);
// projectile
if (!statCode) {
fParticleChangeForGamma->SetProposedKineticEnergy(scatteredEnergy);
fParticleChangeForGamma->ProposeLocalEnergyDeposit(exc);
} else {
fParticleChangeForGamma->SetProposedKineticEnergy(kinE);
fParticleChangeForGamma->ProposeLocalEnergyDeposit(kinE - scatteredEnergy);
}
// delta-electron
auto dp = new G4DynamicParticle(G4Electron::Electron(), deltaDir, esec);
fvect->push_back(dp);
// create radical
if (nullptr != fChemistry) {
fChemistry->CreateWaterMolecule(eIonizedMolecule, fSelectedShell, fTrack);
}
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4int G4DNARuddIonisationDynamicModel::SelectShell()
{
G4double sum = 0.0;
G4double xs;
for (G4int i=0; i<5; ++i) {
auto ptr = xsdata->GetComponent(i);
xs = (fScaledEnergy > fLowestEnergy) ? ptr->FindValue(fScaledEnergy)
: ptr->FindValue(fLowestEnergy)*fScaledEnergy/fLowestEnergy;
sum += xs;
fTemp[i] = sum;
}
sum *= G4UniformRand();
for (G4int i=0; i<5; ++i) {
if (sum <= fTemp[i]) { return i; }
}
return 0;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4double
G4DNARuddIonisationDynamicModel::MaxEnergy()
{
// kinematic limit
G4double tau = fScaledEnergy/CLHEP::proton_mass_c2;
G4double gam = 1.0 + tau;
G4double emax = 2.0*CLHEP::electron_mass_c2*tau*(tau + 2.0);
// Initialisation of sampling
G4double A1, B1, C1, D1, E1, A2, B2, C2, D2;
if (fSelectedShell == 4) {
//Data For Liquid Water K SHELL from Dingfelder (Protons in Water)
A1 = 1.25;
B1 = 0.5;
C1 = 1.00;
D1 = 1.00;
E1 = 3.00;
A2 = 1.10;
B2 = 1.30;
C2 = 1.00;
D2 = 0.00;
alphaConst = 0.66;
} else {
//Data For Liquid Water from Dingfelder (Protons in Water)
A1 = 1.02;
B1 = 82.0;
C1 = 0.45;
D1 = -0.80;
E1 = 0.38;
A2 = 1.07;
// Value provided by M. Dingfelder (priv. comm)
B2 = 11.6;
C2 = 0.60;
D2 = 0.04;
alphaConst = 0.64;
}
bEnergy = Bj[fSelectedShell];
G4double v2 = 0.25*emax/(bEnergy*gam*gam);
v = std::sqrt(v2);
u = Ry/bEnergy;
wc = 4.*v2 - 2.*v - 0.25*u;
G4double L1 = (C1 * fGpow->powA(v, D1)) / (1. + E1 * fGpow->powA(v, (D1 + 4.)));
G4double L2 = C2 * fGpow->powA(v, D2);
G4double H1 = (A1 * G4Log(1. + v2)) / (v2 + (B1 / v2));
G4double H2 = (A2 / v2) + (B2 / (v2 * v2));
F1 = L1 + H1;
F2 = (L2 * H2) / (L2 + H2);
return emax;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4double
G4DNARuddIonisationDynamicModel::SampleElectronEnergy()
{
// sampling is performed for proton projectile
G4double emax = MaxEnergy();
ComputeIntegral(0.0, emax);
G4double e = SampleValue();
if (verbose > 1) {
G4cout << "G4DNARuddIonisationDynamicModel::SampleElectronEnergy: "
<< fParticle->GetParticleName()
<< " Escaled(keV)=" << fScaledEnergy/CLHEP::keV << " Ee(keV)=" << e/CLHEP::keV
<< G4endl;
}
return e;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4double G4DNARuddIonisationDynamicModel::ProbabilityDensityFunction(G4double e)
{
// Shells ids are 0 1 2 3 4 (4 is k shell)
// !!Attention, "energyTransfer" here is the energy transfered to the electron which means
// that the secondary kinetic energy is w = energyTransfer - bindingEnergy
//
// ds S F1(nu) + w * F2(nu)
// ---- = G(k) * ---- -------------------------------------------
// dw Bj (1+w)^3 * [1 + exp{alpha * (w - wc) / nu}]
//
// w is the secondary electron kinetic Energy in eV
//
// All the other parameters can be found in Rudd's Papers
//
// M.Eugene Rudd, 1988, User-Friendly model for the energy distribution of
// electrons from protons or electron collisions. Nucl. Tracks Rad. Meas.Vol 16 N0 2/3 pp 219-218
//
G4double w = e/bEnergy;
G4double x = alphaConst*(w - wc)/v;
G4double y = (x > -15.) ? 1.0 + G4Exp(x) : 1.0;
G4double res = CorrectionFactor() * (F1 + w*F2) /
(fGpow->powN((1. + w)/u, 3) * y);
if (isHelium) {
G4double energyTransfer = e + bEnergy;
G4double Zeff = 2.0 -
(sCoefficient[0] * S_1s(fScaledEnergy, energyTransfer, slaterEffectiveCharge[0], 1.) +
sCoefficient[1] * S_2s(fScaledEnergy, energyTransfer, slaterEffectiveCharge[1], 2.) +
sCoefficient[2] * S_2p(fScaledEnergy, energyTransfer, slaterEffectiveCharge[2], 2.) );
res *= Zeff * Zeff;
}
return std::max(res, 0.0);
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4double G4DNARuddIonisationDynamicModel::S_1s(G4double kine,
G4double energyTransfer,
G4double slaterEffCharge,
G4double shellNumber)
{
// 1 - e^(-2r) * ( 1 + 2 r + 2 r^2)
// Dingfelder, in Chattanooga 2005 proceedings, formula (7)
G4double r = Rh(kine, energyTransfer, slaterEffCharge, shellNumber);
G4double value = 1. - G4Exp(-2 * r) * ( ( 2. * r + 2. ) * r + 1. );
return value;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4double G4DNARuddIonisationDynamicModel::S_2s(G4double kine,
G4double energyTransfer,
G4double slaterEffCharge,
G4double shellNumber)
{
// 1 - e^(-2 r) * ( 1 + 2 r + 2 r^2 + 2 r^4)
// Dingfelder, in Chattanooga 2005 proceedings, formula (8)
G4double r = Rh(kine, energyTransfer, slaterEffCharge, shellNumber);
G4double value =
1. - G4Exp(-2 * r) * (((2. * r * r + 2.) * r + 2.) * r + 1.);
return value;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4double G4DNARuddIonisationDynamicModel::S_2p(G4double kine,
G4double energyTransfer,
G4double slaterEffCharge,
G4double shellNumber)
{
// 1 - e^(-2 r) * ( 1 + 2 r + 2 r^2 + 4/3 r^3 + 2/3 r^4)
// Dingfelder, in Chattanooga 2005 proceedings, formula (9)
G4double r = Rh(kine, energyTransfer, slaterEffCharge, shellNumber);
G4double value =
1. - G4Exp(-2 * r) * (((( 2./3. * r + 4./3.) * r + 2.) * r + 2.) * r + 1.);
return value;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4double G4DNARuddIonisationDynamicModel::Rh(G4double ekin, G4double etrans,
G4double q, G4double shell)
{
// The following values are provided by M. Dingfelder (priv. comm)
// Dingfelder, in Chattanooga 2005 proceedings, p 4
G4double escaled = CLHEP::electron_mass_c2/fMass * ekin;
const G4double H = 13.60569172 * CLHEP::eV;
G4double value = 2.0*std::sqrt(escaled / H)*q*H /(etrans*shell);
return value;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4double G4DNARuddIonisationDynamicModel::CorrectionFactor()
{
// ZF Shortened
G4double res = 1.0;
if (fSelectedShell < 4) {
const G4double ln10 = fGpow->logZ(10);
G4double x = 2.0*((G4Log(fScaledEnergy/CLHEP::eV)/ln10) - 4.2);
// The following values are provided by M. Dingfelder (priv. comm)
res = 0.6/(1.0 + G4Exp(x)) + 0.9;
}
return res;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
@@ -91,7 +91,7 @@ G4DNARuddIonisationExtendedModel::G4DNARuddIonisationExtendedModel(const G4Parti
G4DNARuddIonisationExtendedModel::~G4DNARuddIonisationExtendedModel()
{
if(isFirst) {
if (isFirst) {
for(auto & i : xsdata) { delete i; }
}
}
@@ -222,7 +222,8 @@ void G4DNARuddIonisationExtendedModel::Initialise(const G4ParticleDefinition* p,
statCode = G4EmParameters::Instance()->DNAStationary();
// initialise atomic de-excitation
fAtomDeexcitation = G4LossTableManager::Instance()->AtomDeexcitation();
if (!statCode)
fAtomDeexcitation = G4LossTableManager::Instance()->AtomDeexcitation();
if (verbose > 0) {
G4cout << "### G4DNARuddIonisationExtendedModel::Initialise(..) " << pname
@@ -330,17 +331,18 @@ G4DNARuddIonisationExtendedModel::SampleSecondaries(std::vector<G4DynamicParticl
}
// check energy balance
// remaining excitation energy of water molecule
G4double exc = bindingEnergy - esum;
G4double exc = std::max(bindingEnergy - esum, 0.0);
// remaining projectile energy
G4double scatteredEnergy = kinE - bindingEnergy - esec;
if(scatteredEnergy < -tolerance || exc < -tolerance) {
if (scatteredEnergy < -tolerance || exc < -tolerance) {
G4cout << "G4DNARuddIonisationExtendedModel::SampleSecondaries: "
<< "negative final E(keV)=" << scatteredEnergy/CLHEP::keV << " Ein(keV)="
<< kinE/CLHEP::keV << " " << pd->GetParticleName()
<< " Edelta(keV)=" << esec/CLHEP::keV << " MeV, Exc(keV)=" << exc/CLHEP::keV
<< G4endl;
}
scatteredEnergy = std::max(scatteredEnergy, 0.0);
// projectile
if (!statCode) {
@@ -258,7 +258,22 @@ void G4DNARuddIonisationModel::Initialise(const G4ParticleDefinition* particle,
SetHighEnergyLimit(highEnergyLimit[alphaPlusPlus]);
}
if( verboseLevel>0 )
if (isInitialised) { return; }
// defined stationary mode
statCode = G4EmParameters::Instance()->DNAStationary();
// Initialize water density pointer
fpWaterDensity = G4DNAMolecularMaterial::Instance()->GetNumMolPerVolTableFor(G4Material::GetMaterial("G4_WATER"));
// atomic de-excitation
if (!statCode)
fAtomDeexcitation = G4LossTableManager::Instance()->AtomDeexcitation();
fParticleChangeForGamma = GetParticleChangeForGamma();
isInitialised = true;
if (verboseLevel > 0)
{
G4cout << "Rudd ionisation model is initialized " << G4endl
<< "Energy range: "
@@ -267,19 +282,6 @@ void G4DNARuddIonisationModel::Initialise(const G4ParticleDefinition* particle,
<< particle->GetParticleName()
<< G4endl;
}
// Initialize water density pointer
fpWaterDensity = G4DNAMolecularMaterial::Instance()->GetNumMolPerVolTableFor(G4Material::GetMaterial("G4_WATER"));
//
fAtomDeexcitation = G4LossTableManager::Instance()->AtomDeexcitation();
if (isInitialised)
{ return;}
fParticleChangeForGamma = GetParticleChangeForGamma();
isInitialised = true;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
@@ -32,6 +32,8 @@
#include "G4DNAScavengerMaterial.hh"
#include "G4Scheduler.hh"
#include "G4MoleculeCounterManager.hh"
G4DNAUpdateSystemModel::G4DNAUpdateSystemModel() = default;
void G4DNAUpdateSystemModel::SetMesh(G4DNAMesh* pMesh) { fpMesh = pMesh; }
@@ -53,9 +55,9 @@ void G4DNAUpdateSystemModel::KillMolecule(const Index& index, MolType type)
FatalErrorInArgument, exceptionDescription);
}
iter->second--;
if(G4VMoleculeCounter::Instance()->InUse())
if (G4MoleculeCounterManager::Instance()->GetIsActive())
{
G4VMoleculeCounter::Instance()->RemoveAMoleculeAtTime(type, fGlobalTime);
G4MoleculeCounterManager::Instance()->RemoveMoleculeWithoutTrack(type, fGlobalTime);
}
}
else
@@ -131,9 +133,9 @@ void G4DNAUpdateSystemModel::CreateMolecule(const Index& index, MolType type)
node[type] = 1;
}
if(G4VMoleculeCounter::Instance()->InUse())
if (G4MoleculeCounterManager::Instance()->GetIsActive())
{
G4VMoleculeCounter::Instance()->AddAMoleculeAtTime(type, fGlobalTime);
G4MoleculeCounterManager::Instance()->AddMoleculeWithoutTrack(type, fGlobalTime);
}
}