1144 lines
35 KiB
C++
1144 lines
35 KiB
C++
//
|
|
// ********************************************************************
|
|
// * 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 "G4DNARuddIonisationModel.hh"
|
|
#include "G4PhysicalConstants.hh"
|
|
#include "G4SystemOfUnits.hh"
|
|
#include "G4UAtomicDeexcitation.hh"
|
|
#include "G4LossTableManager.hh"
|
|
#include "G4DNAChemistryManager.hh"
|
|
#include "G4DNAMolecularMaterial.hh"
|
|
#include "G4DNARuddAngle.hh"
|
|
#include "G4DeltaAngle.hh"
|
|
#include "G4Exp.hh"
|
|
|
|
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
|
|
|
|
using namespace std;
|
|
|
|
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
|
|
|
|
G4DNARuddIonisationModel::G4DNARuddIonisationModel(const G4ParticleDefinition*,
|
|
const G4String& nam) :
|
|
G4VEmModel(nam), isInitialised(false)
|
|
{
|
|
fpWaterDensity = 0;
|
|
|
|
slaterEffectiveCharge[0] = 0.;
|
|
slaterEffectiveCharge[1] = 0.;
|
|
slaterEffectiveCharge[2] = 0.;
|
|
sCoefficient[0] = 0.;
|
|
sCoefficient[1] = 0.;
|
|
sCoefficient[2] = 0.;
|
|
|
|
lowEnergyLimitForZ1 = 0 * eV;
|
|
lowEnergyLimitForZ2 = 0 * eV;
|
|
lowEnergyLimitOfModelForZ1 = 100 * eV;
|
|
lowEnergyLimitOfModelForZ2 = 1 * keV;
|
|
killBelowEnergyForZ1 = lowEnergyLimitOfModelForZ1;
|
|
killBelowEnergyForZ2 = lowEnergyLimitOfModelForZ2;
|
|
|
|
verboseLevel = 0;
|
|
// Verbosity scale:
|
|
// 0 = nothing
|
|
// 1 = warning for energy non-conservation
|
|
// 2 = details of energy budget
|
|
// 3 = calculation of cross sections, file openings, sampling of atoms
|
|
// 4 = entering in methods
|
|
|
|
if (verboseLevel > 0)
|
|
{
|
|
G4cout << "Rudd ionisation model is constructed " << G4endl;
|
|
}
|
|
|
|
// Define default angular generator
|
|
SetAngularDistribution(new G4DNARuddAngle());
|
|
|
|
// Mark this model as "applicable" for atomic deexcitation
|
|
SetDeexcitationFlag(true);
|
|
fAtomDeexcitation = 0;
|
|
fParticleChangeForGamma = 0;
|
|
|
|
// Selection of stationary mode
|
|
|
|
statCode = false;
|
|
}
|
|
|
|
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
|
|
|
|
G4DNARuddIonisationModel::~G4DNARuddIonisationModel()
|
|
{
|
|
// Cross section
|
|
|
|
std::map<G4String, G4DNACrossSectionDataSet*, std::less<G4String> >::iterator pos;
|
|
for (pos = tableData.begin(); pos != tableData.end(); ++pos)
|
|
{
|
|
G4DNACrossSectionDataSet* table = pos->second;
|
|
delete table;
|
|
}
|
|
|
|
// The following removal is forbidden since G4VEnergyLossmodel takes care of deletion
|
|
// Coverity however will signal this as an error
|
|
// if (fAtomDeexcitation) {delete fAtomDeexcitation;}
|
|
|
|
}
|
|
|
|
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
|
|
|
|
void G4DNARuddIonisationModel::Initialise(const G4ParticleDefinition* particle,
|
|
const G4DataVector& /*cuts*/)
|
|
{
|
|
|
|
if (verboseLevel > 3)
|
|
{
|
|
G4cout << "Calling G4DNARuddIonisationModel::Initialise()" << G4endl;
|
|
}
|
|
|
|
// Energy limits
|
|
|
|
G4String fileProton("dna/sigma_ionisation_p_rudd");
|
|
G4String fileHydrogen("dna/sigma_ionisation_h_rudd");
|
|
G4String fileAlphaPlusPlus("dna/sigma_ionisation_alphaplusplus_rudd");
|
|
G4String fileAlphaPlus("dna/sigma_ionisation_alphaplus_rudd");
|
|
G4String fileHelium("dna/sigma_ionisation_he_rudd");
|
|
|
|
G4DNAGenericIonsManager *instance;
|
|
instance = G4DNAGenericIonsManager::Instance();
|
|
G4ParticleDefinition* protonDef = G4Proton::ProtonDefinition();
|
|
G4ParticleDefinition* hydrogenDef = instance->GetIon("hydrogen");
|
|
G4ParticleDefinition* alphaPlusPlusDef = instance->GetIon("alpha++");
|
|
G4ParticleDefinition* alphaPlusDef = instance->GetIon("alpha+");
|
|
G4ParticleDefinition* heliumDef = instance->GetIon("helium");
|
|
|
|
G4String proton;
|
|
G4String hydrogen;
|
|
G4String alphaPlusPlus;
|
|
G4String alphaPlus;
|
|
G4String helium;
|
|
|
|
G4double scaleFactor = 1 * m*m;
|
|
|
|
// LIMITS AND DATA
|
|
|
|
// ********************************************************
|
|
|
|
proton = protonDef->GetParticleName();
|
|
tableFile[proton] = fileProton;
|
|
|
|
lowEnergyLimit[proton] = lowEnergyLimitForZ1;
|
|
highEnergyLimit[proton] = 500. * keV;
|
|
|
|
// Cross section
|
|
|
|
G4DNACrossSectionDataSet* tableProton = new G4DNACrossSectionDataSet(new G4LogLogInterpolation,
|
|
eV,
|
|
scaleFactor );
|
|
tableProton->LoadData(fileProton);
|
|
tableData[proton] = tableProton;
|
|
|
|
// ********************************************************
|
|
|
|
hydrogen = hydrogenDef->GetParticleName();
|
|
tableFile[hydrogen] = fileHydrogen;
|
|
|
|
lowEnergyLimit[hydrogen] = lowEnergyLimitForZ1;
|
|
highEnergyLimit[hydrogen] = 100. * MeV;
|
|
|
|
// Cross section
|
|
|
|
G4DNACrossSectionDataSet* tableHydrogen = new G4DNACrossSectionDataSet(new G4LogLogInterpolation,
|
|
eV,
|
|
scaleFactor );
|
|
tableHydrogen->LoadData(fileHydrogen);
|
|
|
|
tableData[hydrogen] = tableHydrogen;
|
|
|
|
// ********************************************************
|
|
|
|
alphaPlusPlus = alphaPlusPlusDef->GetParticleName();
|
|
tableFile[alphaPlusPlus] = fileAlphaPlusPlus;
|
|
|
|
lowEnergyLimit[alphaPlusPlus] = lowEnergyLimitForZ2;
|
|
highEnergyLimit[alphaPlusPlus] = 400. * MeV;
|
|
|
|
// Cross section
|
|
|
|
G4DNACrossSectionDataSet* tableAlphaPlusPlus = new G4DNACrossSectionDataSet(new G4LogLogInterpolation,
|
|
eV,
|
|
scaleFactor );
|
|
tableAlphaPlusPlus->LoadData(fileAlphaPlusPlus);
|
|
|
|
tableData[alphaPlusPlus] = tableAlphaPlusPlus;
|
|
|
|
// ********************************************************
|
|
|
|
alphaPlus = alphaPlusDef->GetParticleName();
|
|
tableFile[alphaPlus] = fileAlphaPlus;
|
|
|
|
lowEnergyLimit[alphaPlus] = lowEnergyLimitForZ2;
|
|
highEnergyLimit[alphaPlus] = 400. * MeV;
|
|
|
|
// Cross section
|
|
|
|
G4DNACrossSectionDataSet* tableAlphaPlus = new G4DNACrossSectionDataSet(new G4LogLogInterpolation,
|
|
eV,
|
|
scaleFactor );
|
|
tableAlphaPlus->LoadData(fileAlphaPlus);
|
|
tableData[alphaPlus] = tableAlphaPlus;
|
|
|
|
// ********************************************************
|
|
|
|
helium = heliumDef->GetParticleName();
|
|
tableFile[helium] = fileHelium;
|
|
|
|
lowEnergyLimit[helium] = lowEnergyLimitForZ2;
|
|
highEnergyLimit[helium] = 400. * MeV;
|
|
|
|
// Cross section
|
|
|
|
G4DNACrossSectionDataSet* tableHelium = new G4DNACrossSectionDataSet(new G4LogLogInterpolation,
|
|
eV,
|
|
scaleFactor );
|
|
tableHelium->LoadData(fileHelium);
|
|
tableData[helium] = tableHelium;
|
|
|
|
//
|
|
|
|
if (particle==protonDef)
|
|
{
|
|
SetLowEnergyLimit(lowEnergyLimit[proton]);
|
|
SetHighEnergyLimit(highEnergyLimit[proton]);
|
|
}
|
|
|
|
if (particle==hydrogenDef)
|
|
{
|
|
SetLowEnergyLimit(lowEnergyLimit[hydrogen]);
|
|
SetHighEnergyLimit(highEnergyLimit[hydrogen]);
|
|
}
|
|
|
|
if (particle==heliumDef)
|
|
{
|
|
SetLowEnergyLimit(lowEnergyLimit[helium]);
|
|
SetHighEnergyLimit(highEnergyLimit[helium]);
|
|
}
|
|
|
|
if (particle==alphaPlusDef)
|
|
{
|
|
SetLowEnergyLimit(lowEnergyLimit[alphaPlus]);
|
|
SetHighEnergyLimit(highEnergyLimit[alphaPlus]);
|
|
}
|
|
|
|
if (particle==alphaPlusPlusDef)
|
|
{
|
|
SetLowEnergyLimit(lowEnergyLimit[alphaPlusPlus]);
|
|
SetHighEnergyLimit(highEnergyLimit[alphaPlusPlus]);
|
|
}
|
|
|
|
if( verboseLevel>0 )
|
|
{
|
|
G4cout << "Rudd ionisation model is initialized " << G4endl
|
|
<< "Energy range: "
|
|
<< LowEnergyLimit() / eV << " eV - "
|
|
<< HighEnergyLimit() / keV << " keV for "
|
|
<< 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....
|
|
|
|
G4double G4DNARuddIonisationModel::CrossSectionPerVolume(const G4Material* material,
|
|
const G4ParticleDefinition* particleDefinition,
|
|
G4double k,
|
|
G4double,
|
|
G4double)
|
|
{
|
|
if (verboseLevel > 3)
|
|
{
|
|
G4cout << "Calling CrossSectionPerVolume() of G4DNARuddIonisationModel"
|
|
<< G4endl;
|
|
}
|
|
|
|
// Calculate total cross section for model
|
|
|
|
G4DNAGenericIonsManager *instance;
|
|
instance = G4DNAGenericIonsManager::Instance();
|
|
|
|
if (
|
|
particleDefinition != G4Proton::ProtonDefinition()
|
|
&&
|
|
particleDefinition != instance->GetIon("hydrogen")
|
|
&&
|
|
particleDefinition != instance->GetIon("alpha++")
|
|
&&
|
|
particleDefinition != instance->GetIon("alpha+")
|
|
&&
|
|
particleDefinition != instance->GetIon("helium")
|
|
)
|
|
|
|
return 0;
|
|
|
|
G4double lowLim = 0;
|
|
|
|
if ( particleDefinition == G4Proton::ProtonDefinition()
|
|
|| particleDefinition == instance->GetIon("hydrogen")
|
|
)
|
|
|
|
lowLim = lowEnergyLimitOfModelForZ1;
|
|
|
|
if ( particleDefinition == instance->GetIon("alpha++")
|
|
|| particleDefinition == instance->GetIon("alpha+")
|
|
|| particleDefinition == instance->GetIon("helium")
|
|
)
|
|
|
|
lowLim = lowEnergyLimitOfModelForZ2;
|
|
|
|
G4double highLim = 0;
|
|
G4double sigma=0;
|
|
|
|
G4double waterDensity = (*fpWaterDensity)[material->GetIndex()];
|
|
|
|
const G4String& particleName = particleDefinition->GetParticleName();
|
|
|
|
// SI - the following is useless since lowLim is already defined
|
|
/*
|
|
std::map< G4String,G4double,std::less<G4String> >::iterator pos1;
|
|
pos1 = lowEnergyLimit.find(particleName);
|
|
|
|
if (pos1 != lowEnergyLimit.end())
|
|
{
|
|
lowLim = pos1->second;
|
|
}
|
|
*/
|
|
|
|
std::map< G4String,G4double,std::less<G4String> >::iterator pos2;
|
|
pos2 = highEnergyLimit.find(particleName);
|
|
|
|
if (pos2 != highEnergyLimit.end())
|
|
{
|
|
highLim = pos2->second;
|
|
}
|
|
|
|
if (k <= highLim)
|
|
{
|
|
//SI : XS must not be zero otherwise sampling of secondaries method ignored
|
|
|
|
if (k < lowLim) k = lowLim;
|
|
|
|
//
|
|
|
|
std::map< G4String,G4DNACrossSectionDataSet*,std::less<G4String> >::iterator pos;
|
|
pos = tableData.find(particleName);
|
|
|
|
if (pos != tableData.end())
|
|
{
|
|
G4DNACrossSectionDataSet* table = pos->second;
|
|
if (table != 0)
|
|
{
|
|
sigma = table->FindValue(k);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
G4Exception("G4DNARuddIonisationModel::CrossSectionPerVolume","em0002",
|
|
FatalException,"Model not applicable to particle type.");
|
|
}
|
|
|
|
}
|
|
|
|
if (verboseLevel > 2)
|
|
{
|
|
G4cout << "__________________________________" << G4endl;
|
|
G4cout << "G4DNARuddIonisationModel - XS INFO START" << G4endl;
|
|
G4cout << "Kinetic energy(eV)=" << k/eV << " particle : " << particleDefinition->GetParticleName() << G4endl;
|
|
G4cout << "Cross section per water molecule (cm^2)=" << sigma/cm/cm << G4endl;
|
|
G4cout << "Cross section per water molecule (cm^-1)=" << sigma*waterDensity/(1./cm) << G4endl;
|
|
//G4cout << " - Cross section per water molecule (cm^-1)="
|
|
//<< sigma*material->GetAtomicNumDensityVector()[1]/(1./cm) << G4endl;
|
|
G4cout << "G4DNARuddIonisationModel - XS INFO END" << G4endl;
|
|
}
|
|
|
|
return sigma*waterDensity;
|
|
|
|
}
|
|
|
|
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
|
|
|
|
void G4DNARuddIonisationModel::SampleSecondaries(std::vector<G4DynamicParticle*>* fvect,
|
|
const G4MaterialCutsCouple* couple,
|
|
const G4DynamicParticle* particle,
|
|
G4double,
|
|
G4double)
|
|
{
|
|
if (verboseLevel > 3)
|
|
{
|
|
G4cout << "Calling SampleSecondaries() of G4DNARuddIonisationModel"
|
|
<< G4endl;
|
|
}
|
|
|
|
G4double lowLim = 0;
|
|
G4double highLim = 0;
|
|
|
|
G4DNAGenericIonsManager *instance;
|
|
instance = G4DNAGenericIonsManager::Instance();
|
|
|
|
if ( particle->GetDefinition() == G4Proton::ProtonDefinition()
|
|
|| particle->GetDefinition() == instance->GetIon("hydrogen")
|
|
)
|
|
|
|
lowLim = killBelowEnergyForZ1;
|
|
|
|
if ( particle->GetDefinition() == instance->GetIon("alpha++")
|
|
|| particle->GetDefinition() == instance->GetIon("alpha+")
|
|
|| particle->GetDefinition() == instance->GetIon("helium")
|
|
)
|
|
|
|
lowLim = killBelowEnergyForZ2;
|
|
|
|
G4double k = particle->GetKineticEnergy();
|
|
|
|
const G4String& particleName = particle->GetDefinition()->GetParticleName();
|
|
|
|
// SI - the following is useless since lowLim is already defined
|
|
/*
|
|
std::map< G4String,G4double,std::less<G4String> >::iterator pos1;
|
|
pos1 = lowEnergyLimit.find(particleName);
|
|
|
|
if (pos1 != lowEnergyLimit.end())
|
|
{
|
|
lowLim = pos1->second;
|
|
}
|
|
*/
|
|
|
|
std::map< G4String,G4double,std::less<G4String> >::iterator pos2;
|
|
pos2 = highEnergyLimit.find(particleName);
|
|
|
|
if (pos2 != highEnergyLimit.end())
|
|
{
|
|
highLim = pos2->second;
|
|
}
|
|
|
|
if (k >= lowLim && k <= highLim)
|
|
{
|
|
G4ParticleDefinition* definition = particle->GetDefinition();
|
|
G4ParticleMomentum primaryDirection = particle->GetMomentumDirection();
|
|
/*
|
|
G4double particleMass = definition->GetPDGMass();
|
|
G4double totalEnergy = k + particleMass;
|
|
G4double pSquare = k*(totalEnergy+particleMass);
|
|
G4double totalMomentum = std::sqrt(pSquare);
|
|
*/
|
|
|
|
G4int ionizationShell = RandomSelect(k,particleName);
|
|
|
|
G4double bindingEnergy = 0;
|
|
bindingEnergy = waterStructure.IonisationEnergy(ionizationShell);
|
|
|
|
//SI: additional protection if tcs interpolation method is modified
|
|
if (k<bindingEnergy) return;
|
|
//
|
|
|
|
// SI - For atom. deexc. tagging - 23/05/2017
|
|
G4int Z = 8;
|
|
//
|
|
|
|
G4double secondaryKinetic = RandomizeEjectedElectronEnergy(definition,k,ionizationShell);
|
|
|
|
G4ThreeVector deltaDirection =
|
|
GetAngularDistribution()->SampleDirectionForShell(particle, secondaryKinetic,
|
|
Z, ionizationShell,
|
|
couple->GetMaterial());
|
|
|
|
G4DynamicParticle* dp = new G4DynamicParticle (G4Electron::Electron(),deltaDirection,secondaryKinetic);
|
|
fvect->push_back(dp);
|
|
|
|
// Ignored for ions on electrons
|
|
/*
|
|
G4double deltaTotalMomentum = std::sqrt(secondaryKinetic*(secondaryKinetic + 2.*electron_mass_c2 ));
|
|
|
|
G4double finalPx = totalMomentum*primaryDirection.x() - deltaTotalMomentum*deltaDirection.x();
|
|
G4double finalPy = totalMomentum*primaryDirection.y() - deltaTotalMomentum*deltaDirection.y();
|
|
G4double finalPz = totalMomentum*primaryDirection.z() - deltaTotalMomentum*deltaDirection.z();
|
|
G4double finalMomentum = std::sqrt(finalPx*finalPx+finalPy*finalPy+finalPz*finalPz);
|
|
finalPx /= finalMomentum;
|
|
finalPy /= finalMomentum;
|
|
finalPz /= finalMomentum;
|
|
|
|
G4ThreeVector direction;
|
|
direction.set(finalPx,finalPy,finalPz);
|
|
|
|
fParticleChangeForGamma->ProposeMomentumDirection(direction.unit()) ;
|
|
*/
|
|
|
|
fParticleChangeForGamma->ProposeMomentumDirection(primaryDirection);
|
|
|
|
// sample deexcitation
|
|
// here we assume that H_{2}O electronic levels are the same of Oxigen.
|
|
// this can be considered true with a rough 10% error in energy on K-shell,
|
|
|
|
size_t secNumberInit = 0;// need to know at a certain point the energy of secondaries
|
|
size_t secNumberFinal = 0;// So I'll make the diference and then sum the energies
|
|
|
|
G4double scatteredEnergy = k-bindingEnergy-secondaryKinetic;
|
|
|
|
// SI: only atomic deexcitation from K shell is considered
|
|
if(fAtomDeexcitation && ionizationShell == 4)
|
|
{
|
|
const G4AtomicShell* shell
|
|
= fAtomDeexcitation->GetAtomicShell(Z, G4AtomicShellEnumerator(0));
|
|
secNumberInit = fvect->size();
|
|
fAtomDeexcitation->GenerateParticles(fvect, shell, Z, 0, 0);
|
|
secNumberFinal = fvect->size();
|
|
|
|
if(secNumberFinal > secNumberInit)
|
|
{
|
|
for (size_t i=secNumberInit; i<secNumberFinal; ++i)
|
|
{
|
|
//Check if there is enough residual energy
|
|
if (bindingEnergy >= ((*fvect)[i])->GetKineticEnergy())
|
|
{
|
|
//Ok, this is a valid secondary: keep it
|
|
bindingEnergy -= ((*fvect)[i])->GetKineticEnergy();
|
|
}
|
|
else
|
|
{
|
|
//Invalid secondary: not enough energy to create it!
|
|
//Keep its energy in the local deposit
|
|
delete (*fvect)[i];
|
|
(*fvect)[i]=0;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
//This should never happen
|
|
if(bindingEnergy < 0.0)
|
|
G4Exception("G4DNAEmfietzoglouIonisatioModel1::SampleSecondaries()",
|
|
"em2050",FatalException,"Negative local energy deposit");
|
|
|
|
//bindingEnergy has been decreased
|
|
//by the amount of energy taken away by deexc. products
|
|
if (!statCode)
|
|
{
|
|
fParticleChangeForGamma->SetProposedKineticEnergy(scatteredEnergy);
|
|
fParticleChangeForGamma->ProposeLocalEnergyDeposit(bindingEnergy);
|
|
}
|
|
else
|
|
{
|
|
fParticleChangeForGamma->SetProposedKineticEnergy(k);
|
|
fParticleChangeForGamma->ProposeLocalEnergyDeposit(k-scatteredEnergy);
|
|
}
|
|
|
|
// debug
|
|
// k-scatteredEnergy-secondaryKinetic-deexSecEnergy = k-(k-bindingEnergy-secondaryKinetic)-secondaryKinetic-deexSecEnergy =
|
|
// = k-k+bindingEnergy+secondaryKinetic-secondaryKinetic-deexSecEnergy=
|
|
// = bindingEnergy-deexSecEnergy
|
|
// SO deexSecEnergy=0 => LocalEnergyDeposit = bindingEnergy
|
|
|
|
// 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);
|
|
}
|
|
|
|
// SI - not useful since low energy of model is 0 eV
|
|
|
|
if (k < lowLim)
|
|
{
|
|
fParticleChangeForGamma->SetProposedKineticEnergy(0.);
|
|
fParticleChangeForGamma->ProposeTrackStatus(fStopAndKill);
|
|
fParticleChangeForGamma->ProposeLocalEnergyDeposit(k);
|
|
}
|
|
|
|
}
|
|
|
|
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
|
|
|
G4double G4DNARuddIonisationModel::RandomizeEjectedElectronEnergy(G4ParticleDefinition* particleDefinition,
|
|
G4double k,
|
|
G4int shell)
|
|
{
|
|
G4double maximumKineticEnergyTransfer = 0.;
|
|
|
|
G4DNAGenericIonsManager *instance;
|
|
instance = G4DNAGenericIonsManager::Instance();
|
|
|
|
if (particleDefinition == G4Proton::ProtonDefinition()
|
|
|| particleDefinition == instance->GetIon("hydrogen"))
|
|
{
|
|
maximumKineticEnergyTransfer = 4. * (electron_mass_c2 / proton_mass_c2) * k;
|
|
}
|
|
|
|
else if (particleDefinition == instance->GetIon("helium")
|
|
|| particleDefinition == instance->GetIon("alpha+")
|
|
|| particleDefinition == instance->GetIon("alpha++"))
|
|
{
|
|
maximumKineticEnergyTransfer = 4. * (0.511 / 3728) * k;
|
|
}
|
|
|
|
G4double crossSectionMaximum = 0.;
|
|
|
|
for (G4double value = waterStructure.IonisationEnergy(shell);
|
|
value <= 5. * waterStructure.IonisationEnergy(shell) && k >= value;
|
|
value += 0.1 * eV)
|
|
{
|
|
G4double differentialCrossSection =
|
|
DifferentialCrossSection(particleDefinition, k, value, shell);
|
|
if (differentialCrossSection >= crossSectionMaximum)
|
|
crossSectionMaximum = differentialCrossSection;
|
|
}
|
|
|
|
G4double secElecKinetic = 0.;
|
|
|
|
do
|
|
{
|
|
secElecKinetic = G4UniformRand()* maximumKineticEnergyTransfer;
|
|
}while(G4UniformRand()*crossSectionMaximum > DifferentialCrossSection(particleDefinition,
|
|
k,
|
|
secElecKinetic+waterStructure.IonisationEnergy(shell),
|
|
shell));
|
|
|
|
return (secElecKinetic);
|
|
}
|
|
|
|
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
|
|
|
// The following section is not used anymore but is kept for memory
|
|
// GetAngularDistribution()->SampleDirectionForShell is used instead
|
|
|
|
/*
|
|
void G4DNARuddIonisationModel::RandomizeEjectedElectronDirection(G4ParticleDefinition* particleDefinition,
|
|
G4double k,
|
|
G4double secKinetic,
|
|
G4double & cosTheta,
|
|
G4double & phi )
|
|
{
|
|
G4DNAGenericIonsManager *instance;
|
|
instance = G4DNAGenericIonsManager::Instance();
|
|
|
|
G4double maxSecKinetic = 0.;
|
|
|
|
if (particleDefinition == G4Proton::ProtonDefinition()
|
|
|| particleDefinition == instance->GetIon("hydrogen"))
|
|
{
|
|
maxSecKinetic = 4.* (electron_mass_c2 / proton_mass_c2) * k;
|
|
}
|
|
|
|
else if (particleDefinition == instance->GetIon("helium")
|
|
|| particleDefinition == instance->GetIon("alpha+")
|
|
|| particleDefinition == instance->GetIon("alpha++"))
|
|
{
|
|
maxSecKinetic = 4.* (0.511 / 3728) * 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 G4DNARuddIonisationModel::DifferentialCrossSection(G4ParticleDefinition* particleDefinition,
|
|
G4double k,
|
|
G4double energyTransfer,
|
|
G4int ionizationLevelIndex)
|
|
{
|
|
// 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
|
|
//
|
|
|
|
const G4int j = ionizationLevelIndex;
|
|
|
|
G4double A1;
|
|
G4double B1;
|
|
G4double C1;
|
|
G4double D1;
|
|
G4double E1;
|
|
G4double A2;
|
|
G4double B2;
|
|
G4double C2;
|
|
G4double D2;
|
|
G4double alphaConst;
|
|
|
|
// const G4double Bj[5] = {12.61*eV, 14.73*eV, 18.55*eV, 32.20*eV, 539.7*eV};
|
|
// The following values are provided by M. dingfelder (priv. comm)
|
|
const G4double Bj[5] = { 12.60 * eV, 14.70 * eV, 18.40 * eV, 32.20 * eV, 540
|
|
* eV };
|
|
|
|
if (j == 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;
|
|
}
|
|
|
|
const G4double n = 2.;
|
|
const G4double Gj[5] = { 0.99, 1.11, 1.11, 0.52, 1. };
|
|
|
|
G4DNAGenericIonsManager* instance;
|
|
instance = G4DNAGenericIonsManager::Instance();
|
|
|
|
G4double wBig = (energyTransfer
|
|
- waterStructure.IonisationEnergy(ionizationLevelIndex));
|
|
if (wBig < 0)
|
|
return 0.;
|
|
|
|
G4double w = wBig / Bj[ionizationLevelIndex];
|
|
// Note that the following (j==4) cases are provided by M. Dingfelder (priv. comm)
|
|
if (j == 4)
|
|
w = wBig / waterStructure.IonisationEnergy(ionizationLevelIndex);
|
|
|
|
G4double Ry = 13.6 * eV;
|
|
|
|
G4double tau = 0.;
|
|
|
|
G4bool isProtonOrHydrogen = false;
|
|
G4bool isHelium = false;
|
|
|
|
if (particleDefinition == G4Proton::ProtonDefinition()
|
|
|| particleDefinition == instance->GetIon("hydrogen"))
|
|
{
|
|
isProtonOrHydrogen = true;
|
|
tau = (electron_mass_c2 / proton_mass_c2) * k;
|
|
}
|
|
|
|
else if (particleDefinition == instance->GetIon("helium")
|
|
|| particleDefinition == instance->GetIon("alpha+")
|
|
|| particleDefinition == instance->GetIon("alpha++"))
|
|
{
|
|
isHelium = true;
|
|
tau = (0.511 / 3728.) * k;
|
|
}
|
|
|
|
G4double S = 4. * pi * Bohr_radius * Bohr_radius * n
|
|
* std::pow((Ry / Bj[ionizationLevelIndex]), 2);
|
|
if (j == 4)
|
|
S = 4. * pi * Bohr_radius * Bohr_radius * n
|
|
* std::pow((Ry / waterStructure.IonisationEnergy(ionizationLevelIndex)),
|
|
2);
|
|
|
|
G4double v2 = tau / Bj[ionizationLevelIndex];
|
|
if (j == 4)
|
|
v2 = tau / waterStructure.IonisationEnergy(ionizationLevelIndex);
|
|
|
|
G4double v = std::sqrt(v2);
|
|
G4double wc = 4. * v2 - 2. * v - (Ry / (4. * Bj[ionizationLevelIndex]));
|
|
if (j == 4)
|
|
wc = 4. * v2 - 2. * v
|
|
- (Ry / (4. * waterStructure.IonisationEnergy(ionizationLevelIndex)));
|
|
|
|
G4double L1 = (C1 * std::pow(v, (D1))) / (1. + E1 * std::pow(v, (D1 + 4.)));
|
|
G4double L2 = C2 * std::pow(v, (D2));
|
|
G4double H1 = (A1 * std::log(1. + v2)) / (v2 + (B1 / v2));
|
|
G4double H2 = (A2 / v2) + (B2 / (v2 * v2));
|
|
|
|
G4double F1 = L1 + H1;
|
|
G4double F2 = (L2 * H2) / (L2 + H2);
|
|
|
|
G4double sigma =
|
|
CorrectionFactor(particleDefinition, k) * Gj[j]
|
|
* (S / Bj[ionizationLevelIndex])
|
|
* ((F1 + w * F2)
|
|
/ (std::pow((1. + w), 3)
|
|
* (1. + G4Exp(alphaConst * (w - wc) / v))));
|
|
|
|
if (j == 4)
|
|
sigma = CorrectionFactor(particleDefinition, k) * Gj[j]
|
|
* (S / waterStructure.IonisationEnergy(ionizationLevelIndex))
|
|
* ((F1 + w * F2)
|
|
/ (std::pow((1. + w), 3)
|
|
* (1. + G4Exp(alphaConst * (w - wc) / v))));
|
|
|
|
if ((particleDefinition == instance->GetIon("hydrogen"))
|
|
&& (ionizationLevelIndex == 4))
|
|
{
|
|
// sigma = Gj[j] * (S/Bj[ionizationLevelIndex])
|
|
sigma = Gj[j] * (S / waterStructure.IonisationEnergy(ionizationLevelIndex))
|
|
* ((F1 + w * F2)
|
|
/ (std::pow((1. + w), 3)
|
|
* (1. + G4Exp(alphaConst * (w - wc) / v))));
|
|
}
|
|
|
|
// if ( particleDefinition == G4Proton::ProtonDefinition()
|
|
// || particleDefinition == instance->GetIon("hydrogen")
|
|
// )
|
|
|
|
if (isProtonOrHydrogen)
|
|
{
|
|
return (sigma);
|
|
}
|
|
|
|
if (particleDefinition == instance->GetIon("alpha++"))
|
|
{
|
|
slaterEffectiveCharge[0] = 0.;
|
|
slaterEffectiveCharge[1] = 0.;
|
|
slaterEffectiveCharge[2] = 0.;
|
|
sCoefficient[0] = 0.;
|
|
sCoefficient[1] = 0.;
|
|
sCoefficient[2] = 0.;
|
|
}
|
|
|
|
else if (particleDefinition == instance->GetIon("alpha+"))
|
|
{
|
|
slaterEffectiveCharge[0] = 2.0;
|
|
// The following values are provided by M. Dingfelder (priv. comm)
|
|
slaterEffectiveCharge[1] = 2.0;
|
|
slaterEffectiveCharge[2] = 2.0;
|
|
//
|
|
sCoefficient[0] = 0.7;
|
|
sCoefficient[1] = 0.15;
|
|
sCoefficient[2] = 0.15;
|
|
}
|
|
|
|
else if (particleDefinition == instance->GetIon("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;
|
|
}
|
|
|
|
// if ( particleDefinition == instance->GetIon("helium")
|
|
// || particleDefinition == instance->GetIon("alpha+")
|
|
// || particleDefinition == instance->GetIon("alpha++")
|
|
// )
|
|
if (isHelium)
|
|
{
|
|
sigma = Gj[j] * (S / Bj[ionizationLevelIndex])
|
|
* ((F1 + w * F2)
|
|
/ (std::pow((1. + w), 3)
|
|
* (1. + G4Exp(alphaConst * (w - wc) / v))));
|
|
|
|
if (j == 4)
|
|
sigma = Gj[j]
|
|
* (S / waterStructure.IonisationEnergy(ionizationLevelIndex))
|
|
* ((F1 + w * F2)
|
|
/ (std::pow((1. + w), 3)
|
|
* (1. + G4Exp(alphaConst * (w - wc) / v))));
|
|
|
|
G4double zEff = particleDefinition->GetPDGCharge() / eplus
|
|
+ particleDefinition->GetLeptonNumber();
|
|
|
|
zEff -= (sCoefficient[0]
|
|
* S_1s(k, energyTransfer, slaterEffectiveCharge[0], 1.)
|
|
+ sCoefficient[1]
|
|
* S_2s(k, energyTransfer, slaterEffectiveCharge[1], 2.)
|
|
+ sCoefficient[2]
|
|
* S_2p(k, energyTransfer, slaterEffectiveCharge[2], 2.));
|
|
|
|
return zEff * zEff * sigma;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
|
|
|
G4double G4DNARuddIonisationModel::S_1s(G4double t,
|
|
G4double energyTransferred,
|
|
G4double slaterEffectiveChg,
|
|
G4double shellNumber)
|
|
{
|
|
// 1 - e^(-2r) * ( 1 + 2 r + 2 r^2)
|
|
// Dingfelder, in Chattanooga 2005 proceedings, formula (7)
|
|
|
|
G4double r = R(t, energyTransferred, slaterEffectiveChg, shellNumber);
|
|
G4double value = 1. - G4Exp(-2 * r) * ((2. * r + 2.) * r + 1.);
|
|
|
|
return value;
|
|
}
|
|
|
|
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
|
|
|
G4double G4DNARuddIonisationModel::S_2s(G4double t,
|
|
G4double energyTransferred,
|
|
G4double slaterEffectiveChg,
|
|
G4double shellNumber)
|
|
{
|
|
// 1 - e^(-2 r) * ( 1 + 2 r + 2 r^2 + 2 r^4)
|
|
// Dingfelder, in Chattanooga 2005 proceedings, formula (8)
|
|
|
|
G4double r = R(t, energyTransferred, slaterEffectiveChg, shellNumber);
|
|
G4double value = 1.
|
|
- G4Exp(-2 * r) * (((2. * r * r + 2.) * r + 2.) * r + 1.);
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
|
|
|
G4double G4DNARuddIonisationModel::S_2p(G4double t,
|
|
G4double energyTransferred,
|
|
G4double slaterEffectiveChg,
|
|
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 = R(t, energyTransferred, slaterEffectiveChg, 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 G4DNARuddIonisationModel::R(G4double t,
|
|
G4double energyTransferred,
|
|
G4double slaterEffectiveChg,
|
|
G4double shellNumber)
|
|
{
|
|
// tElectron = m_electron / m_alpha * t
|
|
// Dingfelder, in Chattanooga 2005 proceedings, p 4
|
|
|
|
G4double tElectron = 0.511 / 3728. * t;
|
|
// The following values are provided by M. Dingfelder (priv. comm)
|
|
G4double H = 2. * 13.60569172 * eV;
|
|
G4double value = std::sqrt(2. * tElectron / H) / (energyTransferred / H)
|
|
* (slaterEffectiveChg / shellNumber);
|
|
|
|
return value;
|
|
}
|
|
|
|
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
|
|
|
G4double G4DNARuddIonisationModel::CorrectionFactor(G4ParticleDefinition* particleDefinition,
|
|
G4double k)
|
|
{
|
|
G4DNAGenericIonsManager *instance;
|
|
instance = G4DNAGenericIonsManager::Instance();
|
|
|
|
if (particleDefinition == G4Proton::Proton())
|
|
{
|
|
return (1.);
|
|
} else if (particleDefinition == instance->GetIon("hydrogen"))
|
|
{
|
|
G4double value = (std::log10(k / eV) - 4.2) / 0.5;
|
|
// The following values are provided by M. Dingfelder (priv. comm)
|
|
return ((0.6 / (1 + G4Exp(value))) + 0.9);
|
|
} else
|
|
{
|
|
return (1.);
|
|
}
|
|
}
|
|
|
|
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
|
|
|
G4int G4DNARuddIonisationModel::RandomSelect(G4double k,
|
|
const G4String& particle)
|
|
{
|
|
|
|
// BEGIN PART 1/2 OF ELECTRON CORRECTION
|
|
|
|
// add ONE or TWO electron-water ionisation for alpha+ and helium
|
|
|
|
G4int level = 0;
|
|
|
|
// Retrieve data table corresponding to the current particle type
|
|
|
|
std::map<G4String, G4DNACrossSectionDataSet*, std::less<G4String> >::iterator pos;
|
|
pos = tableData.find(particle);
|
|
|
|
if (pos != tableData.end())
|
|
{
|
|
G4DNACrossSectionDataSet* table = pos->second;
|
|
|
|
if (table != 0)
|
|
{
|
|
G4double* valuesBuffer = new G4double[table->NumberOfComponents()];
|
|
|
|
const size_t n(table->NumberOfComponents());
|
|
size_t i(n);
|
|
G4double value = 0.;
|
|
|
|
while (i > 0)
|
|
{
|
|
i--;
|
|
valuesBuffer[i] = table->GetComponent(i)->FindValue(k);
|
|
value += valuesBuffer[i];
|
|
}
|
|
|
|
value *= G4UniformRand();
|
|
|
|
i = n;
|
|
|
|
while (i > 0)
|
|
{
|
|
i--;
|
|
|
|
if (valuesBuffer[i] > value)
|
|
{
|
|
delete[] valuesBuffer;
|
|
return i;
|
|
}
|
|
value -= valuesBuffer[i];
|
|
}
|
|
|
|
if (valuesBuffer)
|
|
delete[] valuesBuffer;
|
|
|
|
}
|
|
} else
|
|
{
|
|
G4Exception("G4DNARuddIonisationModel::RandomSelect",
|
|
"em0002",
|
|
FatalException,
|
|
"Model not applicable to particle type.");
|
|
}
|
|
|
|
return level;
|
|
}
|
|
|
|
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
|
|
|
G4double G4DNARuddIonisationModel::PartialCrossSection(const G4Track& track)
|
|
{
|
|
G4double sigma = 0.;
|
|
|
|
const G4DynamicParticle* particle = track.GetDynamicParticle();
|
|
G4double k = particle->GetKineticEnergy();
|
|
|
|
G4double lowLim = 0;
|
|
G4double highLim = 0;
|
|
|
|
const G4String& particleName = particle->GetDefinition()->GetParticleName();
|
|
|
|
std::map<G4String, G4double, std::less<G4String> >::iterator pos1;
|
|
pos1 = lowEnergyLimit.find(particleName);
|
|
|
|
if (pos1 != lowEnergyLimit.end())
|
|
{
|
|
lowLim = pos1->second;
|
|
}
|
|
|
|
std::map<G4String, G4double, std::less<G4String> >::iterator pos2;
|
|
pos2 = highEnergyLimit.find(particleName);
|
|
|
|
if (pos2 != highEnergyLimit.end())
|
|
{
|
|
highLim = pos2->second;
|
|
}
|
|
|
|
if (k >= lowLim && k <= highLim)
|
|
{
|
|
std::map<G4String, G4DNACrossSectionDataSet*, std::less<G4String> >::iterator pos;
|
|
pos = tableData.find(particleName);
|
|
|
|
if (pos != tableData.end())
|
|
{
|
|
G4DNACrossSectionDataSet* table = pos->second;
|
|
if (table != 0)
|
|
{
|
|
sigma = table->FindValue(k);
|
|
}
|
|
} else
|
|
{
|
|
G4Exception("G4DNARuddIonisationModel::PartialCrossSection",
|
|
"em0002",
|
|
FatalException,
|
|
"Model not applicable to particle type.");
|
|
}
|
|
}
|
|
|
|
return sigma;
|
|
}
|
|
|
|
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
|
|
|
G4double G4DNARuddIonisationModel::Sum(G4double /* energy */,
|
|
const G4String& /* particle */)
|
|
{
|
|
return 0;
|
|
}
|
|
|