Import Geant4 10.4.0.beta source tree

This commit is contained in:
Gabriele Cosmo
2017-06-30 10:49:55 +02:00
parent 3a5407696b
commit 1a1316fea4
2180 changed files with 237880 additions and 59109 deletions
@@ -0,0 +1,657 @@
//
// ********************************************************************
// * 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. *
// ********************************************************************
//
// CPA100 elastic model class for electrons
//
// Based on the work of M. Terrissol and M. C. Bordage
//
// Users are requested to cite the following papers:
// - M. Terrissol, A. Baudre, Radiat. Prot. Dosim. 31 (1990) 175-177
// - M.C. Bordage, J. Bordes, S. Edel, M. Terrissol, X. Franceries,
// M. Bardies, N. Lampe, S. Incerti, Phys. Med. 32 (2016) 1833-1840
//
// Authors of this class:
// M.C. Bordage, M. Terrissol, S. Edel, J. Bordes, S. Incerti
//
// 15.01.2014: creation
//
#include "G4DNACPA100ElasticModel.hh"
#include "G4PhysicalConstants.hh"
#include "G4SystemOfUnits.hh"
#include "G4DNAMolecularMaterial.hh"
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
using namespace std;
// #define CPA100_VERBOSE
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4DNACPA100ElasticModel::G4DNACPA100ElasticModel(const G4ParticleDefinition*,
const G4String& nam)
:G4VEmModel(nam),isInitialised(false)
{
//killBelowEnergy = 11. * eV; // Default
//killBelowEnergy = 10.481 * eV;
//lowEnergyLimit = 11 * eV;
//highEnergyLimit = 255955 * eV;
SetLowEnergyLimit(11*eV);
SetHighEnergyLimit(255955 * eV);
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
#ifdef UEHARA_VERBOSE
if( verboseLevel>0 )
{
G4cout << "CPA100 Elastic model is constructed " << G4endl
<< "Energy range: "
<< lowEnergyLimit / eV << " eV - "
<< highEnergyLimit / keV << " keV"
<< G4endl;
}
#endif
fParticleChangeForGamma = 0;
fpMolWaterDensity = 0;
// Selection of stationary mode
statCode = false;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4DNACPA100ElasticModel::~G4DNACPA100ElasticModel()
{
// For total 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;
}
// For final state
eVecm.clear();
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4DNACPA100ElasticModel::Initialise(const G4ParticleDefinition*
particle,
const G4DataVector& /*cuts*/)
{
#ifdef UEHARA_VERBOSE
if (verboseLevel > 3)
G4cout << "Calling G4DNACPA100ElasticModel::Initialise()" << G4endl;
#endif
if(particle->GetParticleName() != "e-")
{
G4Exception("*** WARNING: the G4DNACPA100ElasticModel is "
"not intented to be used with another particle than the electron",
"",FatalException,"") ;
}
// Energy limits
if (LowEnergyLimit() < 11.*eV)
{
G4cout << "G4DNACPA100ElasticModel: low energy limit increased from " <<
LowEnergyLimit()/eV << " eV to " << 11 << " eV" << G4endl;
SetLowEnergyLimit(11.*eV);
}
if (HighEnergyLimit() > 255955.*eV)
{
G4cout << "G4DNACPA100ElasticModel: high energy limit decreased from " <<
HighEnergyLimit()/keV << " keV to " << 255.955 << " keV"
<< G4endl;
SetHighEnergyLimit(255955.*eV);
}
// Reading of data files
G4double scaleFactor = 1e-20*m*m;
G4String fileElectron("dna/sigma_elastic_e_cpa100");
G4ParticleDefinition* electronDef = G4Electron::ElectronDefinition();
G4String electron;
// *** ELECTRON
// For total cross section
electron = electronDef->GetParticleName();
tableFile[electron] = fileElectron;
G4DNACrossSectionDataSet* tableE =
new G4DNACrossSectionDataSet(new G4LogLogInterpolation,
eV,scaleFactor );
/*
G4DNACrossSectionDataSet* tableE =
new G4DNACrossSectionDataSet(new G4DNACPA100LogLogInterpolation,
eV,scaleFactor );
*/
tableE->LoadData(fileElectron);
tableData[electron] = tableE;
// For final state
char *path = getenv("G4LEDATA");
if (!path)
{
G4Exception("G4DNACPA100ElasticModel::Initialise","em0006",
FatalException,"G4LEDATA environment variable not set.");
return;
}
std::ostringstream eFullFileName;
eFullFileName << path
<< "/dna/sigmadiff_cumulated_elastic_e_cpa100.dat";
std::ifstream eDiffCrossSection(eFullFileName.str().c_str());
if (!eDiffCrossSection)
G4Exception("G4DNACPA100ElasticModel::Initialise","em0003",
FatalException,
"Missing data file:/dna/sigmadiff_cumulated_elastic_e_cpa100.dat");
// March 25th, 2014 - Vaclav Stepan, Sebastien Incerti
// Added clear for MT
eTdummyVec.clear();
eVecm.clear();
eDiffCrossSectionData.clear();
//
eTdummyVec.push_back(0.);
while(!eDiffCrossSection.eof())
{
double tDummy;
double eDummy;
eDiffCrossSection>>tDummy>>eDummy;
// SI : mandatory eVecm initialization
if (tDummy != eTdummyVec.back())
{
eTdummyVec.push_back(tDummy);
eVecm[tDummy].push_back(0.);
}
eDiffCrossSection>>eDiffCrossSectionData[tDummy][eDummy];
if (eDummy != eVecm[tDummy].back()) eVecm[tDummy].push_back(eDummy);
}
// End final state
#ifdef UEHARA_VERBOSE
if (verboseLevel > 2)
G4cout << "Loaded cross section files for CPA100 Elastic model" << G4endl;
#endif
#ifdef UEHARA_VERBOSE
if( verboseLevel>0 )
{
G4cout << "CPA100 Elastic model is initialized " << G4endl
<< "Energy range: "
<< LowEnergyLimit() / eV << " eV - "
<< HighEnergyLimit() / keV << " keV"
<< G4endl;
}
#endif
// Initialize water density pointer
fpMolWaterDensity = G4DNAMolecularMaterial::Instance()
->GetNumMolPerVolTableFor(G4Material::GetMaterial("G4_WATER"));
if (isInitialised) { return; }
fParticleChangeForGamma = GetParticleChangeForGamma();
isInitialised = true;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4double G4DNACPA100ElasticModel::CrossSectionPerVolume
(const G4Material* material,
const G4ParticleDefinition* p,
G4double ekin,
G4double,
G4double)
{
#ifdef UEHARA_VERBOSE
if (verboseLevel > 3)
G4cout <<
"Calling CrossSectionPerVolume() of G4DNACPA100ElasticModel" << G4endl;
#endif
// Calculate total cross section for model
G4double sigma=0;
G4double waterDensity = (*fpMolWaterDensity)[material->GetIndex()];
if(waterDensity!= 0.0)
{
const G4String& particleName = p->GetParticleName();
if (ekin < HighEnergyLimit() && ekin >= LowEnergyLimit())
{
//SI : XS must not be zero otherwise sampling of secondaries
// method ignored
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(ekin);
//
//Dump in non-MT mode
//
/*
G4double minEnergy = 10.481 * eV;
G4double maxEnergy = 255955. * eV;
G4int nEnergySteps = 1000;
G4double energy(minEnergy);
G4double
stpEnergy(std::pow(maxEnergy/energy,
1./static_cast<G4double>(nEnergySteps-1)));
G4int step(nEnergySteps);
system ("rm -rf elastic-cpa100.out");
FILE* myFile=fopen("elastic-cpa100.out","a");
while (step>0)
{
step--;
fprintf (myFile,"%16.9le %16.9le\n",
energy/eV,
table->FindValue(energy)/(1e-20*m*m));
energy*=stpEnergy;
}
fclose (myFile);
abort();
*/
//
// end of dump
//
}
}
else
{
G4Exception("G4DNACPA100ElasticModel::ComputeCrossSectionPerVolume",
"em0002",
FatalException,"Model not applicable to particle type.");
}
}
#ifdef UEHARA_VERBOSE
if (verboseLevel > 2)
{
G4cout << "__________________________________" << G4endl;
G4cout << "G4DNACPA100ElasticModel - XS INFO START" << G4endl;
G4cout << "Kinetic energy(eV)=" << ekin/eV << " particle : " << particleName << 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 << "G4DNACPA100ElasticModel - XS INFO END" << G4endl;
}
#endif
}
return sigma*waterDensity;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4DNACPA100ElasticModel::SampleSecondaries(std::vector<G4DynamicParticle*>* /*fvect*/,
const G4MaterialCutsCouple* /*couple*/,
const G4DynamicParticle* aDynamicElectron,
G4double,
G4double)
{
#ifdef UEHARA_VERBOSE
if (verboseLevel > 3)
G4cout << "Calling SampleSecondaries() of G4DNACPA100ElasticModel" << G4endl;
#endif
G4double electronEnergy0 = aDynamicElectron->GetKineticEnergy();
{
G4double cosTheta = RandomizeCosTheta(electronEnergy0);
G4double phi = 2. * pi * G4UniformRand();
G4ThreeVector zVers = aDynamicElectron->GetMomentumDirection();
//G4ThreeVector xVers = zVers.orthogonal();
//G4ThreeVector yVers = zVers.cross(xVers);
//G4double xDir = std::sqrt(1. - cosTheta*cosTheta);
//G4double yDir = xDir;
//xDir *= std::cos(phi);
//yDir *= std::sin(phi);
// Computation of scattering angles (from Subroutine DIRAN in CPA100)
G4double CT1, ST1, CF1, SF1, CT2, ST2, CF2, SF2;
G4double sinTheta = std::sqrt (1-cosTheta*cosTheta);
CT1=0;
ST1=0;
CF1=0;
SF1=0;
CT2=0;
ST2=0;
CF2=0;
SF2=0;
CT1 = zVers.z();
ST1=std::sqrt(1.-CT1*CT1);
if (ST1!=0) CF1 = zVers.x()/ST1; else CF1 = std::cos(2. * pi * G4UniformRand());
if (ST1!=0) SF1 = zVers.y()/ST1; else SF1 = std::sqrt(1.-CF1*CF1);
G4double A3, A4, A5, A2, A1;
A3=0;
A4=0;
A5=0;
A2=0;
A1=0;
A3 = sinTheta*std::cos(phi);
A4 = A3*CT1 + ST1*cosTheta;
A5 = sinTheta * std::sin(phi);
A2 = A4 * SF1 + A5 * CF1;
A1 = A4 * CF1 - A5 * SF1;
CT2 = CT1*cosTheta - ST1*A3;
ST2 = std::sqrt(1.-CT2*CT2);
if (ST2==0) ST2=1E-6;
CF2 = A1/ST2;
SF2 = A2/ST2;
/*
G4cout << "CT1=" << CT1 << G4endl;
G4cout << "ST1=" << ST1 << G4endl;
G4cout << "CF1=" << CF1 << G4endl;
G4cout << "SF1=" << SF1 << G4endl;
G4cout << "cosTheta=" << cosTheta << G4endl;
G4cout << "sinTheta=" << sinTheta << G4endl;
G4cout << "cosPhi=" << std::cos(phi) << G4endl;
G4cout << "sinPhi=" << std::sin(phi) << G4endl;
G4cout << "CT2=" << CT2 << G4endl;
G4cout << "ST2=" << ST2 << G4endl;
G4cout << "CF2=" << CF2 << G4endl;
G4cout << "SF2=" << SF2 << G4endl;
*/
G4ThreeVector zPrimeVers(ST2*CF2,ST2*SF2,CT2);
//
fParticleChangeForGamma->ProposeMomentumDirection(zPrimeVers.unit()) ;
//fParticleChangeForGamma->SetProposedKineticEnergy(electronEnergy0);
if (!statCode)
fParticleChangeForGamma->SetProposedKineticEnergy
(electronEnergy0-1.214E-4*(1.-cosTheta)*electronEnergy0);
else fParticleChangeForGamma->SetProposedKineticEnergy(electronEnergy0);
fParticleChangeForGamma->ProposeLocalEnergyDeposit(1.214E-4*(1.-cosTheta)*electronEnergy0);
}
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4double G4DNACPA100ElasticModel::Theta
(G4ParticleDefinition * particleDefinition, G4double k, G4double integrDiff)
{
G4double theta = 0.;
G4double valueT1 = 0;
G4double valueT2 = 0;
G4double valueE21 = 0;
G4double valueE22 = 0;
G4double valueE12 = 0;
G4double valueE11 = 0;
G4double xs11 = 0;
G4double xs12 = 0;
G4double xs21 = 0;
G4double xs22 = 0;
if (particleDefinition == G4Electron::ElectronDefinition())
{
std::vector<double>::iterator t2 = std::upper_bound(eTdummyVec.begin(),eTdummyVec.end(), k);
std::vector<double>::iterator t1 = t2-1;
std::vector<double>::iterator e12 = std::upper_bound(eVecm[(*t1)].begin(),eVecm[(*t1)].end(),
integrDiff);
std::vector<double>::iterator e11 = e12-1;
std::vector<double>::iterator e22 = std::upper_bound(eVecm[(*t2)].begin(),eVecm[(*t2)].end(),
integrDiff);
std::vector<double>::iterator e21 = e22-1;
valueT1 =*t1;
valueT2 =*t2;
valueE21 =*e21;
valueE22 =*e22;
valueE12 =*e12;
valueE11 =*e11;
xs11 = eDiffCrossSectionData[valueT1][valueE11];
xs12 = eDiffCrossSectionData[valueT1][valueE12];
xs21 = eDiffCrossSectionData[valueT2][valueE21];
xs22 = eDiffCrossSectionData[valueT2][valueE22];
//FOR CPA100
//if(k==valueT1) xs22 = eDiffCrossSectionData[valueT1][valueE12];
}
if (xs11==0 && xs12==0 && xs21==0 && xs22==0) return (0.);
// FOR CPA100
theta = QuadInterpolator ( valueE11, valueE12,
valueE21, valueE22,
xs11, xs12,
xs21, xs22,
valueT1, valueT2,
k, integrDiff );
return theta;
//FOR CPA100
//return xs22;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4double G4DNACPA100ElasticModel::LinLogInterpolate(G4double e1,
G4double e2,
G4double e,
G4double xs1,
G4double xs2)
{
G4double d1 = std::log(xs1);
G4double d2 = std::log(xs2);
G4double value = std::exp(d1 + (d2 - d1)*(e - e1)/ (e2 - e1));
return value;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4double G4DNACPA100ElasticModel::LinLinInterpolate(G4double e1,
G4double e2,
G4double e,
G4double xs1,
G4double xs2)
{
G4double d1 = xs1;
G4double d2 = xs2;
G4double value = (d1 + (d2 - d1)*(e - e1)/ (e2 - e1));
return value;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4double G4DNACPA100ElasticModel::LogLogInterpolate(G4double e1,
G4double e2,
G4double e,
G4double xs1,
G4double xs2)
{
G4double a = (std::log10(xs2)-std::log10(xs1)) / (std::log10(e2)-std::log10(e1));
G4double b = std::log10(xs2) - a*std::log10(e2);
G4double sigma = a*std::log10(e) + b;
G4double value = (std::pow(10.,sigma));
return value;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4double G4DNACPA100ElasticModel::QuadInterpolator(G4double e11, G4double e12,
G4double e21, G4double e22,
G4double xs11, G4double xs12,
G4double xs21, G4double xs22,
G4double t1, G4double t2,
G4double t, G4double e)
{
// Log-Log
/*
G4double interpolatedvalue1 = LogLogInterpolate(e11, e12, e, xs11, xs12);
G4double interpolatedvalue2 = LogLogInterpolate(e21, e22, e, xs21, xs22);
G4double value = LogLogInterpolate(t1, t2, t, interpolatedvalue1, interpolatedvalue2);
// Lin-Log
G4double interpolatedvalue1 = LinLogInterpolate(e11, e12, e, xs11, xs12);
G4double interpolatedvalue2 = LinLogInterpolate(e21, e22, e, xs21, xs22);
G4double value = LinLogInterpolate(t1, t2, t, interpolatedvalue1, interpolatedvalue2);
*/
// Lin-Lin
G4double interpolatedvalue1 = LinLinInterpolate(e11, e12, e, xs11, xs12);
G4double interpolatedvalue2 = LinLinInterpolate(e21, e22, e, xs21, xs22);
G4double value = LinLinInterpolate(t1, t2, t, interpolatedvalue1, interpolatedvalue2);
return value;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4double G4DNACPA100ElasticModel::RandomizeCosTheta(G4double k)
{
G4double integrdiff=0; // PROBABILITY between 0 and 1.
G4double uniformRand=G4UniformRand();
integrdiff = uniformRand;
G4double cosTheta=0.;
// 1 - COS THETA is read from the data file
cosTheta = 1 - Theta(G4Electron::ElectronDefinition(),k/eV,integrdiff);
//
//
//Dump
//
//G4cout << "theta=" << theta << G4endl;
//G4cout << "cos theta=" << std::cos(theta*pi/180) << G4endl;
//G4cout << "sin theta=" << std::sin(theta*pi/180) << G4endl;
//G4cout << "acos(cos theta)=" << std::acos(cosTheta) << G4endl;
//G4cout << "cos theta="<< cosTheta << G4endl;
//G4cout << "1 - cos theta="<< 1. - cosTheta << G4endl;
//G4cout << "sin theta=" << std::sqrt(1-cosTheta*cosTheta) << G4endl;
//
/*
G4double minProb = 0; // we scan probability between 0 and one
G4double maxProb = 1;
G4int nProbSteps = 100;
G4double prob(minProb);
G4double stepProb((maxProb-minProb)/static_cast<G4double>(nProbSteps));
G4int step(nProbSteps);
system ("rm -rf elastic-cumul-cpa100-100keV.out");
FILE* myFile=fopen("elastic-cumul-cpa100-100keV.out","a");
while (step>=0)
{
step--;
fprintf (myFile,"%16.9le %16.9le\n",
prob,
Theta(G4Electron::ElectronDefinition(),100000,prob)); // SELECT NRJ IN eV !!!
prob=prob+stepProb;
}
fclose (myFile);
abort();
*/
//
// end of dump
//
return cosTheta;
}
@@ -0,0 +1,469 @@
//
// ********************************************************************
// * 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. *
// ********************************************************************
//
// CPA100 excitation model class for electrons
//
// Based on the work of M. Terrissol and M. C. Bordage
//
// Users are requested to cite the following papers:
// - M. Terrissol, A. Baudre, Radiat. Prot. Dosim. 31 (1990) 175-177
// - M.C. Bordage, J. Bordes, S. Edel, M. Terrissol, X. Franceries,
// M. Bardies, N. Lampe, S. Incerti, Phys. Med. 32 (2016) 1833-1840
//
// Authors of this class:
// M.C. Bordage, M. Terrissol, S. Edel, J. Bordes, S. Incerti
//
// 15.01.2014: creation
//
#include "G4DNACPA100ExcitationModel.hh"
#include "G4SystemOfUnits.hh"
#include "G4PhysicalConstants.hh"
#include "G4DNAChemistryManager.hh"
#include "G4DNAMolecularMaterial.hh"
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
using namespace std;
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4DNACPA100ExcitationModel::G4DNACPA100ExcitationModel(const G4ParticleDefinition*,
const G4String& nam)
:G4VEmModel(nam),isInitialised(false)
{
fpMolWaterDensity = 0;
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 << "CPA100 excitation model is constructed " << G4endl;
}
fParticleChangeForGamma = 0;
// Selection of stationary mode
statCode = false;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4DNACPA100ExcitationModel::~G4DNACPA100ExcitationModel()
{
// 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;
}
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4DNACPA100ExcitationModel::Initialise(const G4ParticleDefinition* particle,
const G4DataVector& /*cuts*/)
{
if (verboseLevel > 3)
G4cout << "Calling G4DNACPA100ExcitationModel::Initialise()" << G4endl;
G4String fileElectron("dna/sigma_excitation_e_cpa100");
G4ParticleDefinition* electronDef = G4Electron::ElectronDefinition();
G4String electron;
G4double scaleFactor = 1.e-20 *m*m;
// *** ELECTRON
electron = electronDef->GetParticleName();
tableFile[electron] = fileElectron;
lowEnergyLimit[electron] = 11 * eV; // Default low enetgy limit
//lowEnergyLimit[electron] = 10.481 * eV; // From sigexi2 file by MCB
highEnergyLimit[electron] = 255955 * eV; // idem
// Cross section
G4DNACrossSectionDataSet* tableE
= new G4DNACrossSectionDataSet(new G4LogLogInterpolation, eV, scaleFactor );
/*
G4DNACrossSectionDataSet* tableE =
new G4DNACrossSectionDataSet(new G4DNACPA100LogLogInterpolation, eV, scaleFactor );
*/
tableE->LoadData(fileElectron);
tableData[electron] = tableE;
//
if (particle==electronDef)
{
SetLowEnergyLimit(lowEnergyLimit[electron]);
SetHighEnergyLimit(highEnergyLimit[electron]);
}
// if( verboseLevel>0 )
{
G4cout << "CPA100 excitation model is initialized " << G4endl
<< "Energy range: "
<< LowEnergyLimit() / eV << " eV - "
<< HighEnergyLimit() / keV << " keV for "
<< particle->GetParticleName()
<< G4endl;
}
// Initialize water density pointer
fpMolWaterDensity =
G4DNAMolecularMaterial::Instance()->GetNumMolPerVolTableFor(G4Material::GetMaterial("G4_WATER"));
if (isInitialised) { return; }
fParticleChangeForGamma = GetParticleChangeForGamma();
isInitialised = true;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4double G4DNACPA100ExcitationModel::CrossSectionPerVolume(const G4Material* material,
const G4ParticleDefinition* particleDefinition,
G4double ekin,
G4double,
G4double)
{
if (verboseLevel > 3)
G4cout << "Calling CrossSectionPerVolume() of G4DNACPA100ExcitationModel" << G4endl;
if (particleDefinition != G4Electron::ElectronDefinition()) return 0;
// Calculate total cross section for model
G4double lowLim = 0;
G4double highLim = 0;
G4double sigma=0;
G4double waterDensity = (*fpMolWaterDensity)[material->GetIndex()];
if(waterDensity!= 0.0)
{
const G4String& particleName = particleDefinition->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 (ekin > lowLim && ekin < 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(ekin);
}
}
else
{
G4Exception("G4DNACPA100ExcitationModel::CrossSectionPerVolume","em0002",
FatalException,"Model not applicable to particle type.");
}
}
if (verboseLevel > 2)
{
G4cout << "__________________________________" << G4endl;
G4cout << "G4DNACPA100ExcitationModel - XS INFO START" << G4endl;
G4cout << "Kinetic energy(eV)=" << ekin/eV << " particle : " << particleName << 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 << "G4DNACPA100ExcitationModel - XS INFO END" << G4endl;
}
} // if (waterMaterial)
return sigma*waterDensity;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4DNACPA100ExcitationModel::SampleSecondaries(std::vector<G4DynamicParticle*>* ,
const G4MaterialCutsCouple*,
const G4DynamicParticle* aDynamicParticle,
G4double,
G4double)
{
if (verboseLevel > 3)
G4cout << "Calling SampleSecondaries() of G4DNACPA100ExcitationModel" << G4endl;
G4double k = aDynamicParticle->GetKineticEnergy();
const G4String& particleName = aDynamicParticle->GetDefinition()->GetParticleName();
G4int level = RandomSelect(k,particleName);
G4double excitationEnergy = waterStructure.ExcitationEnergy(level);
G4double newEnergy = k - excitationEnergy;
if (newEnergy > 0)
{
// fParticleChangeForGamma->ProposeMomentumDirection(aDynamicParticle->GetMomentumDirection());
// We take into account direction change as described page 87 (II.92) in thesis by S. Edel
G4double cosTheta =
(excitationEnergy/k) / (1. + (k/(2*electron_mass_c2))*(1.-excitationEnergy/k) );
cosTheta = std::sqrt(1.-cosTheta);
G4double phi = 2. * pi * G4UniformRand();
G4ThreeVector zVers = aDynamicParticle->GetMomentumDirection();
//G4ThreeVector xVers = zVers.orthogonal();
//G4ThreeVector yVers = zVers.cross(xVers);
//G4double xDir = std::sqrt(1. - cosTheta*cosTheta);
//G4double yDir = xDir;
//xDir *= std::cos(phi);
//yDir *= std::sin(phi);
// G4ThreeVector zPrimeVers((xDir*xVers + yDir*yVers + cosTheta*zVers));
// Computation of scattering angles (from Subroutine DIRAN in CPA100)
G4double CT1, ST1, CF1, SF1, CT2, ST2, CF2, SF2;
G4double sinTheta = std::sqrt (1-cosTheta*cosTheta);
CT1=0;
ST1=0;
CF1=0;
SF1=0;
CT2=0;
ST2=0;
CF2=0;
SF2=0;
CT1 = zVers.z();
ST1=std::sqrt(1.-CT1*CT1);
if (ST1!=0) CF1 = zVers.x()/ST1; else CF1 = std::cos(2. * pi * G4UniformRand());
if (ST1!=0) SF1 = zVers.y()/ST1; else SF1 = std::sqrt(1.-CF1*CF1);
G4double A3, A4, A5, A2, A1;
A3=0;
A4=0;
A5=0;
A2=0;
A1=0;
A3 = sinTheta*std::cos(phi);
A4 = A3*CT1 + ST1*cosTheta;
A5 = sinTheta * std::sin(phi);
A2 = A4 * SF1 + A5 * CF1;
A1 = A4 * CF1 - A5 * SF1;
CT2 = CT1*cosTheta - ST1*A3;
ST2 = std::sqrt(1.-CT2*CT2);
if (ST2==0) ST2=1E-6;
CF2 = A1/ST2;
SF2 = A2/ST2;
/*
G4cout << "CT1=" << CT1 << G4endl;
G4cout << "ST1=" << ST1 << G4endl;
G4cout << "CF1=" << CF1 << G4endl;
G4cout << "SF1=" << SF1 << G4endl;
G4cout << "cosTheta=" << cosTheta << G4endl;
G4cout << "sinTheta=" << sinTheta << G4endl;
G4cout << "cosPhi=" << std::cos(phi) << G4endl;
G4cout << "sinPhi=" << std::sin(phi) << G4endl;
G4cout << "CT2=" << CT2 << G4endl;
G4cout << "ST2=" << ST2 << G4endl;
G4cout << "CF2=" << CF2 << G4endl;
G4cout << "SF2=" << SF2 << G4endl;
*/
G4ThreeVector zPrimeVers(ST2*CF2,ST2*SF2,CT2);
//
fParticleChangeForGamma->ProposeMomentumDirection(zPrimeVers.unit()) ;
//
if (!statCode) fParticleChangeForGamma->SetProposedKineticEnergy(newEnergy);
else fParticleChangeForGamma->SetProposedKineticEnergy(k);
fParticleChangeForGamma->ProposeLocalEnergyDeposit(excitationEnergy);
}
// Chemistry
const G4Track * theIncomingTrack = fParticleChangeForGamma->GetCurrentTrack();
G4DNAChemistryManager::Instance()->CreateWaterMolecule(eExcitedMolecule,
level,
theIncomingTrack);
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4int G4DNACPA100ExcitationModel::RandomSelect(G4double k, const G4String& particle)
{
G4int level = 0;
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.;
//Verification
/*
G4double tmp=10.481*eV;
G4cout << table->GetComponent(0)->FindValue(tmp)/(1e-20*m*m) << G4endl;
G4cout << table->GetComponent(1)->FindValue(tmp)/(1e-20*m*m) << G4endl;
G4cout << table->GetComponent(2)->FindValue(tmp)/(1e-20*m*m) << G4endl;
G4cout << table->GetComponent(3)->FindValue(tmp)/(1e-20*m*m) << G4endl;
G4cout << table->GetComponent(4)->FindValue(tmp)/(1e-20*m*m) << G4endl;
G4cout <<
table->GetComponent(0)->FindValue(tmp)/(1e-20*m*m) +
table->GetComponent(1)->FindValue(tmp)/(1e-20*m*m) +
table->GetComponent(2)->FindValue(tmp)/(1e-20*m*m) +
table->GetComponent(3)->FindValue(tmp)/(1e-20*m*m) +
table->GetComponent(4)->FindValue(tmp)/(1e-20*m*m)
<< G4endl;
abort();
*/
//
//Dump
//
/*
G4double minEnergy = 10.481 * eV;
G4double maxEnergy = 255955. * eV;
G4int nEnergySteps = 1000;
G4double energy(minEnergy);
G4double stpEnergy(std::pow(maxEnergy/energy, 1./static_cast<G4double>(nEnergySteps-1)));
G4int step(nEnergySteps);
system ("rm -rf excitation-cap100.out");
FILE* myFile=fopen("excitation-cpa100.out","a");
while (step>0)
{
step--;
fprintf (myFile,"%16.9le %16.9le %16.9le %16.9le %16.9le %16.9le %16.9le \n",
energy/eV,
table->GetComponent(0)->FindValue(energy)/(1e-20*m*m),
table->GetComponent(1)->FindValue(energy)/(1e-20*m*m),
table->GetComponent(2)->FindValue(energy)/(1e-20*m*m),
table->GetComponent(3)->FindValue(energy)/(1e-20*m*m),
table->GetComponent(4)->FindValue(energy)/(1e-20*m*m),
table->GetComponent(0)->FindValue(energy)/(1e-20*m*m)+
table->GetComponent(1)->FindValue(energy)/(1e-20*m*m)+
table->GetComponent(2)->FindValue(energy)/(1e-20*m*m)+
table->GetComponent(3)->FindValue(energy)/(1e-20*m*m)+
table->GetComponent(4)->FindValue(energy)/(1e-20*m*m)
);
energy*=stpEnergy;
}
fclose (myFile);
abort();
*/
//
// end of dump
//
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("G4DNACPA100ExcitationModel::RandomSelect","em0002",
FatalException,"Model not applicable to particle type.");
}
return level;
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,79 @@
//
// ********************************************************************
// * 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. *
// ********************************************************************
//
//
// Contact authors: S. Meylan, C. Villagrasa
//
// email: sylvain.meylan@symalgo-tech.com, carmen.villagrasa@irsn.fr
#include "../include/G4DNADummyModel.hh"
#include "G4SystemOfUnits.hh"
G4DNADummyModel::G4DNADummyModel(const G4String& applyToMaterial, const G4ParticleDefinition* p, const G4String& nam, G4VEmModel* emModel)
: G4VDNAModel(nam, applyToMaterial)
{
fpEmModel = emModel;
fpParticleDef = p;
}
G4DNADummyModel::~G4DNADummyModel()
{
// There is no need to delete the model because it will be done in some G4 class.
//if(fpEmModel) delete fpEmModel;
}
void G4DNADummyModel::Initialise(const G4ParticleDefinition* particle, const G4DataVector& v, G4ParticleChangeForGamma* changeForGamme)
{
fMaterialMolPerVol = G4DNAMolecularMaterial::Instance()->GetNumMolPerVolTableFor(G4Material::GetMaterial("G4_WATER") );
fpEmModel->SetParticleChange(changeForGamme, nullptr);
fpEmModel->Initialise(particle, v);
// MatManagSys
EnableForMaterialAndParticle("G4_WATER", fpParticleDef->GetParticleName() );
SetLowELimit("G4_WATER", fpParticleDef->GetParticleName(), fpEmModel->LowEnergyLimit() );
SetHighELimit("G4_WATER",fpParticleDef->GetParticleName(), fpEmModel->HighEnergyLimit() );
}
G4double G4DNADummyModel::CrossSectionPerVolume(const G4Material* material, const G4String& /*materialName*/, const G4ParticleDefinition* p, G4double ekin, G4double emin, G4double emax)
{
G4double crossSectionTimesDensity = fpEmModel->CrossSectionPerVolume(material, p, ekin, emin, emax);
G4double crossSection = crossSectionTimesDensity / GetNumMoleculePerVolumeUnitForMaterial(G4Material::GetMaterial("G4_WATER") );
return crossSection;
}
void G4DNADummyModel::SampleSecondaries(std::vector<G4DynamicParticle*>* a, const G4MaterialCutsCouple* b, const G4String& /*materialName*/, const G4DynamicParticle* c, G4ParticleChangeForGamma* /*particleChangeForGamma*/, G4double tmin, G4double tmax)
{
fpEmModel->SampleSecondaries(a, b, c, tmin, tmax);
}
G4double G4DNADummyModel::GetNumMoleculePerVolumeUnitForMaterial(const G4Material* mat)
{
return fMaterialMolPerVol->at(mat->GetIndex() );
}
@@ -0,0 +1,646 @@
//
// ********************************************************************
// * 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. *
// ********************************************************************
//
//
// Contact authors: S. Meylan, C. Villagrasa
//
// email: sylvain.meylan@symalgo-tech.com, carmen.villagrasa@irsn.fr
#include "G4DNAModelInterface.hh"
#include "G4PhysicalConstants.hh"
#include "G4SystemOfUnits.hh"
#include "G4DNAMolecularMaterial.hh"
G4DNAModelInterface::G4DNAModelInterface(const G4String &nam)
: G4VEmModel(nam), fName(nam), fpParticleChangeForGamma(0), fSampledMat("")
{
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4DNAModelInterface::~G4DNAModelInterface()
{
// Loop on all the registered models to properly delete them (free the memory)
for(unsigned int i=0, ie = fRegisteredModels.size(); i<ie; ++i)
{
if(fRegisteredModels.at(i) != nullptr) delete fRegisteredModels.at(i);
}
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4DNAModelInterface::Initialise(const G4ParticleDefinition* particle,
const G4DataVector& cuts)
{
// Those two statements are necessary to override the energy limits set in the G4DNAProcesses (ionisation, elastic, etc...).
// Indeed, with the ModelInterface system, the model define themselves their energy limits per material and particle.
// Therefore, such a limit should not be in the G4DNAProcess classes.
//
SetLowEnergyLimit(0.);
SetHighEnergyLimit(DBL_MAX);
fpParticleChangeForGamma = GetParticleChangeForGamma();
// Loop on all the registered models to initialise them
for(unsigned int i=0, ie = fRegisteredModels.size(); i<ie; ++i)
{
fRegisteredModels.at(i)->Initialise(particle, cuts, fpParticleChangeForGamma);
}
// Build the [material][particle]=Models table
// used to retrieve the model corresponding to the current material/particle couple
BuildMaterialParticleModelTable(particle);
BuildMaterialMolPerVolTable();
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4double G4DNAModelInterface::CrossSectionPerVolume(const G4Material* material,
const G4ParticleDefinition* p,
G4double ekin,
G4double emin,
G4double emax)
{
// Method to return the crossSection * nbMoleculePerUnitVolume to the process class.
// Process class then calculates the path.
// The cross section is calculated in the registered model(s) and this class just call the method
// Two cases are handled here: normal material and composite material.
//
// Idea:
// *** Simple material ***
// Ask for the cross section of the chosen model.
// Multiply it by the number of medium molecules per volume unit.
// Return the value.
// *** Composite material ***
// Ask for the cross section of the chosen model for each component.
// Apply a factor to each cross section and sum the results. The factor is the molecule number of component per composite volume unit.
// The total cross section is returned.
// To reset the sampledMat variable.
// Can be used by user to retrieve current component
fSampledMat = "";
// This is the value to be sum up and to be returned at then end
G4double crossSectionTimesNbMolPerVol (0);
// Reset the map saving the material and the cumulated corresponding cross section
// Used in SampleSecondaries if the interaction is selected for the step and if the material is a composite
fMaterialCS.clear();
// This is the value to be used by SampleSecondaries
fCSsumTot = 0;
// *****************************
// Material is not a composite
// *****************************
//
if(material->GetMatComponents().empty())
{
// Get the material name
const G4String& materialName = material->GetName();
// Use the table to get the model
G4VDNAModel* model = GetDNAModel(materialName, p->GetParticleName(), ekin);
// Get the nunber of molecules per volume unit for that material
G4double nbOfMoleculePerVolumeUnit = GetNumMoleculePerVolumeUnitForMaterial(material);
// Calculate the cross section times the number of molecules
if(model != 0)
crossSectionTimesNbMolPerVol = nbOfMoleculePerVolumeUnit * model->CrossSectionPerVolume(material, materialName, p, ekin, emin, emax);
else // no model was selected, we are out of the energy ranges
crossSectionTimesNbMolPerVol = 0.;
}
// ********************************
// Material is a composite
// ********************************
//
else
{
// Copy the map in a local variable
// Otherwise we get segmentation fault and iterator pointing to nowhere: do not know why...
// Maybe MatComponents map is overrided by something somewhere ?
std::map<G4Material*, G4double> componentsMap = material->GetMatComponents();
// Retrieve the iterator
std::map<G4Material*, G4double>::const_iterator it = componentsMap.begin();
// Get the size
unsigned int componentNumber = componentsMap.size();
// Loop on all the components
//for(it = material->GetMatComponents().begin(); it!=material->GetMatComponents().end();++it)
for(unsigned int i=0; i<componentNumber; ++i)
{
// Get the current component
G4Material* component = it->first;
// Get the current component mass fraction
//G4double massFraction = it->second;
// Get the number of component molecules in a volume unit of composite material
G4double nbMoleculeOfComponentInCompositeMat = GetNumMolPerVolUnitForComponentInComposite(component, material);
// Get the current component name
const G4String componentName = component->GetName();
// Retrieve the model corresponding to the current component (ie material)
G4VDNAModel* model = GetDNAModel(componentName, p->GetParticleName(), ekin);
// Add the component part of the cross section to the cross section variable.
// The component cross section is multiplied by the total molecule number in the composite scaled by the mass fraction.
if(model != 0)
crossSectionTimesNbMolPerVol =
nbMoleculeOfComponentInCompositeMat * model->CrossSectionPerVolume(component, componentName, p, ekin, emin, emax);
else // no model was selected, we are out of the energy ranges
crossSectionTimesNbMolPerVol = 0.;
// Save the component name and its calculated crossSectionTimesNbMolPerVol
// To be used by sampling secondaries if the interaction is selected for the step
fMaterialCS[componentName] = crossSectionTimesNbMolPerVol;
// Save the component name and its calculated crossSectionTimesNbMolPerVol
// To be used by sampling secondaries if the interaction is selected for the step
fCSsumTot += crossSectionTimesNbMolPerVol;
// Move forward the iterator
++it;
}
crossSectionTimesNbMolPerVol = fCSsumTot;
}
// return the cross section times the number of molecules
// the path of the interaction will be calculated using that value
return crossSectionTimesNbMolPerVol;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4DNAModelInterface::SampleSecondaries(std::vector<G4DynamicParticle*>* fVect,
const G4MaterialCutsCouple* couple,
const G4DynamicParticle* aDynamicParticle,
G4double tmin,
G4double tmax)
{
// To call the sampleSecondaries method of the registered model(s)
// In the case of composite material, we need to choose a component to call the method from.
// To do so we use a random sampling on the crossSectionTimesNbMolPerVol used in CrossSectionPerVolume method.
// If we enter that method it means the corresponding interaction (and process) has been chosen for the current step.
G4String materialName;
// *******************************
// Material is not a composite
// *******************************
//
if(couple->GetMaterial()->GetMatComponents().empty())
{
materialName = couple->GetMaterial()->GetName();
}
// ****************************
// Material is a composite
// ****************************
//
else
{
// Material is a composite
// We need to select a component
// We select a random number between 0 and fCSSumTot
G4double rand = G4UniformRand()*fCSsumTot;
G4double cumulCS (0);
G4bool result = false;
// We loop on each component cumulated cross section
//
// Retrieve the iterators
std::map<const G4String , G4double>::const_iterator it = fMaterialCS.begin();
std::map<const G4String , G4double>::const_iterator ite = fMaterialCS.end();
// While this is true we do not have found our component.
while(rand>cumulCS)
{
// Check if the sampling is ok
if(it==ite)
{
G4Exception("G4DNAModelManager::SampleSecondaries","em0006",
FatalException,
"The random component selection has failed: we ran into the end of the map without having a selected component");
return; // to make some compilers happy
}
// Set the cumulated value for the iteration
cumulCS += it->second;
// Check if we have reach the material to be selected
// The DBL_MAX is here to take into account a return DBL_MAX in CSPerVol for the elastic model
// to force elastic sampleSecondaries where the particle can be killed.
// Used when paticle energy is lower than limit.
if(rand<cumulCS || cumulCS >= DBL_MAX)
{
// we have our selected material
materialName = it->first;
result = true;
break;
}
// make the iterator move forward
++it;
}
// Check that we get a result
if(!result)
{
// it is possible to end up here if the return DBL_MAX of CSPerVol in the elastic model is not taken into account
G4Exception("G4DNAModelManager::SampleSecondaries","em0006",
FatalException,
"The random component selection has failed: while loop ended without a selected component.");
return; // to make some compilers happy
}
}
// **************************************
// Call the SampleSecondaries method
// **************************************
// Rename material if modified NIST material
// This is needed when material is obtained from G4MaterialCutsCouple
if(materialName.find("_MODIFIED")!=G4String::npos)
{
materialName = materialName.substr(0,materialName.size()-9);
}
fSampledMat = materialName;
G4VDNAModel* model = GetDNAModel(materialName,
aDynamicParticle->GetParticleDefinition()->GetParticleName(),
aDynamicParticle->GetKineticEnergy() );
//fMaterialParticleModelTable[materialName][aDynamicParticle->GetDefinition()->GetParticleName()][0];
model->SampleSecondaries(fVect, couple, materialName, aDynamicParticle, fpParticleChangeForGamma, tmin, tmax);
}
void G4DNAModelInterface::RegisterModel(G4VDNAModel* model)
{
fRegisteredModels.push_back(model);
}
void G4DNAModelInterface::RegisterModel(G4VEmModel* model, const G4ParticleDefinition* particle)
{
G4DNADummyModel* dummyWrapper = new G4DNADummyModel("G4_WATER", particle, model->GetName(), model);
RegisterModel(dummyWrapper);
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4DNAModelInterface::BuildMaterialParticleModelTable(const G4ParticleDefinition* p)
{
// Method to build a map: [material][particle] = Model*.
// The map is used to retrieve the correct model for the current particle/material couple.
// Get the current particle name
const G4String& pName = p->GetParticleName();
// Retrieve the iterator
G4MaterialTable::iterator it;
// Loop on all materials registered in the simulation
for(it = G4Material::GetMaterialTable()->begin(); it!=G4Material::GetMaterialTable()->end(); ++it)
{
// Get the material pointer
G4Material* mat = *it;
// Get the map
std::map<G4Material*, G4double> componentMap = mat->GetMatComponents();
// Get the number of component within the composite
unsigned int compositeSize = componentMap.size();
// Check that the material is not a composite material
if(componentMap.empty())
{
// Get the material name
const G4String& matName = mat->GetName();
// Insert the model in the table.
InsertModelInTable(matName, pName);
}
// if the material is a composite material then we need to loop on all its components to register them
else
{
// Retrieve the component map begin iterator
std::map<G4Material*, G4double>::const_iterator itComp = componentMap.begin();
// Loop on all the components of the material
//for(itComp = mat->GetMatComponents().begin(); itComp != eitComp; ++itComp)
for(unsigned int k=0; k<compositeSize; ++k)
{
G4Material* component = itComp->first;
// // Check that the component is not itself a composite
// if(component->GetMatComponents().size()!=0)
// {
// std::ostringstream oss;
// oss<<"Material "<<mat->GetName()<<" is a composite and its component ";
// oss<<component->GetName()<<" is also a composite material. Building composite with other composites is not implemented yet";
// oss<<G4endl;
// G4Exception("G4DNAModelManager::BuildMaterialParticleModelTable","em0006",
// FatalException, oss.str().c_str());
// return; // to make some compilers happy
// }
// Get the current component name
const G4String compName = component->GetName();
// If there is a model then insert the model corresponding to the component in the table
// contains a if statement to check we have not registered the material as a component or a normal material before.
InsertModelInTable(compName, pName);
// move forward the iterator
++itComp;
}
}
}
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4DNAModelInterface::BuildMaterialMolPerVolTable()
{
// To be sure the G4DNAMolecularMaterial is initialized
G4DNAMolecularMaterial::Instance()->Initialize();
G4MaterialTable* materialTable = G4Material::GetMaterialTable();
// Loop on all the materials inside the "materialTable"
for(size_t i=0, ie=materialTable->size(); i<ie; i++)
{
// Current material
G4Material* currentMaterial = materialTable->at(i);
// Current material name
const G4String& currentMatName = currentMaterial->GetName();
// Will the material be used in this interface instance ?
// Loop on all the materials that can be dealt with in this class
MaterialParticleModelTable::iterator it = fMaterialParticleModelTable.begin();
MaterialParticleModelTable::iterator ite = fMaterialParticleModelTable.end();
for(; it != ite; it++)
{
const G4String& materialName = it->first;
if(materialName == currentMatName)
{
const std::vector<double>* numMolPerVolForMat = G4DNAMolecularMaterial::Instance()->GetNumMolPerVolTableFor(currentMaterial);
fMaterialMolPerVol[materialName] = numMolPerVolForMat;
}
}
}
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4DNAModelInterface::InsertModelInTable(const G4String& matName, const G4String& pName)
{
// To insert the model(s) in the table Material Particule -> Model(s)
// First, we need to check if the current material has already been inserted in the table.
// This is possible because of the composite material. We could add a component M1 and then try to add the independant M1 material.
// This case must be avoided. Checking if M1 is already in the table is the way to avoid it.
//
// Chech if the current material and particle are already in the table.
// If they are: do nothing.
// If they are not: add the model(s)
//
// Check for the material
if(fMaterialParticleModelTable.find(matName) == fMaterialParticleModelTable.end())
{
// Check for the particle
if(fMaterialParticleModelTable[matName].find(pName) == fMaterialParticleModelTable[matName].end())
{
G4int modelNbForMaterial (0);
// Loop on all models registered in the simulation to check:
// 1- if they can be applied to the current material
// 2- if they can be applied to the current particle
for(unsigned int i=0, ie=fRegisteredModels.size(); i<ie; ++i)
{
// check if the model is correct for material and particle (previous 1 and 2)
if(fRegisteredModels[i]->IsParticleExistingInModelForMaterial(pName, matName))
{
// if yes then add the model in the map
fMaterialParticleModelTable[matName][pName].push_back(fRegisteredModels[i]);
// and add one to the "there is a model" material flag
++modelNbForMaterial;
}
}
// The model(s) applicable to the currently selected material should be in the map.
// We check if there are several models for the material.
if(modelNbForMaterial>1)
{
// If there are several models for a given material and particle couple it could be
// because of the energy ranges. We will check if the energy ranges are coherent.
// Get the models (vector)
std::vector<G4VDNAModel*>& models = fMaterialParticleModelTable[matName][pName];
// Declare a map to sort the limits (G4double) and a model "id" (G4int).
// The model id is created on the fly here.
// The idea is to fill a map with [limit] = counter. This map will be auto-sorted
// and we will check by iterating on it that the counter order is maintained.
// Delcare the map
std::map<G4double, G4int, std::less<G4double> > sortMap;
G4double smallDiff = 0.01 *eV;
// Loop on all the model for the current couple
// and fill a map with [lim] = modelNumber
for(unsigned int ii=0, em=models.size(); ii<em; ++ii)
{
G4double lowLim = models[ii]->GetLowELimit(matName, pName);
G4double highLim = models[ii]->GetHighELimit(matName, pName);
if(sortMap.find(lowLim) != sortMap.end() )
{
lowLim += smallDiff;
}
sortMap[lowLim] = ii;
if(sortMap.find(highLim) != sortMap.end() )
{
highLim -= smallDiff;
}
sortMap[highLim] = ii;
}
// The map has been created and ordered at this point.
// We will check the map order.
// Loop on the sortMap with iterator and check the order is correct.
std::map<G4double, G4int>::iterator it = sortMap.begin();
// First energy limit value
G4double dummyLim = it->first - smallDiff;
// Loop on all the models again.
// The goal is to check if for each limit pairs we have the same model number
// and that the upper and lower limit are consistent.
for(unsigned int ii=0, eii=models.size(); ii<eii; ++ii)
{
G4double lim1 = it->first - smallDiff;
G4int count1 = it->second;
// Iterate
++it;
G4double lim2 = it->first + smallDiff;
G4int count2 = it->second;
// Iterate
++it;
// Check model number and energy limit consistency
// std::abs(dummyLim - lim1) > 1.*eV because we cannot do (dummyLim != lim1)
// without experimenting precision loss. Therefore, the std::abs(...) > tolerance is the usual way of avoiding
// the issue.
if( (count1 != count2) || ( std::abs(dummyLim - lim1) > 1.*eV ) )
{
// Error
std::ostringstream oss;
oss<<"The material "<<matName<<" and the particle "<<pName;
oss<<" have several models registered for the "<<fName<<" interaction and their energy ranges ";
oss<<"do not match. \nEnergy ranges: \n";
for(int iii=0, eiii=models.size(); iii<eiii; ++iii)
{
oss<<models[iii]->GetName()<<"\n";
oss<<"low: "<<models[iii]->GetLowELimit(matName, pName)/eV<<" eV \n";
oss<<"high: "<<models[iii]->GetHighELimit(matName, pName)/eV<<" eV \n";
}
G4Exception("G4DNAModelManager::InsertModelInTable","em0006",
FatalException, oss.str().c_str());
return; // to make some compilers happy
}
dummyLim = lim2;
}
// If we are here then everything was ok.
}
// no model for the material case
else if(modelNbForMaterial==0)
{
// std::ostringstream oss;
// oss<<"The material "<<matName<<" and the particle "<<pName;
// oss<<" does not have any model registered for the "<<fName<<" interaction. ";
// G4Exception("G4DNAModelManager::InsertModelInTable","em0006",
// FatalException, oss.str().c_str());
// return; // to make some compilers happy
}
}
}
}
G4VDNAModel *G4DNAModelInterface::GetDNAModel(const G4String &material, const G4String &particle, G4double ekin)
{
// Output pointer
G4VDNAModel* model = 0;
// Get a reference to all the models for the couple (material and particle)
std::vector<G4VDNAModel*>& models = fMaterialParticleModelTable[material][particle];
// We must choose one of the model(s) accordingly to the particle energy and the model energy range(s)
//G4bool isOneModelSelected = false;
// Loop on all the models within the models vector and check if ekin is within the energy range.
for(int i=0, ie=models.size(); i<ie; ++i)
{
// ekin is in the energy range: we select the model and stop the loop.
if( ekin >= models[i]->GetLowELimit(material, particle)
&& ekin < models[i]->GetHighELimit(material, particle) )
{
// Select the model
model = models[i];
// Boolean flag
//isOneModelSelected = true;
// Quit the for loop
break;
}
// ekin is not in the energy range: we continue the loop.
}
// // If no model was selected then fatal error
// if(!isOneModelSelected)
// {
// G4String msg = "No model has ";
// msg += ekin/eV;
// msg += " eV in its energy range. Therefore nothing was selected.";
// G4Exception("G4DNAModelManager::GetDNAModel","em0006",
// FatalException,
// msg);
// }
// Return a pointer to the selected model
return model;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4double G4DNAModelInterface::GetNumMoleculePerVolumeUnitForMaterial(const G4Material* mat)
{
return fMaterialMolPerVol[mat->GetName()]->at(mat->GetIndex() );
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4double G4DNAModelInterface::GetNumMolPerVolUnitForComponentInComposite(const G4Material* component, const G4Material* composite)
{
return fMaterialMolPerVol[component->GetName() ]->at(composite->GetIndex() );
}
@@ -23,7 +23,7 @@
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
// $Id: G4DNAOneStepThermalizationModel.cc 102637 2017-02-10 11:08:17Z gcosmo $
// $Id: G4DNAOneStepThermalizationModel.cc 101807 2016-11-30 13:42:28Z gunter $
//
// Author: Mathieu Karamitros
//
@@ -141,7 +141,7 @@ namespace DNA{ namespace Penetration{
size_t lowBin, upBin;
if(k_eV >= 1.){
lowBin=floor(k_eV)+1;
lowBin=std::floor(k_eV)+1;
upBin=std::min(lowBin+1, size_t(10));
}
else{
@@ -183,7 +183,7 @@ namespace DNA{ namespace Penetration{
static constexpr double factor = 2.20496999539;
// 1./(3. - 8./CLHEP::pi);
double sigma1D = sqrt(pow(sigma3D, 2.)*factor);
double sigma1D = std::sqrt(std::pow(sigma3D, 2.)*factor);
// G4cout << "sigma1D = " << sigma1D/CLHEP::nanometer << G4endl;
@@ -0,0 +1,204 @@
//
// ********************************************************************
// * 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. *
// ********************************************************************
//
// Authors: S. Meylan and C. Villagrasa (IRSN, France)
// Models come from
// M. Bug et al, Rad. Phys and Chem. 130, 459-479 (2017)
//
#include "G4DNAPTBAugerModel.hh"
#include "G4PhysicalConstants.hh"
#include "G4SystemOfUnits.hh"
#include "Randomize.hh"
#include "G4Electron.hh"
#include "G4Material.hh"
using namespace std;
G4DNAPTBAugerModel::G4DNAPTBAugerModel(const G4String& modelAugerName): modelName(modelAugerName)
{
// To inform the user that the Auger model is enabled
G4cout << modelName <<" is constructed" << G4endl;
}
G4DNAPTBAugerModel::~G4DNAPTBAugerModel()
{
if( verboseLevel>0 ) G4cout << modelName <<" is deleted" << G4endl;
}
void G4DNAPTBAugerModel::Initialise()
{
verboseLevel = 0;
if( verboseLevel>0 )
{
G4cout << "PTB Auger model is initialised " << G4endl;
}
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4DNAPTBAugerModel::ComputeAugerEffect(std::vector<G4DynamicParticle*>* fvect, const G4String& materialNameIni, G4double bindingEnergy)
{
// Rename material if modified NIST material
// This is needed when material is obtained from G4MaterialCutsCouple
G4String materialName = materialNameIni;
if(materialName.find("_MODIFIED")){
materialName = materialName.substr(0,materialName.size()-9);
}
// check if there is a k-shell ionisation and find the ionised atom
G4int atomId(0);
atomId = DetermineIonisedAtom(atomId, materialName, bindingEnergy);
if(atomId!=0)
{
G4double kineticEnergy = CalculAugerEnergyFor(atomId);
if(kineticEnergy<0)
{
G4cerr<<"**************************"<<G4endl;
G4cerr<<"FatalError. Auger kineticEnergy: "<<kineticEnergy<<G4endl;
exit(EXIT_FAILURE);
}
if(atomId==1 || atomId==2 || atomId==3)
{
GenerateAugerWithRandomDirection(fvect, kineticEnergy);
}
else if(atomId==4)
{
GenerateAugerWithRandomDirection(fvect, kineticEnergy);
GenerateAugerWithRandomDirection(fvect, kineticEnergy);
}
}
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4int G4DNAPTBAugerModel::DetermineIonisedAtom(G4int atomId, const G4String& materialName, G4double bindingEnergy)
{
if(materialName=="THF" || materialName=="backbone_THF"){
if(bindingEnergy==305.07){
atomId=1; //"carbon";
}
else if(bindingEnergy==557.94){
atomId=2; //"oxygen";
}
}
else if(materialName=="PY" || materialName=="PU"
|| materialName=="cytosine_PY" || materialName=="thymine_PY"
|| materialName=="adenine_PU" || materialName=="guanine_PU"
)
{
if(bindingEnergy==307.52){
atomId=1; //"carbon";
}
else if(bindingEnergy==423.44){
atomId=4; //"nitrogen";
}
}
else if(materialName=="TMP"|| materialName=="backbone_TMP"){
if(bindingEnergy==209.59 || bindingEnergy==152.4)
atomId=3; //"carbonTMP";
}
return atomId;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4double G4DNAPTBAugerModel::CalculAugerEnergyFor(G4int atomId)
{
G4double kineticEnergy;
if(atomId==2) // oxygen
{
kineticEnergy = 495*eV;
}
else
{
G4double f1, f2, f3, g1, g2, Y;
Y = G4UniformRand();
if(atomId == 1){ // carbon
f1 = -7.331e-2;
f2 = -3.306e-5;
f3 = 2.433e0;
g1 = 4.838e-1;
g2 = 3.886e0;
}
else if(atomId == 4){ // nitrogen
f1 = -7.518e-2;
f2 = 1.178e-4;
f3 = 2.600e0;
g1 = 4.639e-1;
g2 = 3.770e0;
}
else// if(atomId == 3) // carbon_TMP
{
f1 = -5.700e-2;
f2 = 1.200e-4;
f3 = 2.425e0;
g1 = 5.200e-1;
g2 = 2.560e0;
}
kineticEnergy = pow(10, f1*pow( abs( log10(Y) ) , g1) + f2*pow( abs( log10(Y) ) , g2) + f3 )*eV;
}
return kineticEnergy;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4DNAPTBAugerModel::SetCutForAugerElectrons(G4double cut)
{
minElectronEnergy = cut;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4DNAPTBAugerModel::GenerateAugerWithRandomDirection(std::vector<G4DynamicParticle*>* fvect, G4double kineticEnergy)
{
// Isotropic angular distribution for the outcoming e-
G4double newcosTh = 1.-2.*G4UniformRand();
G4double newsinTh = std::sqrt(1.-newcosTh*newcosTh);
G4double newPhi = twopi*G4UniformRand();
G4double xDir = newsinTh*std::sin(newPhi);
G4double yDir = newsinTh*std::cos(newPhi);
G4double zDir = newcosTh;
G4ThreeVector ElectronDirection(xDir,yDir,zDir);
// generation of new particle
G4DynamicParticle* dp = new G4DynamicParticle (G4Electron::Electron(), ElectronDirection, kineticEnergy) ;
fvect->push_back(dp);
}
@@ -0,0 +1,546 @@
//
// ********************************************************************
// * 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. *
// ********************************************************************
//
// Authors: S. Meylan and C. Villagrasa (IRSN, France)
// Models come from
// M. Bug et al, Rad. Phys and Chem. 130, 459-479 (2017)
//
#include "G4DNAPTBElasticModel.hh"
#include "G4DNAChampionElasticModel.hh"
#include "G4PhysicalConstants.hh"
#include "G4SystemOfUnits.hh"
#include "G4DNAMolecularMaterial.hh"
#include "G4Proton.hh"
G4DNAPTBElasticModel::G4DNAPTBElasticModel(const G4String& applyToMaterial, const G4ParticleDefinition*,
const G4String& nam)
: G4VDNAModel(nam, applyToMaterial)
{
fKillBelowEnergy = 10*eV; // will be override by the limits defined for each material
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 << "PTB Elastic model is constructed " << G4endl;
}
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4DNAPTBElasticModel::~G4DNAPTBElasticModel()
{
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4DNAPTBElasticModel::Initialise(const G4ParticleDefinition* particle,
const G4DataVector& /*cuts*/, G4ParticleChangeForGamma*)
{
if (verboseLevel > 3)
G4cout << "Calling G4DNAPTBElasticModel::Initialise()" << G4endl;
G4double scaleFactor = 1e-16*cm*cm;
G4ParticleDefinition* electronDef = G4Electron::ElectronDefinition();
//*******************************************************
// Cross section data
//*******************************************************
if(particle == electronDef)
{
G4String particleName = particle->GetParticleName();
AddCrossSectionData("THF",
particleName,
"dna/sigma_elastic_e-_PTB_THF",
"dna/sigmadiff_cumulated_elastic_e-_PTB_THF",
scaleFactor);
SetLowELimit("THF", particleName, 10*eV);
SetHighELimit("THF", particleName, 1*keV);
AddCrossSectionData("PY",
particleName,
"dna/sigma_elastic_e-_PTB_PY",
"dna/sigmadiff_cumulated_elastic_e-_PTB_PY",
scaleFactor);
SetLowELimit("PY", particleName, 10*eV);
SetHighELimit("PY", particleName, 1*keV);
AddCrossSectionData("PU",
particleName,
"dna/sigma_elastic_e-_PTB_PU",
"dna/sigmadiff_cumulated_elastic_e-_PTB_PU",
scaleFactor);
SetLowELimit("PU", particleName, 10*eV);
SetHighELimit("PU", particleName, 1*keV);
AddCrossSectionData("TMP",
particleName,
"dna/sigma_elastic_e-_PTB_TMP",
"dna/sigmadiff_cumulated_elastic_e-_PTB_TMP",
scaleFactor);
SetLowELimit("TMP", particleName, 10*eV);
SetHighELimit("TMP", particleName, 1*keV);
AddCrossSectionData("G4_WATER",
particleName,
"dna/sigma_elastic_e_champion",
"dna/sigmadiff_cumulated_elastic_e_champion",
scaleFactor);
SetLowELimit("G4_WATER", particleName, 10*eV);
SetHighELimit("G4_WATER", particleName, 1*keV);
// DNA materials
//
AddCrossSectionData("backbone_THF",
particleName,
"dna/sigma_elastic_e-_PTB_THF",
"dna/sigmadiff_cumulated_elastic_e-_PTB_THF",
scaleFactor*33./30);
SetLowELimit("backbone_THF", particleName, 10*eV);
SetHighELimit("backbone_THF", particleName, 1*keV);
AddCrossSectionData("cytosine_PY",
particleName,
"dna/sigma_elastic_e-_PTB_PY",
"dna/sigmadiff_cumulated_elastic_e-_PTB_PY",
scaleFactor*42./30);
SetLowELimit("cytosine_PY", particleName, 10*eV);
SetHighELimit("cytosine_PY", particleName, 1*keV);
AddCrossSectionData("thymine_PY",
particleName,
"dna/sigma_elastic_e-_PTB_PY",
"dna/sigmadiff_cumulated_elastic_e-_PTB_PY",
scaleFactor*48./30);
SetLowELimit("thymine_PY", particleName, 10*eV);
SetHighELimit("thymine_PY", particleName, 1*keV);
AddCrossSectionData("adenine_PU",
particleName,
"dna/sigma_elastic_e-_PTB_PU",
"dna/sigmadiff_cumulated_elastic_e-_PTB_PU",
scaleFactor*50./44);
SetLowELimit("adenine_PU", particleName, 10*eV);
SetHighELimit("adenine_PU", particleName, 1*keV);
AddCrossSectionData("guanine_PU",
particleName,
"dna/sigma_elastic_e-_PTB_PU",
"dna/sigmadiff_cumulated_elastic_e-_PTB_PU",
scaleFactor*56./44);
SetLowELimit("guanine_PU", particleName, 10*eV);
SetHighELimit("guanine_PU", particleName, 1*keV);
AddCrossSectionData("backbone_TMP",
particleName,
"dna/sigma_elastic_e-_PTB_TMP",
"dna/sigmadiff_cumulated_elastic_e-_PTB_TMP",
scaleFactor*33./50);
SetLowELimit("backbone_TMP", particleName, 10*eV);
SetHighELimit("backbone_TMP", particleName, 1*keV);
}
//*******************************************************
// Load the data
//*******************************************************
LoadCrossSectionData(particle->GetParticleName() );
//*******************************************************
// Verbose output
//*******************************************************
if (verboseLevel > 2)
G4cout << "Loaded cross section files for PTB Elastic model" << G4endl;
if( verboseLevel>0 )
{
G4cout << "PTB Elastic model is initialized " << G4endl;
}
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4DNAPTBElasticModel::ReadDiffCSFile(const G4String& materialName,
const G4String& particleName,
const G4String& file,
const G4double)
{
// Method to read and save the information contained within the differential cross section files.
// This method is not yet standard.
// get the path of the G4LEDATA data folder
char *path = getenv("G4LEDATA");
// if it is not found then quit and print error message
if(!path)
{
G4Exception("G4DNAPTBElasticModel::ReadAllDiffCSFiles","em0006",
FatalException,"G4LEDATA environment variable not set.");
return;
}
// build the fullFileName path of the data file
std::ostringstream fullFileName;
fullFileName << path <<"/"<< file<<".dat";
// open the data file
std::ifstream diffCrossSection (fullFileName.str().c_str());
// error if file is not there
std::stringstream endPath;
if (!diffCrossSection)
{
endPath << "Missing data file: "<<file;
G4Exception("G4DNAPTBElasticModel::Initialise","em0003",
FatalException, endPath.str().c_str());
}
tValuesVec[materialName][particleName].push_back(0.);
G4String line;
// read the file line by line until we reach the end of file point
while(std::getline(diffCrossSection, line))
{
// check if the line is comment or empty
//
std::istringstream testIss(line);
G4String test;
testIss >> test;
// check first caracter to determine if following information is data or comments
if(test=="#")
{
// skip the line by beginning a new while loop.
continue;
}
// check if line is empty
else if(line.empty())
{
// skip the line by beginning a new while loop.
continue;
}
//
// end of the check
// transform the line into a iss
std::istringstream iss(line);
// Variables to be filled by the input file
double tDummy;
double eDummy;
// fill the variables with the content of the line
iss>>tDummy>>eDummy;
// SI : mandatory Vecm initialization
// Fill two vectors contained in maps of types:
// [materialName][particleName]=vector
// [materialName][particleName][T]=vector
// to list all the incident energies (tValues) and all the output energies (eValues) within the file
//
// Check if we already have the current T value in the vector.
// If not then add it
if (tDummy != tValuesVec[materialName][particleName].back())
{
// Add the current T value
tValuesVec[materialName][particleName].push_back(tDummy);
// Make it correspond to a default zero E value
eValuesVect[materialName][particleName][tDummy].push_back(0.);
}
// Put the differential cross section value of the input file within the diffCrossSectionData map
iss>>diffCrossSectionData[materialName][particleName][tDummy][eDummy];
// If the current E value (eDummy) is different from the one already registered in the eVector then add it to the vector
if (eDummy != eValuesVect[materialName][particleName][tDummy].back()) eValuesVect[materialName][particleName][tDummy].push_back(eDummy);
}
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4double G4DNAPTBElasticModel::CrossSectionPerVolume(const G4Material* /*material*/,
const G4String& materialName,
const G4ParticleDefinition* p,
G4double ekin,
G4double /*emin*/,
G4double /*emax*/)
{
if (verboseLevel > 3)
G4cout << "Calling CrossSectionPerVolume() of G4DNAPTBElasticModel" << G4endl;
// Get the name of the current particle
const G4String& particleName = p->GetParticleName();
// set killBelowEnergy value for current material
fKillBelowEnergy = GetLowELimit(materialName, particleName);
// initialise the return value (cross section) to zero
G4double sigma(0);
// check if we are below the high energy limit
if (ekin < GetHighELimit(materialName, particleName) )
{
// This is used to kill the particle if its kinetic energy is below fKillBelowEnergy.
// If the energy is lower then we return a maximum cross section and thus the SampleSecondaries method will be called for sure.
// SampleSecondaries will remove the particle from the simulation.
//
//SI : XS must not be zero otherwise sampling of secondaries method ignored
if (ekin < fKillBelowEnergy) return DBL_MAX;
// Get the tables with the cross section data
TableMapData* tableData = GetTableData();
// Retrieve the cross section value
sigma = (*tableData)[materialName][particleName]->FindValue(ekin);
}
if (verboseLevel > 2)
{
G4cout << "__________________________________" << G4endl;
G4cout << "°°° G4DNAPTBElasticModel - XS INFO START" << G4endl;
G4cout << "°°° Kinetic energy(eV)=" << ekin/eV << " particle : " << particleName << G4endl;
G4cout << "°°° Cross section per molecule (cm^2)=" << sigma/cm/cm << G4endl;
G4cout << "°°° G4DNAPTBElasticModel - XS INFO END" << G4endl;
}
// Return the cross section
return sigma;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4DNAPTBElasticModel::SampleSecondaries(std::vector<G4DynamicParticle*>* /*fvect*/,
const G4MaterialCutsCouple* /*couple*/,
const G4String& materialName,
const G4DynamicParticle* aDynamicElectron,
G4ParticleChangeForGamma* particleChangeForGamma,
G4double /*tmin*/,
G4double /*tmax*/)
{
if (verboseLevel > 3)
G4cout << "Calling SampleSecondaries() of G4DNAPTBElasticModel" << G4endl;
G4double electronEnergy0 = aDynamicElectron->GetKineticEnergy();
const G4String& particleName = aDynamicElectron->GetParticleDefinition()->GetParticleName();
// set killBelowEnergy value for material
fKillBelowEnergy = GetLowELimit(materialName, particleName);
// If the particle (electron here) energy is below the kill limit then we remove it from the simulation
if (electronEnergy0 < fKillBelowEnergy)
{
particleChangeForGamma->SetProposedKineticEnergy(0.);
particleChangeForGamma->ProposeTrackStatus(fStopAndKill);
particleChangeForGamma->ProposeLocalEnergyDeposit(electronEnergy0);
}
// If we are above the kill limite and below the high limit then we proceed
else if (electronEnergy0>= fKillBelowEnergy && electronEnergy0 < GetHighELimit(materialName, particleName) )
{
// Random sampling of the cosTheta
G4double cosTheta = RandomizeCosTheta(electronEnergy0, materialName);
// Random sampling of phi
G4double phi = 2. * pi * G4UniformRand();
G4ThreeVector zVers = aDynamicElectron->GetMomentumDirection();
G4ThreeVector xVers = zVers.orthogonal();
G4ThreeVector yVers = zVers.cross(xVers);
G4double xDir = std::sqrt(1. - cosTheta*cosTheta);
G4double yDir = xDir;
xDir *= std::cos(phi);
yDir *= std::sin(phi);
// Particle direction after ModelInterface
G4ThreeVector zPrikeVers((xDir*xVers + yDir*yVers + cosTheta*zVers));
// Give the new direction
particleChangeForGamma->ProposeMomentumDirection(zPrikeVers.unit()) ;
// Update the energy which does not change here
particleChangeForGamma->SetProposedKineticEnergy(electronEnergy0);
}
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4double G4DNAPTBElasticModel::Theta
(G4ParticleDefinition * particleDefinition, G4double k, G4double integrDiff, const G4String& materialName)
{
G4double theta = 0.;
G4double valueT1 = 0;
G4double valueT2 = 0;
G4double valueE21 = 0;
G4double valueE22 = 0;
G4double valueE12 = 0;
G4double valueE11 = 0;
G4double xs11 = 0;
G4double xs12 = 0;
G4double xs21 = 0;
G4double xs22 = 0;
G4String particleName = particleDefinition->GetParticleName();
if (particleDefinition == G4Electron::ElectronDefinition())
{
std::vector<double>::iterator t2 = std::upper_bound(tValuesVec[materialName][particleName].begin(),tValuesVec[materialName][particleName].end(), k);
std::vector<double>::iterator t1 = t2-1;
std::vector<double>::iterator e12 = std::upper_bound(eValuesVect[materialName][particleName][(*t1)].begin(),eValuesVect[materialName][particleName][(*t1)].end(), integrDiff);
std::vector<double>::iterator e11 = e12-1;
std::vector<double>::iterator e22 = std::upper_bound(eValuesVect[materialName][particleName][(*t2)].begin(),eValuesVect[materialName][particleName][(*t2)].end(), integrDiff);
std::vector<double>::iterator e21 = e22-1;
valueT1 =*t1;
valueT2 =*t2;
valueE21 =*e21;
valueE22 =*e22;
valueE12 =*e12;
valueE11 =*e11;
xs11 = diffCrossSectionData[materialName][particleName][valueT1][valueE11];
xs12 = diffCrossSectionData[materialName][particleName][valueT1][valueE12];
xs21 = diffCrossSectionData[materialName][particleName][valueT2][valueE21];
xs22 = diffCrossSectionData[materialName][particleName][valueT2][valueE22];
}
if (xs11==0 && xs12==0 && xs21==0 && xs22==0) return (0.);
theta = QuadInterpolator ( valueE11, valueE12,
valueE21, valueE22,
xs11, xs12,
xs21, xs22,
valueT1, valueT2,
k, integrDiff );
return theta;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4double G4DNAPTBElasticModel::LinLogInterpolate(G4double e1,
G4double e2,
G4double e,
G4double xs1,
G4double xs2)
{
G4double d1 = std::log(xs1);
G4double d2 = std::log(xs2);
G4double value = std::exp(d1 + (d2 - d1)*(e - e1)/ (e2 - e1));
return value;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4double G4DNAPTBElasticModel::LinLinInterpolate(G4double e1,
G4double e2,
G4double e,
G4double xs1,
G4double xs2)
{
G4double d1 = xs1;
G4double d2 = xs2;
G4double value = (d1 + (d2 - d1)*(e - e1)/ (e2 - e1));
return value;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4double G4DNAPTBElasticModel::LogLogInterpolate(G4double e1,
G4double e2,
G4double e,
G4double xs1,
G4double xs2)
{
G4double a = (std::log10(xs2)-std::log10(xs1)) / (std::log10(e2)-std::log10(e1));
G4double b = std::log10(xs2) - a*std::log10(e2);
G4double sigma = a*std::log10(e) + b;
G4double value = (std::pow(10.,sigma));
return value;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4double G4DNAPTBElasticModel::QuadInterpolator(G4double e11, G4double e12,
G4double e21, G4double e22,
G4double xs11, G4double xs12,
G4double xs21, G4double xs22,
G4double t1, G4double t2,
G4double t, G4double e)
{
// Log-Log
/*
G4double interpolatedvalue1 = LogLogInterpolate(e11, e12, e, xs11, xs12);
G4double interpolatedvalue2 = LogLogInterpolate(e21, e22, e, xs21, xs22);
G4double value = LogLogInterpolate(t1, t2, t, interpolatedvalue1, interpolatedvalue2);
// Lin-Log
G4double interpolatedvalue1 = LinLogInterpolate(e11, e12, e, xs11, xs12);
G4double interpolatedvalue2 = LinLogInterpolate(e21, e22, e, xs21, xs22);
G4double value = LinLogInterpolate(t1, t2, t, interpolatedvalue1, interpolatedvalue2);
*/
// Lin-Lin
G4double interpolatedvalue1 = LinLinInterpolate(e11, e12, e, xs11, xs12);
G4double interpolatedvalue2 = LinLinInterpolate(e21, e22, e, xs21, xs22);
G4double value = LinLinInterpolate(t1, t2, t, interpolatedvalue1, interpolatedvalue2);
return value;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4double G4DNAPTBElasticModel::RandomizeCosTheta(G4double k, const G4String& materialName)
{
G4double integrdiff=0;
G4double uniformRand=G4UniformRand();
integrdiff = uniformRand;
G4double theta=0.;
G4double cosTheta=0.;
theta = Theta(G4Electron::ElectronDefinition(),k/eV,integrdiff, materialName);
cosTheta= std::cos(theta*pi/180);
return cosTheta;
}
@@ -0,0 +1,287 @@
//
// ********************************************************************
// * 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. *
// ********************************************************************
//
// Authors: S. Meylan and C. Villagrasa (IRSN, France)
// Models come from
// M. Bug et al, Rad. Phys and Chem. 130, 459-479 (2017)
//
#include "G4DNAPTBExcitationModel.hh"
#include "G4SystemOfUnits.hh"
#include "G4DNAChemistryManager.hh"
#include "G4DNAMolecularMaterial.hh"
G4DNAPTBExcitationModel::G4DNAPTBExcitationModel(const G4String& applyToMaterial, const G4ParticleDefinition*,
const G4String& nam)
: G4VDNAModel(nam, applyToMaterial)
{
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
// initialisation of mean energy loss for each material
tableMeanEnergyPTB["THF"] = 8.01*eV;
tableMeanEnergyPTB["PY"] = 7.61*eV;
tableMeanEnergyPTB["PU"] = 7.61*eV;
tableMeanEnergyPTB["TMP"] = 8.01*eV;
if( verboseLevel>0 )
{
G4cout << "PTB excitation model is constructed " << G4endl;
}
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4DNAPTBExcitationModel::~G4DNAPTBExcitationModel()
{
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4DNAPTBExcitationModel::Initialise(const G4ParticleDefinition* particle,
const G4DataVector& /*cuts*/, G4ParticleChangeForGamma*)
{
if (verboseLevel > 3)
G4cout << "Calling G4DNAPTBExcitationModel::Initialise()" << G4endl;
G4double scaleFactor = 1e-16*cm*cm;
G4double scaleFactorBorn = (1.e-22 / 3.343) * m*m;
G4ParticleDefinition* electronDef = G4Electron::ElectronDefinition();
//*******************************************************
// Cross section data
//*******************************************************
if(particle == electronDef)
{
G4String particleName = particle->GetParticleName();
AddCrossSectionData("THF",
particleName,
"dna/sigma_excitation_e-_PTB_THF",
scaleFactor);
SetLowELimit("THF", particleName, 9.*eV);
SetHighELimit("THF", particleName, 1.*keV);
AddCrossSectionData("PY",
particleName,
"dna/sigma_excitation_e-_PTB_PY",
scaleFactor);
SetLowELimit("PY", particleName, 9.*eV);
SetHighELimit("PY", particleName, 1.*keV);
AddCrossSectionData("PU",
particleName,
"dna/sigma_excitation_e-_PTB_PU",
scaleFactor);
SetLowELimit("PU", particleName, 9.*eV);
SetHighELimit("PU", particleName, 1.*keV);
AddCrossSectionData("TMP",
particleName,
"dna/sigma_excitation_e-_PTB_TMP",
scaleFactor);
SetLowELimit("TMP", particleName, 9.*eV);
SetHighELimit("TMP", particleName, 1.*keV);
AddCrossSectionData("G4_WATER",
particleName,
"dna/sigma_excitation_e_born",
scaleFactorBorn);
SetLowELimit("G4_WATER", particleName, 9.*eV);
SetHighELimit("G4_WATER", particleName, 1.*keV);
// DNA materials
//
AddCrossSectionData("backbone_THF",
particleName,
"dna/sigma_excitation_e-_PTB_THF",
scaleFactor*33./30);
SetLowELimit("backbone_THF", particleName, 9.*eV);
SetHighELimit("backbone_THF", particleName, 1.*keV);
AddCrossSectionData("cytosine_PY",
particleName,
"dna/sigma_excitation_e-_PTB_PY",
scaleFactor*42./30);
SetLowELimit("cytosine_PY", particleName, 9.*eV);
SetHighELimit("cytosine_PY", particleName, 1.*keV);
AddCrossSectionData("thymine_PY",
particleName,
"dna/sigma_excitation_e-_PTB_PY",
scaleFactor*48./30);
SetLowELimit("thymine_PY", particleName, 9.*eV);
SetHighELimit("thymine_PY", particleName, 1.*keV);
AddCrossSectionData("adenine_PU",
particleName,
"dna/sigma_excitation_e-_PTB_PU",
scaleFactor*50./44);
SetLowELimit("adenine_PU", particleName, 9.*eV);
SetHighELimit("adenine_PU", particleName, 1.*keV);
AddCrossSectionData("guanine_PU",
particleName,
"dna/sigma_excitation_e-_PTB_PU",
scaleFactor*56./44);
SetLowELimit("guanine_PU", particleName, 9.*eV);
SetHighELimit("guanine_PU", particleName, 1.*keV);
AddCrossSectionData("backbone_TMP",
particleName,
"dna/sigma_excitation_e-_PTB_TMP",
scaleFactor*33./50);
SetLowELimit("backbone_TMP", particleName, 9.*eV);
SetHighELimit("backbone_TMP", particleName, 1.*keV);
}
//*******************************************************
// Load data
//*******************************************************
LoadCrossSectionData(particle->GetParticleName() );
//*******************************************************
// Verbose
//*******************************************************
if( verboseLevel>0 )
{
G4cout << "PTB excitation model is initialized " << G4endl;
}
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4double G4DNAPTBExcitationModel::CrossSectionPerVolume(const G4Material* /*material*/,
const G4String& materialName,
const G4ParticleDefinition* particleDefinition,
G4double ekin,
G4double /*emin*/,
G4double /*emax*/)
{
if (verboseLevel > 3)
G4cout << "Calling CrossSectionPerVolume() of G4DNAPTBExcitationModel" << G4endl;
// Get the name of the current particle
G4String particleName = particleDefinition->GetParticleName();
// initialise variables
G4double lowLim = 0;
G4double highLim = 0;
G4double sigma=0;
// Get the low energy limit for the current particle
lowLim = GetLowELimit(materialName, particleName);
// Get the high energy limit for the current particle
highLim = GetHighELimit(materialName, particleName);
// Check that we are in the correct energy range
if (ekin >= lowLim && ekin < highLim)
{
// Get the map with all the data tables
TableMapData* tableData = GetTableData();
// Retrieve the cross section value
sigma = (*tableData)[materialName][particleName]->FindValue(ekin);
if (verboseLevel > 2)
{
G4cout << "__________________________________" << G4endl;
G4cout << "°°° G4DNAPTBExcitationModel - XS INFO START" << G4endl;
G4cout << "°°° Kinetic energy(eV)=" << ekin/eV << " particle : " << particleName << G4endl;
G4cout << "°°° Cross section per "<< materialName <<" molecule (cm^2)=" << sigma/cm/cm << G4endl;
G4cout << "°°° G4DNAPTBExcitationModel - XS INFO END" << G4endl;
}
}
// Return the cross section value
return sigma;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4DNAPTBExcitationModel::SampleSecondaries(std::vector<G4DynamicParticle*>* /*fvect*/,
const G4MaterialCutsCouple* /*couple*/,
const G4String& materialName,
const G4DynamicParticle* aDynamicParticle,
G4ParticleChangeForGamma* particleChangeForGamma,
G4double /*tmin*/,
G4double /*tmax*/)
{
if (verboseLevel > 3)
G4cout << "Calling SampleSecondaries() of G4DNAPTBExcitationModel" << G4endl;
// Get the incident particle kinetic energy
G4double k = aDynamicParticle->GetKineticEnergy();
if(materialName!="G4_WATER")
{
// Retrieve the excitation energy for the current material
G4double excitationEnergy = tableMeanEnergyPTB[materialName];
// Calculate the new energy of the particle
G4double newEnergy = k - excitationEnergy;
// Check that the new energy is above zero before applying it the particle.
// Otherwise, do nothing.
if (newEnergy > 0)
{
particleChangeForGamma->ProposeMomentumDirection(aDynamicParticle->GetMomentumDirection());
particleChangeForGamma->SetProposedKineticEnergy(newEnergy);
particleChangeForGamma->ProposeLocalEnergyDeposit(excitationEnergy);
}
}
else
{
const G4String& particleName = aDynamicParticle->GetDefinition()->GetParticleName();
G4int level = RandomSelectShell(k,particleName, materialName);
G4double excitationEnergy = waterStructure.ExcitationEnergy(level);
G4double newEnergy = k - excitationEnergy;
if (newEnergy > 0)
{
particleChangeForGamma->ProposeMomentumDirection(aDynamicParticle->GetMomentumDirection());
particleChangeForGamma->SetProposedKineticEnergy(newEnergy);
particleChangeForGamma->ProposeLocalEnergyDeposit(excitationEnergy);
}
const G4Track * theIncomingTrack = particleChangeForGamma->GetCurrentTrack();
G4DNAChemistryManager::Instance()->CreateWaterMolecule(eExcitedMolecule,
level,
theIncomingTrack);
}
}
@@ -0,0 +1,996 @@
//
// ********************************************************************
// * 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. *
// ********************************************************************
//
// Authors: S. Meylan and C. Villagrasa (IRSN, France)
// Models come from
// M. Bug et al, Rad. Phys and Chem. 130, 459-479 (2017)
//
#include "G4DNAPTBIonisationModel.hh"
#include "G4PhysicalConstants.hh"
#include "G4SystemOfUnits.hh"
#include "G4UAtomicDeexcitation.hh"
#include "G4LossTableManager.hh"
#include "G4DNAChemistryManager.hh"
G4DNAPTBIonisationModel::G4DNAPTBIonisationModel(const G4String& applyToMaterial,
const G4ParticleDefinition*,
const G4String& nam, const G4bool isAuger)
: G4VDNAModel(nam, applyToMaterial)
{
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 << "PTB ionisation model is constructed " << G4endl;
}
if(isAuger)
{
// create the PTB Auger model
fDNAPTBAugerModel = new G4DNAPTBAugerModel("e-_G4DNAPTBAugerModel");
}
else
{
// no PTB Auger model
fDNAPTBAugerModel = 0;
}
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4DNAPTBIonisationModel::~G4DNAPTBIonisationModel()
{
// To delete the DNAPTBAugerModel created at initialisation of the ionisation class
if(fDNAPTBAugerModel) delete fDNAPTBAugerModel;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4DNAPTBIonisationModel::Initialise(const G4ParticleDefinition* particle,
const G4DataVector& /*cuts*/, G4ParticleChangeForGamma*)
{
if (verboseLevel > 3)
G4cout << "Calling G4DNAPTBIonisationModel::Initialise()" << G4endl;
G4double scaleFactor = 1e-16 * cm*cm;
G4double scaleFactorBorn = (1.e-22 / 3.343) * m*m;
G4ParticleDefinition* electronDef = G4Electron::ElectronDefinition();
G4ParticleDefinition* protonDef= G4Proton::ProtonDefinition();
//*******************************************************
// Cross section data
//*******************************************************
if(particle == electronDef)
{
G4String particleName = particle->GetParticleName();
// Raw materials
//
AddCrossSectionData("THF",
particleName,
"dna/sigma_ionisation_e-_PTB_THF",
"dna/sigmadiff_cumulated_ionisation_e-_PTB_THF",
scaleFactor);
SetLowELimit("THF", particleName, 12.*eV);
SetHighELimit("THF", particleName, 1.*keV);
AddCrossSectionData("PY",
particleName,
"dna/sigma_ionisation_e-_PTB_PY",
"dna/sigmadiff_cumulated_ionisation_e-_PTB_PY",
scaleFactor);
SetLowELimit("PY", particleName, 12.*eV);
SetHighELimit("PY", particleName, 1.*keV);
AddCrossSectionData("PU",
particleName,
"dna/sigma_ionisation_e-_PTB_PU",
"dna/sigmadiff_cumulated_ionisation_e-_PTB_PU",
scaleFactor);
SetLowELimit("PU", particleName, 12.*eV);
SetHighELimit("PU", particleName, 1.*keV);
AddCrossSectionData("TMP",
particleName,
"dna/sigma_ionisation_e-_PTB_TMP",
"dna/sigmadiff_cumulated_ionisation_e-_PTB_TMP",
scaleFactor);
SetLowELimit("TMP", particleName, 12.*eV);
SetHighELimit("TMP", particleName, 1.*keV);
AddCrossSectionData("G4_WATER",
particleName,
"dna/sigma_ionisation_e_born",
"dna/sigmadiff_ionisation_e_born",
scaleFactorBorn);
SetLowELimit("G4_WATER", particleName, 12.*eV);
SetHighELimit("G4_WATER", particleName, 1.*keV);
// DNA materials
//
AddCrossSectionData("backbone_THF",
particleName,
"dna/sigma_ionisation_e-_PTB_THF",
"dna/sigmadiff_cumulated_ionisation_e-_PTB_THF",
scaleFactor*33./30);
SetLowELimit("backbone_THF", particleName, 12.*eV);
SetHighELimit("backbone_THF", particleName, 1.*keV);
AddCrossSectionData("cytosine_PY",
particleName,
"dna/sigma_ionisation_e-_PTB_PY",
"dna/sigmadiff_cumulated_ionisation_e-_PTB_PY",
scaleFactor*42./30);
SetLowELimit("cytosine_PY", particleName, 12.*eV);
SetHighELimit("cytosine_PY", particleName, 1.*keV);
AddCrossSectionData("thymine_PY",
particleName,
"dna/sigma_ionisation_e-_PTB_PY",
"dna/sigmadiff_cumulated_ionisation_e-_PTB_PY",
scaleFactor*48./30);
SetLowELimit("thymine_PY", particleName, 12.*eV);
SetHighELimit("thymine_PY", particleName, 1.*keV);
AddCrossSectionData("adenine_PU",
particleName,
"dna/sigma_ionisation_e-_PTB_PU",
"dna/sigmadiff_cumulated_ionisation_e-_PTB_PU",
scaleFactor*50./44);
SetLowELimit("adenine_PU", particleName, 12.*eV);
SetHighELimit("adenine_PU", particleName, 1.*keV);
AddCrossSectionData("guanine_PU",
particleName,
"dna/sigma_ionisation_e-_PTB_PU",
"dna/sigmadiff_cumulated_ionisation_e-_PTB_PU",
scaleFactor*56./44);
SetLowELimit("guanine_PU", particleName, 12.*eV);
SetHighELimit("guanine_PU", particleName, 1.*keV);
AddCrossSectionData("backbone_TMP",
particleName,
"dna/sigma_ionisation_e-_PTB_TMP",
"dna/sigmadiff_cumulated_ionisation_e-_PTB_TMP",
scaleFactor*33./50);
SetLowELimit("backbone_TMP", particleName, 12.*eV);
SetHighELimit("backbone_TMP", particleName, 1.*keV);
}
else if (particle == protonDef)
{
G4String particleName = particle->GetParticleName();
// Raw materials
//
AddCrossSectionData("THF",
particleName,
"dna/sigma_ionisation_p_HKS_THF",
"dna/sigmadiff_cumulated_ionisation_p_PTB_THF",
scaleFactor);
SetLowELimit("THF", particleName, 70.*keV);
SetHighELimit("THF", particleName, 10.*MeV);
AddCrossSectionData("PY",
particleName,
"dna/sigma_ionisation_p_HKS_PY",
"dna/sigmadiff_cumulated_ionisation_p_PTB_PY",
scaleFactor);
SetLowELimit("PY", particleName, 70.*keV);
SetHighELimit("PY", particleName, 10.*MeV);
/*
AddCrossSectionData("PU",
particleName,
"dna/sigma_ionisation_e-_PTB_PU",
"dna/sigmadiff_cumulated_ionisation_e-_PTB_PU",
scaleFactor);
SetLowELimit("PU", particleName2, 70.*keV);
SetHighELimit("PU", particleName2, 10.*keV);
*/
AddCrossSectionData("TMP",
particleName,
"dna/sigma_ionisation_p_HKS_TMP",
"dna/sigmadiff_cumulated_ionisation_p_PTB_TMP",
scaleFactor);
SetLowELimit("TMP", particleName, 70.*keV);
SetHighELimit("TMP", particleName, 10.*MeV);
}
// *******************************************************
// deal with composite materials
// *******************************************************
LoadCrossSectionData(particle->GetParticleName() );
// *******************************************************
// Verbose
// *******************************************************
// initialise DNAPTBAugerModel
if(fDNAPTBAugerModel) fDNAPTBAugerModel->Initialise();
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4double G4DNAPTBIonisationModel::CrossSectionPerVolume(const G4Material* /*material*/,
const G4String& materialName,
const G4ParticleDefinition* p,
G4double ekin,
G4double /*emin*/,
G4double /*emax*/)
{
if(verboseLevel > 3)
G4cout << "Calling CrossSectionPerVolume() of G4DNAPTBIonisationModel" << G4endl;
// initialise the cross section value (output value)
G4double sigma(0);
// Get the current particle name
const G4String& particleName = p->GetParticleName();
// Set the low and high energy limits
G4double lowLim = GetLowELimit(materialName, particleName);
G4double highLim = GetHighELimit(materialName, particleName);
// Check that we are in the correct energy range
if (ekin >= lowLim && ekin < highLim)
{
// Get the map with all the model data tables
TableMapData* tableData = GetTableData();
// Retrieve the cross section value for the current material, particle and energy values
sigma = (*tableData)[materialName][particleName]->FindValue(ekin);
if (verboseLevel > 2)
{
G4cout << "__________________________________" << G4endl;
G4cout << "°°° G4DNAPTBIonisationModel - XS INFO START" << G4endl;
G4cout << "°°° Kinetic energy(eV)=" << ekin/eV << " particle : " << particleName << G4endl;
G4cout << "°°° Cross section per "<< materialName <<" molecule (cm^2)=" << sigma/cm/cm << G4endl;
G4cout << "°°° G4DNAPTBIonisationModel - XS INFO END" << G4endl;
}
}
// Return the cross section value
return sigma;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4DNAPTBIonisationModel::SampleSecondaries(std::vector<G4DynamicParticle*>* fvect,
const G4MaterialCutsCouple* /*couple*/,
const G4String& materialName,
const G4DynamicParticle* aDynamicParticle,
G4ParticleChangeForGamma* particleChangeForGamma,
G4double /*tmin*/,
G4double /*tmax*/)
{
if (verboseLevel > 3)
G4cout << "Calling SampleSecondaries() of G4DNAPTBIonisationModel" << G4endl;
// Get the current particle energy
G4double k = aDynamicParticle->GetKineticEnergy();
// Get the current particle name
const G4String& particleName = aDynamicParticle->GetDefinition()->GetParticleName();
// Get the energy limits
G4double lowLim = GetLowELimit(materialName, particleName);
G4double highLim = GetHighELimit(materialName, particleName);
// Check if we are in the correct energy range
if (k >= lowLim && k < highLim)
{
G4ParticleMomentum primaryDirection = aDynamicParticle->GetMomentumDirection();
G4double particleMass = aDynamicParticle->GetDefinition()->GetPDGMass();
G4double totalEnergy = k + particleMass;
G4double pSquare = k * (totalEnergy + particleMass);
G4double totalMomentum = std::sqrt(pSquare);
// Get the ionisation shell from a random sampling
G4int ionizationShell = RandomSelectShell(k, particleName, materialName);
// Get the binding energy from the ptbStructure class
G4double bindingEnergy = ptbStructure.IonisationEnergy(ionizationShell, materialName);
// Initialize the secondary kinetic energy to a negative value.
G4double secondaryKinetic (-1000*eV);
if(materialName!="G4_WATER")
{
// Get the energy of the secondary particle
secondaryKinetic = RandomizeEjectedElectronEnergyFromCumulated(aDynamicParticle->GetDefinition(),k/eV,ionizationShell, materialName);
}
else
{
secondaryKinetic = RandomizeEjectedElectronEnergy(aDynamicParticle->GetDefinition(),k,ionizationShell, materialName);
}
if(secondaryKinetic<=0)
{
G4cout<<"Fatal error *************************************** "<<secondaryKinetic/eV<<G4endl;
G4cout<<"secondaryKinetic: "<<secondaryKinetic/eV<<G4endl;
G4cout<<"k: "<<k/eV<<G4endl;
G4cout<<"shell: "<<ionizationShell<<G4endl;
G4cout<<"material:"<<materialName<<G4endl;
exit(EXIT_FAILURE);
}
G4double cosTheta = 0.;
G4double phi = 0.;
RandomizeEjectedElectronDirection(aDynamicParticle->GetDefinition(), k, secondaryKinetic, cosTheta, phi);
G4double sinTheta = std::sqrt(1.-cosTheta*cosTheta);
G4double dirX = sinTheta*std::cos(phi);
G4double dirY = sinTheta*std::sin(phi);
G4double dirZ = cosTheta;
G4ThreeVector deltaDirection(dirX,dirY,dirZ);
deltaDirection.rotateUz(primaryDirection);
// The model is written only for electron and thus we want the change the direction of the incident electron
// after each ionization. However, if other particle are going to be introduced within this model the following should be added:
//
// Check if the particle is an electron
if(aDynamicParticle->GetDefinition() == G4Electron::ElectronDefinition() )
{
// If yes do the following code until next commented "else" statement
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(finalPx,finalPy,finalPz);
if(direction.unit().getX()>1||direction.unit().getY()>1||direction.unit().getZ()>1)
{
G4cout<<"Fatal error ****************************"<<G4endl;
G4cout<<"direction problem "<<direction.unit()<<G4endl;
exit(EXIT_FAILURE);
}
// Give the new direction to the particle
particleChangeForGamma->ProposeMomentumDirection(direction.unit()) ;
}
// If the particle is not an electron
else particleChangeForGamma->ProposeMomentumDirection(primaryDirection) ;
// note that secondaryKinetic is the energy of the delta ray, not of all secondaries.
G4double scatteredEnergy = k-bindingEnergy-secondaryKinetic;
if(scatteredEnergy<=0)
{
G4cout<<"Fatal error ****************************"<<G4endl;
G4cout<<"k: "<<k/eV<<G4endl;
G4cout<<"secondaryKinetic: "<<secondaryKinetic/eV<<G4endl;
G4cout<<"shell: "<<ionizationShell<<G4endl;
G4cout<<"bindingEnergy: "<<bindingEnergy/eV<<G4endl;
G4cout<<"scatteredEnergy: "<<scatteredEnergy/eV<<G4endl;
G4cout<<"material: "<<materialName<<G4endl;
exit(EXIT_FAILURE);
}
// Set the new energy of the particle
particleChangeForGamma->SetProposedKineticEnergy(scatteredEnergy);
// Set the energy deposited by the ionization
particleChangeForGamma->ProposeLocalEnergyDeposit(k-scatteredEnergy-secondaryKinetic);
// Create the new particle with its characteristics
G4DynamicParticle* dp = new G4DynamicParticle (G4Electron::Electron(),deltaDirection,secondaryKinetic) ;
fvect->push_back(dp);
// Check if the auger model is activated (ie instanciated)
if(fDNAPTBAugerModel)
{
// run the PTB Auger model
if(materialName!="G4_WATER") fDNAPTBAugerModel->ComputeAugerEffect(fvect, materialName, bindingEnergy);
}
}
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4DNAPTBIonisationModel::ReadDiffCSFile(const G4String& materialName,
const G4String& particleName,
const G4String& file,
const G4double scaleFactor)
{
// To read and save the informations contained within the differential cross section files
// get the path of the G4LEDATA data folder
char *path = getenv("G4LEDATA");
// if it is not found then quit and print error message
if(!path)
{
G4Exception("G4DNAPTBIonisationModel::ReadAllDiffCSFiles","em0006",
FatalException,"G4LEDATA environment variable not set.");
return;
}
// build the fullFileName path of the data file
std::ostringstream fullFileName;
fullFileName << path <<"/"<< file<<".dat";
// open the data file
std::ifstream diffCrossSection (fullFileName.str().c_str());
// error if file is not there
std::stringstream endPath;
if (!diffCrossSection)
{
endPath << "Missing data file: "<<file;
G4Exception("G4DNAPTBIonisationModel::Initialise","em0003",
FatalException, endPath.str().c_str());
}
// load data from the file
fTMapWithVec[materialName][particleName].push_back(0.);
G4String line;
// read the file until we reach the end of file point
// fill fTMapWithVec, diffCrossSectionData, fEnergyTransferData, fProbaShellMap and fEMapWithVector
while(std::getline(diffCrossSection, line))
{
// check if the line is comment or empty
//
std::istringstream testIss(line);
G4String test;
testIss >> test;
// check first caracter to determine if following information is data or comments
if(test=="#")
{
// skip the line by beginning a new while loop.
continue;
}
// check if line is empty
else if(line.empty())
{
// skip the line by beginning a new while loop.
continue;
}
//
// end of the check
// transform the line into a iss
std::istringstream iss(line);
// Initialise the variables to be filled
double T;
double E;
// Filled T and E with the first two numbers of each file line
iss>>T>>E;
// Fill the fTMapWithVec container with all the different T values contained within the file.
// Duplicate must be avoided and this is the purpose of the if statement
if (T != fTMapWithVec[materialName][particleName].back()) fTMapWithVec[materialName][particleName].push_back(T);
// iterate on each shell of the corresponding material
for (int shell=0, eshell=ptbStructure.NumberOfLevels(materialName); shell<eshell; ++shell)
{
// map[material][particle][shell][T][E]=diffCrossSectionValue
// Fill the map with the informations of the input file
iss>>diffCrossSectionData[materialName][particleName][shell][T][E];
if(materialName!="G4_WATER")
{
// map[material][particle][shell][T][CS]=E
// Fill the map
fEnergySecondaryData[materialName][particleName][shell][T][diffCrossSectionData[materialName][particleName][shell][T][E] ]=E;
// map[material][particle][shell][T]=CS_vector
// Fill the vector within the map
fProbaShellMap[materialName][particleName][shell][T].push_back(diffCrossSectionData[materialName][particleName][shell][T][E]);
}
else
{
diffCrossSectionData[materialName][particleName][shell][T][E]*=scaleFactor;
fEMapWithVector[materialName][particleName][T].push_back(E);
}
}
}
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4double G4DNAPTBIonisationModel::RandomizeEjectedElectronEnergy(G4ParticleDefinition* particleDefinition,
G4double k, G4int shell, const G4String& materialName)
{
if (particleDefinition == G4Electron::ElectronDefinition())
{
//G4double Tcut=25.0E-6;
G4double maximumEnergyTransfer=0.;
if ((k+ptbStructure.IonisationEnergy(shell, materialName))/2. > k) maximumEnergyTransfer=k;
else maximumEnergyTransfer = (k+ptbStructure.IonisationEnergy(shell,materialName))/2.;
// SI : original method
/*
G4double crossSectionMaximum = 0.;
for(G4double value=waterStructure.IonisationEnergy(shell); value<=maximumEnergyTransfer; value+=0.1*eV)
{
G4double differentialCrossSection = DifferentialCrossSection(particleDefinition, k/eV, value/eV, shell);
if(differentialCrossSection >= crossSectionMaximum) crossSectionMaximum = differentialCrossSection;
}
*/
// SI : alternative method
//if (k > Tcut)
//{
G4double crossSectionMaximum = 0.;
G4double minEnergy = ptbStructure.IonisationEnergy(shell, materialName);
G4double maxEnergy = maximumEnergyTransfer;
G4int nEnergySteps = 50;
G4double value(minEnergy);
G4double stpEnergy(std::pow(maxEnergy/value, 1./static_cast<G4double>(nEnergySteps-1)));
G4int step(nEnergySteps);
while (step>0)
{
step--;
G4double differentialCrossSection = DifferentialCrossSection(particleDefinition, k/eV, value/eV, shell, materialName);
if(differentialCrossSection >= crossSectionMaximum) crossSectionMaximum = differentialCrossSection;
value *= stpEnergy;
}
//
G4double secondaryElectronKineticEnergy=0.;
do
{
secondaryElectronKineticEnergy = G4UniformRand() * (maximumEnergyTransfer-ptbStructure.IonisationEnergy(shell, materialName));
} while(G4UniformRand()*crossSectionMaximum >
DifferentialCrossSection(particleDefinition, k/eV,(secondaryElectronKineticEnergy+ptbStructure.IonisationEnergy(shell, materialName))/eV,shell, materialName));
return secondaryElectronKineticEnergy;
// }
// else if (k < Tcut)
// {
// G4double bindingEnergy = ptbStructure.IonisationEnergy(shell, materialName);
// G4double maxEnergy = ((k-bindingEnergy)/2.);
// G4double secondaryElectronKineticEnergy = G4UniformRand()*maxEnergy;
// return secondaryElectronKineticEnergy;
// }
}
else if (particleDefinition == G4Proton::ProtonDefinition())
{
G4double maximumKineticEnergyTransfer = 4.* (electron_mass_c2 / proton_mass_c2) * k;
G4double crossSectionMaximum = 0.;
for (G4double value = ptbStructure.IonisationEnergy(shell, materialName);
value<=4.*ptbStructure.IonisationEnergy(shell, materialName) ;
value+=0.1*eV)
{
G4double differentialCrossSection = DifferentialCrossSection(particleDefinition, k/eV, value/eV, shell, materialName);
if (differentialCrossSection >= crossSectionMaximum) crossSectionMaximum = differentialCrossSection;
}
G4double secondaryElectronKineticEnergy = 0.;
do
{
secondaryElectronKineticEnergy = G4UniformRand() * maximumKineticEnergyTransfer;
} while(G4UniformRand()*crossSectionMaximum >=
DifferentialCrossSection(particleDefinition, k/eV,(secondaryElectronKineticEnergy+ptbStructure.IonisationEnergy(shell, materialName))/eV,shell, materialName));
return secondaryElectronKineticEnergy;
}
return 0;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
void G4DNAPTBIonisationModel::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....
double G4DNAPTBIonisationModel::DifferentialCrossSection(G4ParticleDefinition * particleDefinition,
G4double k,
G4double energyTransfer,
G4int ionizationLevelIndex,
const G4String& materialName)
{
G4double sigma = 0.;
const G4String& particleName = particleDefinition->GetParticleName();
G4double shellEnergy (ptbStructure.IonisationEnergy(ionizationLevelIndex, materialName));
G4double kSE (energyTransfer-shellEnergy);
if (energyTransfer >= shellEnergy)
{
G4double valueT1 = 0;
G4double valueT2 = 0;
G4double valueE21 = 0;
G4double valueE22 = 0;
G4double valueE12 = 0;
G4double valueE11 = 0;
G4double xs11 = 0;
G4double xs12 = 0;
G4double xs21 = 0;
G4double xs22 = 0;
if (particleDefinition == G4Electron::ElectronDefinition())
{
// k should be in eV and energy transfer eV also
std::vector<double>::iterator t2 = std::upper_bound(fTMapWithVec[materialName][particleName].begin(),fTMapWithVec[materialName][particleName].end(), k);
std::vector<double>::iterator t1 = t2-1;
// SI : the following condition avoids situations where energyTransfer >last vector element
if (kSE <= fEMapWithVector[materialName][particleName][(*t1)].back() && kSE <= fEMapWithVector[materialName][particleName][(*t2)].back() )
{
std::vector<double>::iterator e12 = std::upper_bound(fEMapWithVector[materialName][particleName][(*t1)].begin(),fEMapWithVector[materialName][particleName][(*t1)].end(), kSE);
std::vector<double>::iterator e11 = e12-1;
std::vector<double>::iterator e22 = std::upper_bound(fEMapWithVector[materialName][particleName][(*t2)].begin(),fEMapWithVector[materialName][particleName][(*t2)].end(), kSE);
std::vector<double>::iterator e21 = e22-1;
valueT1 =*t1;
valueT2 =*t2;
valueE21 =*e21;
valueE22 =*e22;
valueE12 =*e12;
valueE11 =*e11;
xs11 = diffCrossSectionData[materialName][particleName][ionizationLevelIndex][valueT1][valueE11];
xs12 = diffCrossSectionData[materialName][particleName][ionizationLevelIndex][valueT1][valueE12];
xs21 = diffCrossSectionData[materialName][particleName][ionizationLevelIndex][valueT2][valueE21];
xs22 = diffCrossSectionData[materialName][particleName][ionizationLevelIndex][valueT2][valueE22];
}
}
if (particleDefinition == G4Proton::ProtonDefinition())
{
// k should be in eV and energy transfer eV also
std::vector<double>::iterator t2 = std::upper_bound(fTMapWithVec[materialName][particleName].begin(),fTMapWithVec[materialName][particleName].end(), k);
std::vector<double>::iterator t1 = t2-1;
std::vector<double>::iterator e12 = std::upper_bound(fEMapWithVector[materialName][particleName][(*t1)].begin(),fEMapWithVector[materialName][particleName][(*t1)].end(), kSE);
std::vector<double>::iterator e11 = e12-1;
std::vector<double>::iterator e22 = std::upper_bound(fEMapWithVector[materialName][particleName][(*t2)].begin(),fEMapWithVector[materialName][particleName][(*t2)].end(), kSE);
std::vector<double>::iterator e21 = e22-1;
valueT1 =*t1;
valueT2 =*t2;
valueE21 =*e21;
valueE22 =*e22;
valueE12 =*e12;
valueE11 =*e11;
xs11 = diffCrossSectionData[materialName][particleName][ionizationLevelIndex][valueT1][valueE11];
xs12 = diffCrossSectionData[materialName][particleName][ionizationLevelIndex][valueT1][valueE12];
xs21 = diffCrossSectionData[materialName][particleName][ionizationLevelIndex][valueT2][valueE21];
xs22 = diffCrossSectionData[materialName][particleName][ionizationLevelIndex][valueT2][valueE22];
}
G4double xsProduct = xs11 * xs12 * xs21 * xs22;
if (xsProduct != 0.)
{
sigma = QuadInterpolator(valueE11, valueE12,
valueE21, valueE22,
xs11, xs12,
xs21, xs22,
valueT1, valueT2,
k, kSE);
}
}
return sigma;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4double G4DNAPTBIonisationModel::RandomizeEjectedElectronEnergyFromCumulated(G4ParticleDefinition* particleDefinition,G4double k, G4int ionizationLevelIndex, const G4String& materialName)
{
// k should be in eV
// Schematic explanation.
// We will do an interpolation to get a final E value (ejected electron energy).
// 1/ We choose a random number between 0 and 1 (ie we select a cumulated cross section).
// 2/ We look for T_lower and T_upper.
// 3/ We look for the cumulated corresponding cross sections and their associated E values.
//
// T_low | CS_low_1 -> E_low_1
// | CS_low_2 -> E_low_2
// T_up | CS_up_1 -> E_up_1
// | CS_up_2 -> E_up_2
//
// 4/ We interpolate to get our E value.
//
// T_low | CS_low_1 -> E_low_1 -----
// | |----> E_low --
// | CS_low_2 -> E_low_2 ----- |
// | ---> E_final
// T_up | CS_up_1 -> E_up_1 ------- |
// | |----> E_up ---
// | CS_up_2 -> E_up_2 -------
// Initialize some values
//
G4double ejectedElectronEnergy = 0.;
G4double valueK1 = 0;
G4double valueK2 = 0;
G4double valueCumulCS21 = 0;
G4double valueCumulCS22 = 0;
G4double valueCumulCS12 = 0;
G4double valueCumulCS11 = 0;
G4double secElecE11 = 0;
G4double secElecE12 = 0;
G4double secElecE21 = 0;
G4double secElecE22 = 0;
G4String particleName = particleDefinition->GetParticleName();
// ***************************************************************************
// Get a random number between 0 and 1 to compare with the cumulated CS
// ***************************************************************************
//
// It will allow us to choose an ejected electron energy with respect to the CS.
G4double random = G4UniformRand();
// **********************************************
// Take the input from the data tables
// **********************************************
// Cumulated tables are like this: T E cumulatedCS1 cumulatedCS2 cumulatedCS3
// We have two sets of loaded data: fTMapWithVec which contains data about T (incident particle energy)
// and fProbaShellMap which contains cumulated cross section data.
// Since we already have a specific T energy value which could not be explicitly in the table, we must interpolate all the values.
// First, we select the upper and lower T data values surrounding our T value (ie "k").
std::vector<double>::iterator k2 = std::upper_bound(fTMapWithVec[materialName][particleName].begin(),fTMapWithVec[materialName][particleName].end(), k);
std::vector<double>::iterator k1 = k2-1;
// Check if we have found a k2 value (0 if we did not found it).
// A missing k2 value can be caused by a energy to high for the data table,
// Ex : table done for 12*eV -> 1000*eV and k=2000*eV
// then k2 = 0 and k1 = max of the table.
// To detect this, we check that k1 is not superior to k2.
if(*k1 > *k2)
{
// Error
G4cerr<<"**************** Fatal error ******************"<<G4endl;
G4cerr<<"G4DNAPTBIonisationModel::RandomizeEjectedElectronEnergyFromCumulated"<<G4endl;
G4cerr<<"You have *k1 > *k2 with k1 "<<*k1<<" and k2 "<<*k2<<G4endl;
G4cerr<<"This may be because the energy of the incident particle is to high for the data table."<<G4endl;
G4cerr<<"Particle energy (eV): "<<k<<G4endl;
exit(EXIT_FAILURE);
}
// We have a random number and we select the cumulated cross section data values surrounding our random number.
// But we need to do that for each T value (ie two T values) previously selected.
//
// First one.
std::vector<double>::iterator cumulCS12 = std::upper_bound(fProbaShellMap[materialName][particleName][ionizationLevelIndex][(*k1)].begin(),
fProbaShellMap[materialName][particleName][ionizationLevelIndex][(*k1)].end(), random);
std::vector<double>::iterator cumulCS11 = cumulCS12-1;
// Second one.
std::vector<double>::iterator cumulCS22 = std::upper_bound(fProbaShellMap[materialName][particleName][ionizationLevelIndex][(*k2)].begin(),
fProbaShellMap[materialName][particleName][ionizationLevelIndex][(*k2)].end(), random);
std::vector<double>::iterator cumulCS21 = cumulCS22-1;
// Now that we have the "values" through pointers, we access them.
valueK1 = *k1;
valueK2 = *k2;
valueCumulCS11 = *cumulCS11;
valueCumulCS12 = *cumulCS12;
valueCumulCS21 = *cumulCS21;
valueCumulCS22 = *cumulCS22;
// *************************************************************
// Do the interpolation to get the ejected electron energy
// *************************************************************
// Here we will get four E values corresponding to our four cumulated cross section values previously selected.
// But we need to take into account a specific case: we have selected a shell by using the ionisation cross section table
// and, since we get two T values, we could have differential cross sections (or cumulated) equal to 0 for the lower T
// and not for the upper T. When looking for the cumulated cross section values which surround the selected random number (for the lower T),
// the upper_bound method will only found 0 values. Thus, the upper_bound method will return the last E value present in the table for the
// selected T. The last E value being the highest, we will later perform an interpolation between a high E value (for the lower T) and
// a small E value (for the upper T). This is inconsistent because if the cross section are equal to zero for the lower T then it
// means it is not possible to ionize and, thus, to have a secondary electron. But, in our situation, it is possible to ionize for the upper T
// AND for an interpolate T value between Tupper Tlower. That's why the final E value should be interpolate between 0 and the E value (upper T).
//
if(cumulCS12==fProbaShellMap[materialName][particleName][ionizationLevelIndex][(*k1)].end())
{
// Here we are in the special case and we force Elower1 and Elower2 to be equal at 0 for the interpolation.
secElecE11 = 0;
secElecE12 = 0;
secElecE21 = fEnergySecondaryData[materialName][particleName][ionizationLevelIndex][valueK2][valueCumulCS21];
secElecE22 = fEnergySecondaryData[materialName][particleName][ionizationLevelIndex][valueK2][valueCumulCS22];
valueCumulCS11 = 0;
valueCumulCS12 = 0;
}
else
{
// No special case, interpolation will happen as usual.
secElecE11 = fEnergySecondaryData[materialName][particleName][ionizationLevelIndex][valueK1][valueCumulCS11];
secElecE12 = fEnergySecondaryData[materialName][particleName][ionizationLevelIndex][valueK1][valueCumulCS12];
secElecE21 = fEnergySecondaryData[materialName][particleName][ionizationLevelIndex][valueK2][valueCumulCS21];
secElecE22 = fEnergySecondaryData[materialName][particleName][ionizationLevelIndex][valueK2][valueCumulCS22];
}
ejectedElectronEnergy = QuadInterpolator(valueCumulCS11, valueCumulCS12,
valueCumulCS21, valueCumulCS22,
secElecE11, secElecE12,
secElecE21, secElecE22,
valueK1, valueK2,
k, random);
// **********************************************
// Some tests for debugging
// **********************************************
G4double bindingEnergy (ptbStructure.IonisationEnergy(ionizationLevelIndex, materialName)/eV);
if(k-ejectedElectronEnergy-bindingEnergy<=0 || ejectedElectronEnergy<=0)
{
G4cout<<"k "<<k<<G4endl;
G4cout<<"material "<<materialName<<G4endl;
G4cout<<"secondaryKin "<<ejectedElectronEnergy<<G4endl;
G4cout<<"shell "<<ionizationLevelIndex<<G4endl;
G4cout<<"bindingEnergy "<<bindingEnergy<<G4endl;
G4cout<<"scatteredEnergy "<<k-ejectedElectronEnergy-bindingEnergy<<G4endl;
G4cout<<"rand "<<random<<G4endl;
G4cout<<"surrounding k values: valueK1 valueK2\n"<<valueK1<<" "<<valueK2<<G4endl;
G4cout<<"surrounding E values: secElecE11 secElecE12 secElecE21 secElecE22\n"
<<secElecE11<<" "<<secElecE12<<" "<<secElecE21<<" "<<secElecE22<<" "<<G4endl;
G4cout<<"surrounding cumulCS values: valueCumulCS11 valueCumulCS12 valueCumulCS21 valueCumulCS22\n"
<<valueCumulCS11<<" "<<valueCumulCS12<<" "<<valueCumulCS21<<" "<<valueCumulCS22<<" "<<G4endl;
G4cerr<<"*****************************"<<G4endl;
G4cerr<<"Fatal error, EXIT."<<G4endl;
exit(EXIT_FAILURE);
}
return ejectedElectronEnergy*eV;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4double G4DNAPTBIonisationModel::LogLogInterpolate(G4double e1,
G4double e2,
G4double e,
G4double xs1,
G4double xs2)
{
G4double value (0);
// Switch to log-lin interpolation for faster code
if ((e2-e1)!=0 && xs1 !=0 && xs2 !=0)
{
G4double d1 = std::log10(xs1);
G4double d2 = std::log10(xs2);
value = std::pow(10.,(d1 + (d2 - d1)*(e - e1)/ (e2 - e1)) );
}
// Switch to lin-lin interpolation for faster code
// in case one of xs1 or xs2 (=cum proba) value is zero
if ((e2-e1)!=0 && (xs1 ==0 || xs2 ==0))
{
G4double d1 = xs1;
G4double d2 = xs2;
value = (d1 + (d2 - d1)*(e - e1)/ (e2 - e1));
}
return value;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4double G4DNAPTBIonisationModel::QuadInterpolator(G4double e11, G4double e12,
G4double e21, G4double e22,
G4double xs11, G4double xs12,
G4double xs21, G4double xs22,
G4double t1, G4double t2,
G4double t, G4double e)
{
G4double interpolatedvalue1 (-1);
if(xs11!=xs12) interpolatedvalue1 = LogLogInterpolate(e11, e12, e, xs11, xs12);
else interpolatedvalue1 = xs11;
G4double interpolatedvalue2 (-1);
if(xs21!=xs22) interpolatedvalue2 = LogLogInterpolate(e21, e22, e, xs21, xs22);
else interpolatedvalue2 = xs21;
G4double value (-1);
if(interpolatedvalue1!=interpolatedvalue2) value = LogLogInterpolate(t1, t2, t, interpolatedvalue1, interpolatedvalue2);
else value = interpolatedvalue1;
return value;
// G4double interpolatedvalue1 = LogLogInterpolate(e11, e12, e, xs11, xs12);
// G4double interpolatedvalue2 = LogLogInterpolate(e21, e22, e, xs21, xs22);
// G4double value = LogLogInterpolate(t1, t2, t, interpolatedvalue1, interpolatedvalue2);
// return value;
}
@@ -23,7 +23,7 @@
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
// $Id: G4DNARuddIonisationExtendedModel.cc 96060 2016-03-11 12:58:04Z gcosmo $
// $Id: G4DNARuddIonisationExtendedModel.cc 104430 2017-05-31 07:43:44Z gcosmo $
// GEANT4 tag $Name: $
//
// Modified by Z. Francis, S. Incerti to handle HZE
@@ -742,7 +742,8 @@ void G4DNARuddIonisationExtendedModel::SampleSecondaries(std::vector<G4DynamicPa
if (pos2 != highEnergyLimit.end())highLim = pos2->second;
if (k >= lowLim && k < highLim)
if (k >= lowLim && k <= highLim)
// SI: no strict limits, like in the non extended version of the model
{
G4ParticleDefinition* definition = particle->GetDefinition();
G4ParticleMomentum primaryDirection = particle->GetMomentumDirection();
@@ -23,7 +23,7 @@
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
// $Id: G4DNARuddIonisationModel.cc 96060 2016-03-11 12:58:04Z gcosmo $
// $Id: G4DNARuddIonisationModel.cc 104430 2017-05-31 07:43:44Z gcosmo $
// GEANT4 tag $Name: $
//
@@ -0,0 +1,97 @@
//
// ********************************************************************
// * 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. *
// ********************************************************************
//
// $Id$
//
#include "G4DNAVacuumModel.hh"
#include "G4SystemOfUnits.hh"
#include "G4DNAChemistryManager.hh"
#include "G4DNAMolecularMaterial.hh"
G4DNAVacuumModel::G4DNAVacuumModel(const G4String& applyToMaterial, const G4ParticleDefinition*,
const G4String& nam)
: G4VDNAModel(nam, applyToMaterial)
{
verboseLevel = 0;
if( verboseLevel>0 )
{
G4cout << "G4DNAVacuumModel is constructed " << G4endl;
}
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4DNAVacuumModel::~G4DNAVacuumModel()
{
if (verboseLevel > 3)
G4cout << "Calling G4DNAVacuumModel::Initialise()" << G4endl;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4DNAVacuumModel::Initialise(const G4ParticleDefinition* particle,
const G4DataVector& /*cuts*/, G4ParticleChangeForGamma*)
{
if (verboseLevel > 3)
G4cout << "Calling G4DNAVacuumModel::Initialise()" << G4endl;
EnableForMaterialAndParticle("G4_Galactic", particle->GetParticleName() );
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4double G4DNAVacuumModel::CrossSectionPerVolume(const G4Material* /*material*/,
const G4String& /*materialName*/,
const G4ParticleDefinition* /*particleDefinition*/,
G4double /*ekin*/,
G4double /*emin*/,
G4double /*emax*/)
{
if (verboseLevel > 3)
G4cout << "Calling CrossSectionPerVolume() of G4DNAVacuumModel" << G4endl;
return 0;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4DNAVacuumModel::SampleSecondaries(std::vector<G4DynamicParticle*>* /*fvect*/,
const G4MaterialCutsCouple* /*couple*/,
const G4String& /*materialName*/,
const G4DynamicParticle* /*aDynamicParticle*/,
G4ParticleChangeForGamma* /*particleChangeForGamma*/,
G4double /*tmin*/,
G4double /*tmax*/)
{
if (verboseLevel > 3)
G4cout << "Calling SampleSecondaries() of G4DNAVacuumModel" << G4endl;
}
@@ -0,0 +1,286 @@
//
// ********************************************************************
// * 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. *
// ********************************************************************
//
// Authors: S. Meylan and C. Villagrasa (IRSN, France)
// This class is used to support PTB models that come from
// M. Bug et al, Rad. Phys and Chem. 130, 459-479 (2017)
//
#include "G4VDNAModel.hh"
#include "G4SystemOfUnits.hh"
#include "G4ParticleTable.hh"
G4VDNAModel::G4VDNAModel(const G4String &nam, const G4String &applyToMaterial)
: fStringOfMaterials(applyToMaterial), fName(nam)
{
}
G4VDNAModel::~G4VDNAModel()
{
// Clean fTableData
std::map<G4String, std::map<G4String,G4DNACrossSectionDataSet*,std::less<G4String> > >::iterator posOuter;
std::map<G4String,G4DNACrossSectionDataSet*,std::less<G4String> >::iterator posInner;
// iterate on each material
for (posOuter = fTableData.begin(); posOuter != fTableData.end(); ++posOuter)
{
// iterate on each particle
for(posInner = posOuter->second.begin(); posInner != posOuter->second.end(); ++posInner)
{
G4DNACrossSectionDataSet* table = posInner->second;
if(table != 0) delete table;
}
}
}
void G4VDNAModel::AddCrossSectionData(G4String materialName, G4String particleName, G4String fileCS, G4String fileDiffCS, G4double scaleFactor)
{
fModelMaterials.push_back(materialName);
fModelParticles.push_back(particleName);
fModelCSFiles.push_back(fileCS);
fModelDiffCSFiles.push_back(fileDiffCS);
fModelScaleFactors.push_back(scaleFactor);
}
void G4VDNAModel::AddCrossSectionData(G4String materialName, G4String particleName, G4String fileCS, G4double scaleFactor)
{
fModelMaterials.push_back(materialName);
fModelParticles.push_back(particleName);
fModelCSFiles.push_back(fileCS);
fModelScaleFactors.push_back(scaleFactor);
}
void G4VDNAModel::LoadCrossSectionData(const G4String& particleName)
{
G4String fileElectron, fileDiffElectron;
G4String materialName, modelParticleName;
G4double scaleFactor;
// construct applyToMatVect with materials specified by the user
std::vector<G4String> applyToMatVect = BuildApplyToMatVect(fStringOfMaterials);
// iterate on each material contained into the fStringOfMaterials variable (through applyToMatVect)
for(unsigned int i=0;i<applyToMatVect.size();++i)
{
// We have selected a material coming from applyToMatVect
// We try to find if this material correspond to a model registered material
// If it is, then isMatFound becomes true
G4bool isMatFound = false;
// We iterate on each model registered materials to load the CS data
// We have to do a for loop because of the "all" option
// applyToMatVect[i] == "all" implies applyToMatVect.size()=1 and we want to iterate on all registered materials
for(unsigned int j=0;j<fModelMaterials.size();++j)
{
if(applyToMatVect[i] == fModelMaterials[j] || applyToMatVect[i] == "all")
{
isMatFound = true;
materialName = fModelMaterials[j];
modelParticleName = fModelParticles[j];
fileElectron = fModelCSFiles[j];
if(!fModelDiffCSFiles.empty()) fileDiffElectron = fModelDiffCSFiles[j];
scaleFactor = fModelScaleFactors[j];
ReadAndSaveCSFile(materialName, modelParticleName, fileElectron, scaleFactor);
if(!fModelDiffCSFiles.empty()) ReadDiffCSFile(materialName, modelParticleName, fileDiffElectron, scaleFactor);
}
}
// check if we found a correspondance, if not: fatal error
if(!isMatFound)
{
std::ostringstream oss;
oss << applyToMatVect[i] << " material was not found. It means the material specified in the UserPhysicsList is not a model material for ";
oss << particleName;
G4Exception("G4VDNAModel::LoadCrossSectionData","em0003",
FatalException, oss.str().c_str());
return;
}
}
}
void G4VDNAModel::ReadDiffCSFile(const G4String&, const G4String&, const G4String&, const G4double)
{
G4String text("ReadDiffCSFile must be implemented in the model class using a differential cross section data file");
G4Exception("G4VDNAModel::ReadDiffCSFile","em0003",
FatalException, text);
}
void G4VDNAModel::EnableForMaterialAndParticle(const G4String &materialName, const G4String &particleName)
{
fTableData[materialName][particleName] = 0;
}
std::vector<G4String> G4VDNAModel::BuildApplyToMatVect(const G4String& materials)
{
// output material vector
std::vector<G4String> materialVect;
// if we don't find any "/" then it means we only have one "material" (could be the "all" option)
if(materials.find("/")==std::string::npos)
{
// we add the material to the output vector
materialVect.push_back(materials);
}
// if we have several materials listed in the string then we must retrieve them
else
{
G4String materialsNonIdentified = materials;
while(materialsNonIdentified.find_first_of("/") != std::string::npos)
{
// we select the first material and stop at the "/" caracter
G4String mat = materialsNonIdentified.substr(0, materialsNonIdentified.find_first_of("/"));
materialVect.push_back(mat);
// we remove the previous material from the materialsNonIdentified string
materialsNonIdentified = materialsNonIdentified.substr(materialsNonIdentified.find_first_of("/")+1,
materialsNonIdentified.size()-materialsNonIdentified.find_first_of("/"));
}
// we don't find "/" anymore, it means we only have one material string left
// we get it
materialVect.push_back(materialsNonIdentified);
}
return materialVect;
}
void G4VDNAModel::ReadAndSaveCSFile(const G4String& materialName,
const G4String& particleName,
const G4String& file, G4double scaleFactor)
{
fTableData[materialName][particleName] = new G4DNACrossSectionDataSet(new G4LogLogInterpolation, eV, scaleFactor);
fTableData[materialName][particleName]->LoadData(file);
}
G4int G4VDNAModel::RandomSelectShell(G4double k, const G4String& particle, const G4String& materialName)
{
G4int level = 0;
TableMapData* tableData = GetTableData();
std::map< G4String,G4DNACrossSectionDataSet*,std::less<G4String> >::iterator pos;
pos = (*tableData)[materialName].find(particle);
if (pos != (*tableData)[materialName].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("G4VDNAModel::RandomSelectShell","em0002",
FatalException,"Model not applicable to particle type.");
}
return level;
}
G4bool G4VDNAModel::IsMaterialDefine(const G4String& materialName)
{
// Check if the given material is defined in the simulation
G4bool exist (false);
double matTableSize = G4Material::GetMaterialTable()->size();
for(int i=0;i<matTableSize;i++)
{
if(materialName == G4Material::GetMaterialTable()->at(i)->GetName())
{
exist = true;
return exist;
}
}
return exist;
}
G4bool G4VDNAModel::IsMaterialExistingInModel(const G4String& materialName)
{
// Check if the given material is defined in the current model class
if (fTableData.find(materialName) == fTableData.end())
{
return false;
}
else
{
return true;
}
}
G4bool G4VDNAModel::IsParticleExistingInModelForMaterial(const G4String& particleName, const G4String& materialName)
{
// To check two things:
// 1- is the material existing in model ?
// 2- if yes, is the particle defined for that material ?
if(IsMaterialExistingInModel(materialName))
{
if (fTableData[materialName].find(particleName) == fTableData[materialName].end())
{
return false;
}
else return true;
}
else return false;
}