Files
geant4/source/processes/electromagnetic/lowenergy/src/G4hLowEnergyIonisation.cc
T
2016-06-09 10:15:15 +02:00

2009 lines
64 KiB
C++

//
// ********************************************************************
// * DISCLAIMER *
// * *
// * The following disclaimer summarizes all the specific disclaimers *
// * of contributors to this software. The specific disclaimers,which *
// * govern, are listed with their locations in: *
// * http://cern.ch/geant4/license *
// * *
// * 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. *
// * *
// * This code implementation is the intellectual property of the *
// * GEANT4 collaboration. *
// * By copying, distributing or modifying the Program (or any work *
// * based on the Program) you indicate your acceptance of this *
// * statement, and all its terms. *
// ********************************************************************
//
//
// -------------------------------------------------------------
// GEANT 4 class implementation file
//
// History: based on object model of
// 2nd December 1995, G.Cosmo
// ---------- G4hLowEnergyIonisation physics process -------
// by Vladimir Ivanchenko, 14 July 1999
// was made on the base of G4hIonisation class
// developed by Laszlo Urban
// ************************************************************
// It is the extention of the ionisation process for the slow
// charged hadrons.
// ************************************************************
// 28 July 1999 V.Ivanchenko cleen up
// 17 August 1999 G.Mancinelli added ICRU parametrisations for protons
// 20 August 1999 G.Mancinelli added ICRU tables for alpha
// 31 August 1999 V.Ivanchenko update and cleen up
// 30 Sept. 1999 V.Ivanchenko minor upgrade
// 12 Dec. 1999 S. Chauvie added Barkas correction
// 19 Jan. 2000 V.Ivanchenko minor changing in Barkas corrections
// 02 April 2000 S. Chauvie linearization of Barkas effect
// 03 April 2000 V.Ivanchenko Nuclear Stopping power for antiprotons
// 23 May 2000 MG Pia Clean up for QAO model
// 24 May 2000 MG Pia Code properly indented to improve legibility
// 17 July 2000 V.Ivanchenko Bug in scaling AlongStepDoIt method
// 25 July 2000 V.Ivanchenko New design iteration
// 17 August 2000 V.Ivanchenko Add ion fluctuation models
// 18 August 2000 V.Ivanchenko Bug fixed in GetConstrain
// 22 August 2000 V.Ivanchenko Insert paramStepLimit and
// reorganise access to Barkas and Bloch terms
// 04 Sept. 2000 V.Ivanchenko rename fluctuations
// 05 Sept. 2000 V.Ivanchenko clean up
// 03 Oct. 2000 V.Ivanchenko CodeWizard clean up
// 03 Nov. 2000 V.Ivanchenko MinKineticEnergy=LowestKineticEnergy=10eV
// 05 Nov. 2000 MG Pia - Removed const cast previously introduced to get
// the code compiled (const G4Material* now introduced in
// electromagnetic/utils utils-V02-00-03 tag)
// (this is going back and forth, to cope with Michel's
// utils tag not being accepted yet by system testing)
// 21 Nov. 2000 V.Ivanchenko Fix a problem in fluctuations
// 23 Nov. 2000 V.Ivanchenko Ion type fluctuations only for charge>0
// 10 May 2001 V.Ivanchenko Clean up againist Linux compilation with -Wall
// 23 May 2001 V.Ivanchenko Minor fix in PostStepDoIt
// 07 June 2001 V.Ivanchenko Clean up AntiProtonDEDX + add print out
// 18 June 2001 V.Ivanchenko Cleanup print out
// 18 Oct. 2001 V.Ivanchenko Add fluorescence
// 30 Oct. 2001 V.Ivanchenko Add minGammaEnergy and minElectronEnergy
// 07 Dec 2001 V.Ivanchenko Add SetFluorescence method
// 15 Feb 2002 V.Ivanchenko Fix problem of Generic Ions
// 25 Mar 2002 V.Ivanchenko Fix problem of fluorescence below threshold
// 28 Mar 2002 V.Ivanchenko Set fluorescence off by default
// 09 Apr 2002 V.Ivanchenko Fix table problem of GenericIons
// 28 May 2002 V.Ivanchenko Remove flag fStopAndKill
// 31 May 2002 V.Ivanchenko Add path of Fluo + Auger cuts to
// AtomicDeexcitation
// 03 Jun 2002 MGP Restore fStopAndKill
// 10 Jun 2002 V.Ivanchenko Restore fStopButAlive
// 12 Jun 2002 V.Ivanchenko Fix in fluctuations - if tmax<2*Ipot Gaussian
// fluctuations enables
// 20 Sept 2002 V.Ivanchenko Clean up energy ranges for models
// 07 Oct 2002 V.Ivanchenko Clean up initialisation of fluorescence
// 28 Oct 2002 V.Ivanchenko Optimal binning for dE/dx
// 10 Dec 2002 V.Ivanchenko antiProtonLowEnergy -> 25 keV, QEG model below
// 21 Jan 2003 V.Ivanchenko Cut per region
// 10 Mar 2003 V.Ivanchenko Use SubTypes for ions
// 12 Apr 2003 V.Ivanchenko Cut per region for fluo AlongStep
// 18 Apr 2003 V.Ivanchenko finalRange redefinition
// 26 Apr 2003 V.Ivanchenko fix for stepLimit
// -----------------------------------------------------------------------
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
#include "G4hLowEnergyIonisation.hh"
#include "globals.hh"
#include "G4ios.hh"
#include "Randomize.hh"
#include "G4Poisson.hh"
#include "G4UnitsTable.hh"
#include "G4EnergyLossTables.hh"
#include "G4Material.hh"
#include "G4DynamicParticle.hh"
#include "G4ParticleDefinition.hh"
#include "G4AtomicDeexcitation.hh"
#include "G4AtomicTransitionManager.hh"
#include "G4ShellVacancy.hh"
#include "G4hShellCrossSection.hh"
#include "G4VEMDataSet.hh"
#include "G4EMDataSet.hh"
#include "G4CompositeEMDataSet.hh"
#include "G4Gamma.hh"
#include "G4LogLogInterpolation.hh"
#include "G4SemiLogInterpolation.hh"
#include "G4ProcessManager.hh"
#include "G4ProductionCutsTable.hh"
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4hLowEnergyIonisation::G4hLowEnergyIonisation(const G4String& processName)
: G4hLowEnergyLoss(processName),
theBetheBlochModel(0),
theProtonModel(0),
theAntiProtonModel(0),
theIonEffChargeModel(0),
theNuclearStoppingModel(0),
theIonChuFluctuationModel(0),
theIonYangFluctuationModel(0),
theProtonTable("ICRU_R49p"),
theAntiProtonTable("ICRU_R49p"),
theNuclearTable("ICRU_R49"),
nStopping(true),
theBarkas(true),
theMeanFreePathTable(0),
paramStepLimit (0.005),
shellVacancy(0),
shellCS(0),
theFluo(false)
{
InitializeMe();
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4hLowEnergyIonisation::InitializeMe()
{
LowestKineticEnergy = 10.0*eV ;
HighestKineticEnergy = 100.0*GeV ;
MinKineticEnergy = 10.0*eV ;
TotBin = 360 ;
protonLowEnergy = 1.*keV ;
protonHighEnergy = 2.*MeV ;
antiProtonLowEnergy = 25.*keV ;
antiProtonHighEnergy = 2.*MeV ;
minGammaEnergy = 25.*keV;
minElectronEnergy = 25.*keV;
verboseLevel = 0;
shellCS = new G4hShellCrossSection();
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4hLowEnergyIonisation::~G4hLowEnergyIonisation()
{
if (theMeanFreePathTable) {
theMeanFreePathTable->clearAndDestroy();
delete theMeanFreePathTable;
}
if(theBetheBlochModel)delete theBetheBlochModel;
if(theProtonModel)delete theProtonModel;
if(theAntiProtonModel)delete theAntiProtonModel;
if(theNuclearStoppingModel)delete theNuclearStoppingModel;
if(theIonEffChargeModel)delete theIonEffChargeModel;
if(theIonChuFluctuationModel)delete theIonChuFluctuationModel;
if(theIonYangFluctuationModel)delete theIonYangFluctuationModel;
if(shellVacancy) delete shellVacancy;
if(shellCS) delete shellCS;
cutForDelta.clear();
G4int length = zFluoDataVector.size();
if(length) {
for(G4int i=0; i<length; i++) {
delete &(zFluoDataVector[i]);
}
zFluoDataVector.clear();
}
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4hLowEnergyIonisation::SetElectronicStoppingPowerModel(
const G4ParticleDefinition* aParticle,
const G4String& dedxTable)
// This method defines the ionisation parametrisation method via its name
{
if(0 < aParticle->GetPDGCharge()) {
SetProtonElectronicStoppingPowerModel(dedxTable) ;
} else {
SetAntiProtonElectronicStoppingPowerModel(dedxTable) ;
}
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4hLowEnergyIonisation::InitializeParametrisation()
{
// Define models for parametrisation of electronic energy losses
theBetheBlochModel = new G4hBetheBlochModel("Bethe-Bloch") ;
theProtonModel = new G4hParametrisedLossModel(theProtonTable) ;
theAntiProtonModel = new G4QAOLowEnergyLoss(theAntiProtonTable) ;
theNuclearStoppingModel = new G4hNuclearStoppingModel(theNuclearTable) ;
theIonEffChargeModel = new G4hIonEffChargeSquare("Ziegler1988") ;
theIonChuFluctuationModel = new G4IonChuFluctuationModel("Chu") ;
theIonYangFluctuationModel = new G4IonYangFluctuationModel("Yang") ;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4hLowEnergyIonisation::BuildPhysicsTable(
const G4ParticleDefinition& aParticleType)
// just call BuildLossTable+BuildLambdaTable
{
if(verboseLevel > 0) {
G4cout << "G4hLowEnergyIonisation::BuildPhysicsTable for "
<< aParticleType.GetParticleName()
<< " mass(MeV)= " << aParticleType.GetPDGMass()/MeV
<< " charge= " << aParticleType.GetPDGCharge()/eplus
<< " type= " << aParticleType.GetParticleType()
<< G4endl;
if(verboseLevel > 1) {
G4ProcessVector* pv = aParticleType.GetProcessManager()->GetProcessList();
G4cout << " 0: " << (*pv)[0]->GetProcessName() << " " << (*pv)[0]
<< " 1: " << (*pv)[1]->GetProcessName() << " " << (*pv)[1]
// << " 2: " << (*pv)[2]->GetProcessName() << " " << (*pv)[2]
<< G4endl;
G4cout << "ionModel= " << theIonEffChargeModel
<< " MFPtable= " << theMeanFreePathTable
<< " iniMass= " << initialMass
<< G4endl;
}
}
if(aParticleType.GetParticleType() == "nucleus" &&
aParticleType.GetParticleName() != "GenericIon" &&
aParticleType.GetParticleSubType() == "generic")
{
G4EnergyLossTables::Register(&aParticleType,
theDEDXpTable,
theRangepTable,
theInverseRangepTable,
theLabTimepTable,
theProperTimepTable,
LowestKineticEnergy, HighestKineticEnergy,
proton_mass_c2/aParticleType.GetPDGMass(),
TotBin);
return;
}
if( !CutsWhereModified() && theLossTable) return;
InitializeParametrisation() ;
G4Proton* theProton = G4Proton::Proton();
G4AntiProton* theAntiProton = G4AntiProton::AntiProton();
charge = aParticleType.GetPDGCharge()/eplus;
chargeSquare = charge*charge ;
const G4ProductionCutsTable* theCoupleTable=
G4ProductionCutsTable::GetProductionCutsTable();
size_t numOfCouples = theCoupleTable->GetTableSize();
cutForDelta.clear();
cutForGamma.clear();
for (size_t j=0; j<numOfCouples; j++) {
// get material parameters needed for the energy loss calculation
const G4MaterialCutsCouple* couple = theCoupleTable->GetMaterialCutsCouple(j);
const G4Material* material= couple->GetMaterial();
// the cut cannot be below lowest limit
G4double tCut = (*(theCoupleTable->GetEnergyCutsVector(1)))[j];
if(tCut > HighestKineticEnergy) tCut = HighestKineticEnergy;
G4double excEnergy = material->GetIonisation()->GetMeanExcitationEnergy();
tCut = G4std::max(tCut,excEnergy);
cutForDelta.push_back(tCut);
// the cut cannot be below lowest limit
tCut = (*(theCoupleTable->GetEnergyCutsVector(0)))[j];
if(tCut > HighestKineticEnergy) tCut = HighestKineticEnergy;
tCut = G4std::max(tCut,minGammaEnergy);
cutForGamma.push_back(tCut);
}
if(verboseLevel > 0) {
G4cout << "Cuts are defined " << G4endl;
}
if(0.0 < charge)
{
{
BuildLossTable(*theProton) ;
RecorderOfpProcess[CounterOfpProcess] = theLossTable ;
CounterOfpProcess++;
}
} else {
{
BuildLossTable(*theAntiProton) ;
RecorderOfpbarProcess[CounterOfpbarProcess] = theLossTable ;
CounterOfpbarProcess++;
}
}
if(verboseLevel > 0) {
G4cout << "G4hLowEnergyIonisation::BuildPhysicsTable: "
<< "Loss table is built "
// << theLossTable
<< G4endl;
}
BuildLambdaTable(aParticleType) ;
BuildDataForFluorescence(aParticleType);
if(verboseLevel > 1) {
G4cout << (*theMeanFreePathTable) << G4endl;
}
if(verboseLevel > 0) {
G4cout << "G4hLowEnergyIonisation::BuildPhysicsTable: "
<< "DEDX table will be built "
// << theDEDXpTable << " " << theDEDXpbarTable
// << " " << theRangepTable << " " << theRangepbarTable
<< G4endl;
}
BuildDEDXTable(aParticleType) ;
if(verboseLevel > 1) {
G4cout << (*theDEDXpTable) << G4endl;
}
if((&aParticleType == theProton) ) PrintInfoDefinition() ;
if(verboseLevel > 0) {
G4cout << "G4hLowEnergyIonisation::BuildPhysicsTable: end for "
<< aParticleType.GetParticleName() << G4endl;
}
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4hLowEnergyIonisation::BuildLossTable(
const G4ParticleDefinition& aParticleType)
{
// Initialisation
G4double lowEdgeEnergy , ionloss, ionlossBB, paramB ;
G4double lowEnergy, highEnergy;
G4Proton* theProton = G4Proton::Proton();
if(aParticleType == *theProton) {
lowEnergy = protonLowEnergy ;
highEnergy = protonHighEnergy ;
charge = 1.0 ;
} else {
lowEnergy = antiProtonLowEnergy ;
highEnergy = antiProtonHighEnergy ;
charge = -1.0 ;
}
chargeSquare = 1.0 ;
const G4ProductionCutsTable* theCoupleTable=
G4ProductionCutsTable::GetProductionCutsTable();
size_t numOfCouples = theCoupleTable->GetTableSize();
if ( theLossTable) {
theLossTable->clearAndDestroy();
delete theLossTable;
}
theLossTable = new G4PhysicsTable(numOfCouples);
// loop for materials
for (size_t j=0; j<numOfCouples; j++) {
// create physics vector and fill it
G4PhysicsLogVector* aVector = new G4PhysicsLogVector(LowestKineticEnergy,
HighestKineticEnergy,
TotBin);
// get material parameters needed for the energy loss calculation
const G4MaterialCutsCouple* couple = theCoupleTable->GetMaterialCutsCouple(j);
const G4Material* material= couple->GetMaterial();
if ( charge > 0.0 ) {
ionloss = ProtonParametrisedDEDX(couple,highEnergy) ;
} else {
ionloss = AntiProtonParametrisedDEDX(couple,highEnergy) ;
}
ionlossBB = theBetheBlochModel->TheValue(&aParticleType,material,highEnergy) ;
ionlossBB -= DeltaRaysEnergy(couple,highEnergy,proton_mass_c2) ;
paramB = ionloss/ionlossBB - 1.0 ;
// now comes the loop for the kinetic energy values
for (G4int i = 0 ; i < TotBin ; i++) {
lowEdgeEnergy = aVector->GetLowEdgeEnergy(i) ;
// low energy part for this material, parametrised energy loss formulae
if ( lowEdgeEnergy < highEnergy ) {
if ( charge > 0.0 ) {
ionloss = ProtonParametrisedDEDX(couple,lowEdgeEnergy) ;
} else {
ionloss = AntiProtonParametrisedDEDX(couple,lowEdgeEnergy) ;
}
} else {
// high energy part for this material, Bethe-Bloch formula
ionloss = theBetheBlochModel->TheValue(theProton,material,
lowEdgeEnergy) ;
ionloss -= DeltaRaysEnergy(couple,lowEdgeEnergy,proton_mass_c2) ;
ionloss *= (1.0 + paramB*highEnergy/lowEdgeEnergy) ;
}
// now put the loss into the vector
if(verboseLevel > 1) {
G4cout << "E(MeV)= " << lowEdgeEnergy/MeV
<< " dE/dx(MeV/mm)= " << ionloss*mm/MeV
<< " in " << material->GetName() << G4endl;
}
aVector->PutValue(i,ionloss) ;
}
// Insert vector for this material into the table
theLossTable->insert(aVector) ;
}
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4hLowEnergyIonisation::BuildDataForFluorescence(
const G4ParticleDefinition& aParticleType)
{
if(verboseLevel > 1) {
G4cout << "G4hLowEnergyIonisation::BuildDataForFluorescence for "
<< aParticleType.GetParticleName() << " is started" << G4endl;
}
// fill data for fluorescence
deexcitationManager.SetCutForSecondaryPhotons(minGammaEnergy);
deexcitationManager.SetCutForAugerElectrons(minElectronEnergy);
G4double mass = aParticleType.GetPDGMass();
const G4ProductionCutsTable* theCoupleTable=
G4ProductionCutsTable::GetProductionCutsTable();
size_t numOfCouples = theCoupleTable->GetTableSize();
if (shellVacancy != 0) delete shellVacancy;
shellVacancy = new G4ShellVacancy();
G4DataVector* ksi = 0;
G4DataVector* ksi1 = 0;
G4DataVector* energy = 0;
G4DataVector* energy1 = 0;
size_t binForFluo = TotBin/10;
G4int length = zFluoDataVector.size();
if(length > 0) {
for(G4int i=0; i<length; i++) {
G4VEMDataSet* x = zFluoDataVector[i];
delete x;
}
zFluoDataVector.clear();
}
G4PhysicsLogVector* bVector = new G4PhysicsLogVector(LowestKineticEnergy,
HighestKineticEnergy,
binForFluo);
const G4AtomicTransitionManager* transitionManager =
G4AtomicTransitionManager::Instance();
G4double bindingEnergy;
// G4double x;
// G4double y;
// loop for materials
for (size_t j=0; j<numOfCouples; j++) {
// get material parameters needed for the energy loss calculation
const G4MaterialCutsCouple* couple = theCoupleTable->GetMaterialCutsCouple(j);
const G4Material* material= couple->GetMaterial();
const G4ElementVector* theElementVector = material->GetElementVector();
size_t NumberOfElements = material->GetNumberOfElements() ;
const G4double* theAtomicNumDensityVector =
material->GetAtomicNumDensityVector();
G4VDataSetAlgorithm* interp = new G4SemiLogInterpolation();
G4VEMDataSet* xsis = new G4CompositeEMDataSet(interp, 1., 1.);
G4VDataSetAlgorithm* interp1 = new G4SemiLogInterpolation();
G4VEMDataSet* xsis1 = new G4CompositeEMDataSet(interp1, 1., 1.);
G4double tCut = cutForDelta[j];
G4double elDensity = 1.;
for (size_t iel=0; iel<NumberOfElements; iel++ ) {
G4int Z = (G4int)((*theElementVector)[iel]->GetZ());
G4int nShells = transitionManager->NumberOfShells(Z);
energy = new G4DataVector();
ksi = new G4DataVector();
energy1= new G4DataVector();
ksi1 = new G4DataVector();
//if(NumberOfElements > 1)
elDensity = theAtomicNumDensityVector[iel]/((G4double)nShells);
for (size_t j = 0; j<binForFluo; j++) {
G4double tkin = bVector->GetLowEdgeEnergy(j);
G4double gamma = tkin/mass + 1.;
G4double beta2 = 1.0 - 1.0/(gamma*gamma);
G4double r = electron_mass_c2/mass;
G4double tmax = 2.*electron_mass_c2*(gamma*gamma - 1.)/(1. + 2.*gamma*r + r*r);
G4double cross = 0.;
G4double cross1 = 0.;
G4double eAverage= 0.;
G4double tmin = G4std::min(tCut,tmax);
G4double rel;
for (G4int n=0; n<nShells; n++) {
bindingEnergy = transitionManager->Shell(Z, n)->BindingEnergy();
if (tmin > bindingEnergy) {
rel = log(tmin/bindingEnergy);
eAverage += rel - beta2*(tmin - bindingEnergy)/tmax;
cross += 1.0/bindingEnergy - 1.0/tmin - beta2*rel/tmax;
}
if (tmax > tmin) {
cross1 += 1.0/tmin - 1.0/tmax - beta2*log(tmax/tmin)/tmax;
}
}
cross1 *= elDensity;
energy1->push_back(tkin);
ksi1->push_back(cross1);
if(eAverage > 0.) cross /= eAverage;
else cross = 0.;
energy->push_back(tkin);
ksi->push_back(cross);
}
G4VDataSetAlgorithm* algo = interp->Clone();
G4VEMDataSet* set = new G4EMDataSet(Z,energy,ksi,algo,1.,1.);
xsis->AddComponent(set);
G4VDataSetAlgorithm* algo1 = interp1->Clone();
G4VEMDataSet* set1 = new G4EMDataSet(Z,energy1,ksi1,algo1,1.,1.);
xsis1->AddComponent(set1);
}
if(verboseLevel > 1) {
G4cout << "### Shell inverse cross sections for "
<< material->GetName() << G4endl;
xsis->PrintData();
G4cout << "### Atom cross sections for "
<< material->GetName() << G4endl;
xsis1->PrintData();
}
shellVacancy->AddXsiTable(xsis);
zFluoDataVector.push_back(xsis1);
}
delete bVector;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4hLowEnergyIonisation::BuildLambdaTable(
const G4ParticleDefinition& aParticleType)
{
// Build mean free path tables for the delta ray production process
// tables are built for MATERIALS
if(verboseLevel > 1) {
G4cout << "G4hLowEnergyIonisation::BuildLambdaTable for "
<< aParticleType.GetParticleName() << " is started" << G4endl;
}
G4double lowEdgeEnergy, value;
charge = aParticleType.GetPDGCharge()/eplus ;
chargeSquare = charge*charge ;
initialMass = aParticleType.GetPDGMass();
const G4ProductionCutsTable* theCoupleTable=
G4ProductionCutsTable::GetProductionCutsTable();
size_t numOfCouples = theCoupleTable->GetTableSize();
if (theMeanFreePathTable) {
theMeanFreePathTable->clearAndDestroy();
delete theMeanFreePathTable;
}
theMeanFreePathTable = new G4PhysicsTable(numOfCouples);
// loop for materials
for (size_t J=0 ; J < numOfCouples; J++) {
//create physics vector then fill it ....
G4PhysicsLogVector* aVector = new G4PhysicsLogVector(LowestKineticEnergy,
HighestKineticEnergy,
TotBin);
// compute the (macroscopic) cross section first
const G4MaterialCutsCouple* couple = theCoupleTable->GetMaterialCutsCouple(J);
const G4Material* material= couple->GetMaterial();
const G4ElementVector* theElementVector =
material->GetElementVector() ;
const G4double* theAtomicNumDensityVector =
material->GetAtomicNumDensityVector();
const G4int NumberOfElements = material->GetNumberOfElements() ;
// get the electron kinetic energy cut for the actual material,
// it will be used in ComputeMicroscopicCrossSection
// ( it is the SAME for ALL the ELEMENTS in THIS MATERIAL )
// ------------------------------------------------------
G4double deltaCut = cutForDelta[J];
for ( G4int i = 0 ; i < TotBin ; i++ ) {
lowEdgeEnergy = aVector->GetLowEdgeEnergy(i) ;
G4double sigma = 0.0 ;
for (G4int iel=0; iel<NumberOfElements; iel++ ) {
sigma += theAtomicNumDensityVector[iel]*
ComputeMicroscopicCrossSection(
aParticleType,
lowEdgeEnergy,
(*theElementVector)[iel]->GetZ(),
deltaCut ) ;
}
// mean free path = 1./macroscopic cross section
value = sigma<=0 ? DBL_MAX : 1./sigma ;
aVector->PutValue(i, value) ;
}
theMeanFreePathTable->insert(aVector);
}
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4double G4hLowEnergyIonisation::ComputeMicroscopicCrossSection(
const G4ParticleDefinition& aParticleType,
G4double kineticEnergy,
G4double atomicNumber,
G4double deltaCutInEnergy) const
{
//******************************************************************
// cross section formula is OK for spin=0, 1/2, 1 only !
// *****************************************************************
// calculates the microscopic cross section in GEANT4 internal units
// ( it is called for elements , AtomicNumber = z )
G4double energy, gamma, beta2, tmax, var;
G4double totalCrossSection = 0.0 ;
G4double particleMass = initialMass;
// get particle data ...................................
energy = kineticEnergy + particleMass;
// some kinematics......................
gamma = energy/particleMass;
beta2 = 1.0 - 1.0/(gamma*gamma);
var = electron_mass_c2/particleMass;
tmax = 2.*electron_mass_c2*(gamma*gamma - 1.)/(1. + 2.*gamma*var + var*var);
// now you can calculate the total cross section
if( tmax > deltaCutInEnergy ) {
var=deltaCutInEnergy/tmax;
totalCrossSection = (1.0 - var*(1.0 - beta2*log(var))) / deltaCutInEnergy ;
G4double spin = aParticleType.GetPDGSpin() ;
// +term for spin=1/2 particle
if( 0.5 == spin )
totalCrossSection += 0.5 * (tmax - deltaCutInEnergy) / (energy*energy);
// +term for spin=1 particle
else if( 0.9 < spin )
totalCrossSection += -log(var)/(3.0*deltaCutInEnergy) +
(tmax - deltaCutInEnergy) * ( (5.0+ 1.0/var)*0.25 / (energy*energy) -
beta2 / (tmax * deltaCutInEnergy) ) / 3.0 ;
totalCrossSection *= twopi_mc2_rcl2 * atomicNumber / beta2 ;
}
return totalCrossSection ;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4double G4hLowEnergyIonisation::GetMeanFreePath(const G4Track& trackData,
G4double previousStepSize,
enum G4ForceCondition* condition)
{
const G4DynamicParticle* aParticle = trackData.GetDynamicParticle();
const G4MaterialCutsCouple* couple = trackData.GetMaterialCutsCouple();
const G4Material* material = couple->GetMaterial();
G4double meanFreePath;
G4bool isOutRange ;
*condition = NotForced ;
G4double kineticEnergy = (aParticle->GetKineticEnergy())*initialMass/(aParticle->GetMass());
charge = aParticle->GetCharge();
chargeSquare = theIonEffChargeModel->TheValue(aParticle, material);
if(kineticEnergy < LowestKineticEnergy) meanFreePath = DBL_MAX;
else {
if(kineticEnergy > HighestKineticEnergy)
kineticEnergy = HighestKineticEnergy;
meanFreePath = (((*theMeanFreePathTable)(couple->GetIndex()))->
GetValue(kineticEnergy,isOutRange))/chargeSquare;
}
return meanFreePath ;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4double G4hLowEnergyIonisation::GetConstraints(
const G4DynamicParticle* particle,
const G4MaterialCutsCouple* couple)
{
// returns the Step limit
// dEdx is calculated as well as the range
// based on Effective Charge Approach
const G4Material* material = couple->GetMaterial();
G4Proton* theProton = G4Proton::Proton();
G4AntiProton* theAntiProton = G4AntiProton::AntiProton();
G4double stepLimit = 0.0 ;
G4double dx, highEnergy;
G4double massRatio = proton_mass_c2/(particle->GetMass()) ;
G4double kineticEnergy = particle->GetKineticEnergy() ;
// Scale the kinetic energy
G4double tscaled = kineticEnergy*massRatio ;
if(charge > 0.0) {
highEnergy = protonHighEnergy ;
fRangeNow = G4EnergyLossTables::GetRange(theProton, tscaled, couple);
dx = G4EnergyLossTables::GetRange(theProton, highEnergy, couple);
fdEdx = G4EnergyLossTables::GetDEDX(theProton, tscaled, couple)
* chargeSquare ;
if(tscaled > highEnergy) {
// Correction for positive ions
if(theBarkas) {
fdEdx += BarkasTerm(material,tscaled)*sqrt(chargeSquare)*chargeSquare;
fdEdx += BlochTerm(material,tscaled,chargeSquare);
}
}
// Antiprotons and negative hadrons
} else {
highEnergy = antiProtonHighEnergy ;
fRangeNow = G4EnergyLossTables::GetRange(theAntiProton, tscaled, couple);
dx = G4EnergyLossTables::GetRange(theAntiProton, highEnergy, couple);
fdEdx = G4EnergyLossTables::GetDEDX(theAntiProton, tscaled, couple)
* chargeSquare ;
if(tscaled > highEnergy) {
// Correction for positive ions
if(theBarkas) {
fdEdx -= BarkasTerm(material,tscaled)*sqrt(chargeSquare)*chargeSquare;
fdEdx += BlochTerm(material,tscaled,chargeSquare);
}
}
}
// scaling back
fRangeNow /= (chargeSquare*massRatio) ;
dx /= (chargeSquare*massRatio) ;
stepLimit = fRangeNow ;
G4double r = G4std::min(finalRange, couple->GetProductionCuts()
->GetProductionCut(idxG4ElectronCut));
if (fRangeNow > r) {
stepLimit = dRoverRange*fRangeNow + r*(1.0 - dRoverRange)*(2.0 - r/fRangeNow);
if(rndmStepFlag) stepLimit = r + (stepLimit-r)*G4UniformRand() ;
if (stepLimit > fRangeNow) stepLimit = fRangeNow;
}
// compute the (random) Step limit in standard energy range
if(tscaled > highEnergy ) {
if(stepLimit > fRangeNow - dx*0.9) stepLimit = fRangeNow - dx*0.9 ;
// Step limit in low energy range
} else {
G4double x = dx*paramStepLimit;
if (stepLimit > x) stepLimit = x;
}
return stepLimit ;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4VParticleChange* G4hLowEnergyIonisation::AlongStepDoIt(
const G4Track& trackData,
const G4Step& stepData)
{
// compute the energy loss after a step
G4Proton* theProton = G4Proton::Proton();
G4AntiProton* theAntiProton = G4AntiProton::AntiProton();
G4double finalT = 0.0 ;
aParticleChange.Initialize(trackData) ;
const G4MaterialCutsCouple* couple = trackData.GetMaterialCutsCouple();
const G4Material* material = couple->GetMaterial();
// get the actual (true) Step length from stepData
const G4double step = stepData.GetStepLength() ;
const G4DynamicParticle* particle = trackData.GetDynamicParticle() ;
G4double kineticEnergy = particle->GetKineticEnergy() ;
G4double massRatio = proton_mass_c2/(particle->GetMass()) ;
G4double tscaled= kineticEnergy*massRatio ;
G4double eloss = 0.0 ;
G4double nloss = 0.0 ;
// very small particle energy
if(kineticEnergy < MinKineticEnergy) {
eloss = kineticEnergy ;
// particle energy outside tabulated energy range
} else if( kineticEnergy > HighestKineticEnergy) {
eloss = step*fdEdx ;
// big step
} else if(step >= fRangeNow ) {
eloss = kineticEnergy ;
// tabulated range
} else {
// step longer than linear step limit
if(step > linLossLimit*fRangeNow) {
G4double rscaled= fRangeNow*massRatio*chargeSquare ;
G4double sscaled= step *massRatio*chargeSquare ;
if(charge > 0.0) {
eloss = G4EnergyLossTables::GetPreciseEnergyFromRange(
theProton,rscaled, couple) -
G4EnergyLossTables::GetPreciseEnergyFromRange(
theProton,rscaled-sscaled,couple) ;
} else {
eloss = G4EnergyLossTables::GetPreciseEnergyFromRange(
theAntiProton,rscaled,couple) -
G4EnergyLossTables::GetPreciseEnergyFromRange(
theAntiProton,rscaled-sscaled,couple) ;
}
eloss /= massRatio ;
// step shorter than linear step limit
} else {
eloss = step*fdEdx ;
}
// Correction for positive ions
if(theBarkas && 1.0 < charge) {
G4double ts = tscaled - eloss*0.5*massRatio;
if(ts < protonHighEnergy) ts = protonHighEnergy;
eloss += BarkasTerm(material,ts)*charge*chargeSquare*step;
eloss += BlochTerm(material,ts,chargeSquare)*step;
}
if(nStopping && tscaled < protonHighEnergy) {
nloss = (theNuclearStoppingModel->TheValue(particle, material))*step;
}
}
if(eloss < 0.0) eloss = 0.0;
finalT = kineticEnergy - eloss - nloss;
if( EnlossFlucFlag && 0.0 < eloss && finalT > MinKineticEnergy) {
// now the electron loss with fluctuation
eloss = ElectronicLossFluctuation(particle, couple, eloss, step) ;
if(eloss < 0.0) eloss = 0.0;
finalT = kineticEnergy - eloss - nloss;
}
// stop particle if the kinetic energy <= MinKineticEnergy
if (finalT <= MinKineticEnergy ) {
finalT = 0.0;
if(!particle->GetDefinition()->GetProcessManager()->
GetAtRestProcessVector()->size())
aParticleChange.SetStatusChange(fStopAndKill);
else
aParticleChange.SetStatusChange(fStopButAlive);
}
aParticleChange.SetEnergyChange( finalT );
G4double edep = kineticEnergy-finalT;
// Deexcitation only of ionised atoms
eloss = G4std::min(edep, eloss);
G4double hMass = particle->GetMass();
G4std::vector<G4DynamicParticle*>* newpart = 0;
G4DynamicParticle* part = 0;
if(theFluo) newpart = DeexciteAtom(couple, kineticEnergy, hMass, eloss);
if(newpart != 0) {
size_t nSecondaries = newpart->size();
aParticleChange.SetNumberOfSecondaries(nSecondaries);
G4Track* newtrack = 0;
const G4StepPoint* preStep = stepData.GetPreStepPoint();
const G4StepPoint* postStep = stepData.GetPostStepPoint();
G4ThreeVector r = preStep->GetPosition();
G4ThreeVector deltaR = postStep->GetPosition();
deltaR -= r;
G4double t = preStep->GetGlobalTime();
G4double deltaT = postStep->GetGlobalTime();
deltaT -= t;
G4double time, q, e;
G4ThreeVector position;
for(size_t i=0; i<nSecondaries; i++) {
part = (*newpart)[i];
if(part) {
e = part->GetKineticEnergy();
if(e <= edep) {
edep -= e;
q = G4UniformRand();
time = deltaT*q + t;
position = deltaR*q;
position += r;
newtrack = new G4Track(part, time, position);
aParticleChange.AddSecondary(newtrack);
} else {
delete part;
}
}
}
delete newpart;
}
aParticleChange.SetLocalEnergyDeposit(edep);
return &aParticleChange ;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4double G4hLowEnergyIonisation::ProtonParametrisedDEDX(
const G4MaterialCutsCouple* couple,
G4double kineticEnergy) const
{
const G4Material* material = couple->GetMaterial();
G4Proton* theProton = G4Proton::Proton();
G4double eloss = 0.0;
// Free Electron Gas Model
if(kineticEnergy < protonLowEnergy) {
eloss = (theProtonModel->TheValue(theProton, material, protonLowEnergy))
* sqrt(kineticEnergy/protonLowEnergy) ;
// Parametrisation
} else {
eloss = theProtonModel->TheValue(theProton, material, kineticEnergy) ;
}
// Delta rays energy
eloss -= DeltaRaysEnergy(couple,kineticEnergy,proton_mass_c2) ;
if(verboseLevel > 2) {
G4cout << "p E(MeV)= " << kineticEnergy/MeV
<< " dE/dx(MeV/mm)= " << eloss*mm/MeV
<< " for " << material->GetName()
<< " model: " << theProtonModel << G4endl;
}
if(eloss < 0.0) eloss = 0.0 ;
return eloss ;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4double G4hLowEnergyIonisation::AntiProtonParametrisedDEDX(
const G4MaterialCutsCouple* couple,
G4double kineticEnergy) const
{
const G4Material* material = couple->GetMaterial();
G4AntiProton* theAntiProton = G4AntiProton::AntiProton();
G4double eloss = 0.0 ;
// Antiproton model is used
if(theAntiProtonModel->IsInCharge(theAntiProton,material)) {
if(kineticEnergy < antiProtonLowEnergy) {
eloss = theAntiProtonModel->TheValue(theAntiProton,material,antiProtonLowEnergy)
* sqrt(kineticEnergy/antiProtonLowEnergy) ;
// Parametrisation
} else {
eloss = theAntiProtonModel->TheValue(theAntiProton,material,
kineticEnergy);
}
// The proton model is used + Barkas correction
} else {
if(kineticEnergy < protonLowEnergy) {
eloss = theProtonModel->TheValue(G4Proton::Proton(),material,protonLowEnergy);
// Parametrisation
} else {
eloss = theProtonModel->TheValue(G4Proton::Proton(),material,
kineticEnergy);
}
if(theBarkas) eloss -= 2.0*BarkasTerm(material, kineticEnergy);
}
// Delta rays energy
eloss -= DeltaRaysEnergy(couple,kineticEnergy,proton_mass_c2) ;
if(verboseLevel > 2) {
G4cout << "pbar E(MeV)= " << kineticEnergy/MeV
<< " dE/dx(MeV/mm)= " << eloss*mm/MeV
<< " for " << material->GetName()
<< " model: " << theProtonModel << G4endl;
}
if(eloss < 0.0) eloss = 0.0 ;
return eloss ;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4double G4hLowEnergyIonisation::DeltaRaysEnergy(
const G4MaterialCutsCouple* couple,
G4double kineticEnergy,
G4double particleMass) const
{
G4double dloss = 0.0 ;
G4double deltaCutNow = cutForDelta[(couple->GetIndex())] ;
const G4Material* material = couple->GetMaterial();
G4double electronDensity = material->GetElectronDensity();
G4double eexc = material->GetIonisation()->GetMeanExcitationEnergy();
G4double tau = kineticEnergy/particleMass ;
G4double rateMass = electron_mass_c2/particleMass ;
// some local variables
G4double gamma,bg2,beta2,tmax,x ;
gamma = tau + 1.0 ;
bg2 = tau*(tau+2.0) ;
beta2 = bg2/(gamma*gamma) ;
tmax = 2.*electron_mass_c2*bg2/(1.0+2.0*gamma*rateMass+rateMass*rateMass) ;
// Validity range for delta electron cross section
G4double deltaCut = G4std::max(deltaCutNow, eexc);
if ( deltaCut < tmax) {
x = deltaCut / tmax ;
dloss = ( beta2 * (x - 1.0) - log(x) ) * twopi_mc2_rcl2
* electronDensity / beta2 ;
}
return dloss ;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4VParticleChange* G4hLowEnergyIonisation::PostStepDoIt(
const G4Track& trackData,
const G4Step& stepData)
{
// Units are expressed in GEANT4 internal units.
G4double KineticEnergy,TotalEnergy,TotalMomentum,betasquare,
DeltaKineticEnergy,DeltaTotalMomentum,costheta,sintheta,phi,
dirx,diry,dirz,finalKineticEnergy,finalPx,finalPy,finalPz,
x,xc,grej,Psquare,Esquare,rate,finalMomentum ;
aParticleChange.Initialize(trackData) ;
const G4MaterialCutsCouple* couple = trackData.GetMaterialCutsCouple();
const G4DynamicParticle* aParticle = trackData.GetDynamicParticle() ;
// some kinematics
ParticleMass=aParticle->GetDefinition()->GetPDGMass();
KineticEnergy=aParticle->GetKineticEnergy();
TotalEnergy=KineticEnergy + ParticleMass ;
Psquare=KineticEnergy*(TotalEnergy+ParticleMass) ;
Esquare=TotalEnergy*TotalEnergy;
betasquare=Psquare/Esquare;
G4ThreeVector ParticleDirection = aParticle->GetMomentumDirection() ;
G4double gamma= KineticEnergy/ParticleMass + 1.;
G4double r = electron_mass_c2/ParticleMass;
G4double tmax = 2.*electron_mass_c2*(gamma*gamma - 1.)/(1. + 2.*gamma*r + r*r);
// Validity range for delta electron cross section
G4double DeltaCut = cutForDelta[couple->GetIndex()];
// This should not be a case
if(DeltaCut >= tmax)
return G4VContinuousDiscreteProcess::PostStepDoIt(trackData,stepData);
xc = DeltaCut / tmax;
rate = tmax / TotalEnergy;
rate = rate*rate ;
G4double spin = aParticle->GetDefinition()->GetPDGSpin() ;
// sampling follows ...
do {
x=xc/(1.-(1.-xc)*G4UniformRand());
if(0.0 == spin) {
grej = 1.0 - betasquare * x ;
} else if (0.5 == spin) {
grej = (1.0 - betasquare * x + 0.5*x*x*rate) / (1.0 + 0.5 * rate) ;
} else {
grej = (1.0 - betasquare * x ) * (1.0 + x/ (3.0*xc)) +
x * x * rate * (1.0 + 0.5 * x / xc) / 3.0 /
(1.0 + 1.0/(3.0*xc) + rate *(1.0+ 0.5/xc) /3.0) ;
}
} while( G4UniformRand() > grej );
DeltaKineticEnergy = x * tmax;
DeltaTotalMomentum = sqrt(DeltaKineticEnergy * (DeltaKineticEnergy +
2. * electron_mass_c2 )) ;
TotalMomentum = sqrt(Psquare) ;
costheta = DeltaKineticEnergy * (TotalEnergy + electron_mass_c2)
/(DeltaTotalMomentum * TotalMomentum) ;
// protection against costheta > 1 or < -1 ---------------
if ( costheta < -1. )
costheta = -1. ;
if ( costheta > +1. )
costheta = +1. ;
// direction of the delta electron ........
phi = twopi * G4UniformRand() ;
sintheta = sqrt(1. - costheta*costheta);
dirx = sintheta * cos(phi) ;
diry = sintheta * sin(phi) ;
dirz = costheta ;
G4ThreeVector DeltaDirection(dirx,diry,dirz) ;
DeltaDirection.rotateUz(ParticleDirection) ;
// create G4DynamicParticle object for delta ray
G4DynamicParticle *theDeltaRay = new G4DynamicParticle;
theDeltaRay->SetKineticEnergy( DeltaKineticEnergy );
theDeltaRay->SetMomentumDirection(DeltaDirection.x(),
DeltaDirection.y(),
DeltaDirection.z());
theDeltaRay->SetDefinition(G4Electron::Electron());
// fill aParticleChange
finalKineticEnergy = KineticEnergy - DeltaKineticEnergy ;
// Generation of Fluorescence and Auger
size_t nSecondaries = 0;
size_t totalNumber = 1;
G4std::vector<G4DynamicParticle*>* secondaryVector = 0;
G4DynamicParticle* aSecondary = 0;
G4ParticleDefinition* type = 0;
// Select atom and shell
G4int Z = SelectRandomAtom(couple, KineticEnergy);
if(theFluo && Z > 5) {
G4int shell = shellCS->SelectRandomShell(Z, KineticEnergy,
ParticleMass,DeltaKineticEnergy);
const G4AtomicShell* atomicShell =
(G4AtomicTransitionManager::Instance())->Shell(Z, shell);
G4double bindingEnergy = atomicShell->BindingEnergy();
if(verboseLevel > 1) {
G4cout << "PostStep Z= " << Z << " shell= " << shell
<< " bindingE(keV)= " << bindingEnergy/keV
<< " finalE(keV)= " << finalKineticEnergy/keV
<< G4endl;
}
// Fluorescence data start from element 6
if (finalKineticEnergy >= bindingEnergy
&& (bindingEnergy >= minGammaEnergy
|| bindingEnergy >= minElectronEnergy) ) {
G4int shellId = atomicShell->ShellId();
secondaryVector = deexcitationManager.GenerateParticles(Z, shellId);
if (secondaryVector != 0) {
nSecondaries = secondaryVector->size();
for (size_t i = 0; i<nSecondaries; i++) {
aSecondary = (*secondaryVector)[i];
if (aSecondary) {
G4double e = aSecondary->GetKineticEnergy();
type = aSecondary->GetDefinition();
if (e < finalKineticEnergy &&
((type == G4Gamma::Gamma() && e > minGammaEnergy ) ||
(type == G4Electron::Electron() && e > minElectronEnergy ))) {
finalKineticEnergy -= e;
totalNumber++;
} else {
delete aSecondary;
(*secondaryVector)[i] = 0;
}
}
}
}
}
}
// Save delta-electrons
G4double edep = 0.0;
if (finalKineticEnergy > MinKineticEnergy)
{
finalPx = TotalMomentum*ParticleDirection.x()
- DeltaTotalMomentum*DeltaDirection.x();
finalPy = TotalMomentum*ParticleDirection.y()
- DeltaTotalMomentum*DeltaDirection.y();
finalPz = TotalMomentum*ParticleDirection.z()
- DeltaTotalMomentum*DeltaDirection.z();
finalMomentum =
sqrt(finalPx*finalPx+finalPy*finalPy+finalPz*finalPz) ;
finalPx /= finalMomentum ;
finalPy /= finalMomentum ;
finalPz /= finalMomentum ;
aParticleChange.SetMomentumChange( finalPx,finalPy,finalPz );
}
else
{
edep = finalKineticEnergy;
finalKineticEnergy = 0.;
aParticleChange.SetMomentumChange(ParticleDirection.x(),
ParticleDirection.y(),ParticleDirection.z());
if(!aParticle->GetDefinition()->GetProcessManager()->
GetAtRestProcessVector()->size())
aParticleChange.SetStatusChange(fStopAndKill);
else
aParticleChange.SetStatusChange(fStopButAlive);
}
aParticleChange.SetEnergyChange( finalKineticEnergy );
aParticleChange.SetLocalEnergyDeposit (edep);
aParticleChange.SetNumberOfSecondaries(totalNumber);
aParticleChange.AddSecondary(theDeltaRay);
// Save Fluorescence and Auger
if (secondaryVector) {
for (size_t l = 0; l < nSecondaries; l++) {
aSecondary = (*secondaryVector)[l];
if(aSecondary) {
aParticleChange.AddSecondary(aSecondary);
}
}
delete secondaryVector;
}
return G4VContinuousDiscreteProcess::PostStepDoIt(trackData,stepData);
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4std::vector<G4DynamicParticle*>*
G4hLowEnergyIonisation::DeexciteAtom(const G4MaterialCutsCouple* couple,
G4double incidentEnergy,
G4double hMass,
G4double eLoss)
{
if (verboseLevel > 1) {
G4cout << "DeexciteAtom: cutForPhotons(keV)= " << minGammaEnergy/keV
<< " cutForElectrons(keV)= " << minElectronEnergy/keV
<< " eLoss(MeV)= " << eLoss
<< G4endl;
}
if(eLoss < minGammaEnergy && eLoss < minElectronEnergy) return 0;
const G4Material* material = couple->GetMaterial();
G4int index = couple->GetIndex();
// G4double eexc = material->GetIonisation()->GetMeanExcitationEnergy();
G4double gamma = incidentEnergy/hMass + 1;
G4double beta2 = 1.0 - 1.0/(gamma*gamma);
G4double r = electron_mass_c2/hMass;
G4double tmax = 2.*electron_mass_c2*(gamma*gamma - 1.)/(1. + 2.*gamma*r + r*r);
G4double tcut = G4std::min(tmax,cutForDelta[index]);
const G4AtomicTransitionManager* transitionManager =
G4AtomicTransitionManager::Instance();
size_t nElements = material->GetNumberOfElements();
const G4ElementVector* theElementVector = material->GetElementVector();
G4bool stop = true;
for (size_t j=0; j<nElements; j++) {
G4int Z = (G4int)((*theElementVector)[j]->GetZ());
G4double maxE = transitionManager->Shell(Z, 0)->BindingEnergy();
if (Z > 5 && maxE < tcut && (maxE > minGammaEnergy || maxE > minElectronEnergy) ) {
stop = false;
break;
}
}
if(stop) return 0;
// create vector of tracks of secondary particles
G4std::vector<G4DynamicParticle*>* partVector =
new G4std::vector<G4DynamicParticle*>;
G4std::vector<G4DynamicParticle*>* secVector = 0;
G4DynamicParticle* aSecondary = 0;
G4ParticleDefinition* type = 0;
G4double e, tkin, grej;
G4ThreeVector position;
G4int shell, shellId;
// sample secondaries
G4double etot = 0.0;
G4std::vector<G4int> n = shellVacancy->GenerateNumberOfIonisations(couple,
incidentEnergy, eLoss);
for (size_t i=0; i<nElements; i++) {
size_t nVacancies = n[i];
G4int Z = (G4int)((*theElementVector)[i]->GetZ());
G4double maxE = transitionManager->Shell(Z, 0)->BindingEnergy();
if (nVacancies && Z > 5 && maxE < tcut && (maxE > minGammaEnergy || maxE > minElectronEnergy)) {
for(size_t j=0; j<nVacancies; j++) {
// sampling follows
do {
tkin = tcut/(1.0 + (tcut/maxE - 1.0)*G4UniformRand());
grej = 1.0 - beta2 * tkin/tmax;
} while( G4UniformRand() > grej );
shell = shellCS->SelectRandomShell(Z,incidentEnergy,hMass,tkin);
shellId = transitionManager->Shell(Z, shell)->ShellId();
G4double maxE = transitionManager->Shell(Z, shell)->BindingEnergy();
if (maxE>minGammaEnergy || maxE>minElectronEnergy ) {
secVector = deexcitationManager.GenerateParticles(Z, shellId);
} else {
secVector = 0;
}
if (secVector) {
for (size_t l = 0; l<secVector->size(); l++) {
aSecondary = (*secVector)[l];
if(aSecondary) {
e = aSecondary->GetKineticEnergy();
type = aSecondary->GetDefinition();
if ( etot + e <= eLoss &&
(type == G4Gamma::Gamma() && e > minGammaEnergy ) ||
(type == G4Electron::Electron() && e > minElectronEnergy)) {
etot += e;
partVector->push_back(aSecondary);
} else {
delete aSecondary;
}
}
}
delete secVector;
}
}
}
}
if(partVector->empty()) {
delete partVector;
return 0;
}
return partVector;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4int G4hLowEnergyIonisation::SelectRandomAtom(const G4MaterialCutsCouple* couple,
G4double kineticEnergy) const
{
const G4Material* material = couple->GetMaterial();
G4int nElements = material->GetNumberOfElements();
G4int Z = 0;
if(nElements == 1) {
Z = (G4int)(material->GetZ());
return Z;
}
const G4ElementVector* theElementVector = material->GetElementVector();
G4std::vector<G4double> p;
G4int index = couple->GetIndex();
G4double norm = 0.0;
for (G4int j=0; j<nElements; j++) {
const G4VEMDataSet* set = (zFluoDataVector[index])->GetComponent(j);
G4double cross = set->FindValue(kineticEnergy);
p.push_back(cross);
norm += cross;
}
if(norm == 0.0) return 0;
G4double q = norm*G4UniformRand();
for (G4int i=0; i<nElements; i++) {
if(p[i] > q) {
Z = (G4int)((*theElementVector)[i]->GetZ());
break;
}
q -= p[i];
}
return Z;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4double G4hLowEnergyIonisation::ComputeDEDX(
const G4ParticleDefinition* aParticle,
const G4MaterialCutsCouple* couple,
G4double kineticEnergy)
{
const G4Material* material = couple->GetMaterial();
G4Proton* theProton = G4Proton::Proton();
G4AntiProton* theAntiProton = G4AntiProton::AntiProton();
G4double dedx = 0.0 ;
G4double tscaled = kineticEnergy*proton_mass_c2/(aParticle->GetPDGMass()) ;
charge = aParticle->GetPDGCharge() ;
if(charge>0.0) {
if(tscaled > protonHighEnergy) {
dedx=G4EnergyLossTables::GetDEDX(theProton,tscaled,couple) ;
} else {
dedx=ProtonParametrisedDEDX(couple,tscaled) ;
}
} else {
if(tscaled > antiProtonHighEnergy) {
dedx=G4EnergyLossTables::GetDEDX(theAntiProton,tscaled,couple);
} else {
dedx=AntiProtonParametrisedDEDX(couple,tscaled) ;
}
}
dedx *= theIonEffChargeModel->TheValue(aParticle, material, kineticEnergy) ;
return dedx ;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4double G4hLowEnergyIonisation::BarkasTerm(const G4Material* material,
G4double kineticEnergy) const
//Function to compute the Barkas term for protons:
//
//Ref. Z_1^3 effect in the stopping power of matter for charged particles
// J.C Ashley and R.H.Ritchie
// Physical review B Vol.5 No.7 1 April 1972 pagg. 2393-2397
//
{
static double FTable[47][2] = {
{ 0.02, 21.5},
{ 0.03, 20.0},
{ 0.04, 18.0},
{ 0.05, 15.6},
{ 0.06, 15.0},
{ 0.07, 14.0},
{ 0.08, 13.5},
{ 0.09, 13.},
{ 0.1, 12.2},
{ 0.2, 9.25},
{ 0.3, 7.0},
{ 0.4, 6.0},
{ 0.5, 4.5},
{ 0.6, 3.5},
{ 0.7, 3.0},
{ 0.8, 2.5},
{ 0.9, 2.0},
{ 1.0, 1.7},
{ 1.2, 1.2},
{ 1.3, 1.0},
{ 1.4, 0.86},
{ 1.5, 0.7},
{ 1.6, 0.61},
{ 1.7, 0.52},
{ 1.8, 0.5},
{ 1.9, 0.43},
{ 2.0, 0.42},
{ 2.1, 0.3},
{ 2.4, 0.2},
{ 3.0, 0.13},
{ 3.08, 0.1},
{ 3.1, 0.09},
{ 3.3, 0.08},
{ 3.5, 0.07},
{ 3.8, 0.06},
{ 4.0, 0.051},
{ 4.1, 0.04},
{ 4.8, 0.03},
{ 5.0, 0.024},
{ 5.1, 0.02},
{ 6.0, 0.013},
{ 6.5, 0.01},
{ 7.0, 0.009},
{ 7.1, 0.008},
{ 8.0, 0.006},
{ 9.0, 0.0032},
{ 10.0, 0.0025} };
// Information on particle and material
G4double kinE = kineticEnergy ;
if(0.5*MeV > kinE) kinE = 0.5*MeV ;
G4double gamma = 1.0 + kinE / proton_mass_c2 ;
G4double beta2 = 1.0 - 1.0/(gamma*gamma) ;
if(0.0 >= beta2) return 0.0;
G4double BarkasTerm = 0.0;
G4double AMaterial = 0.0;
G4double ZMaterial = 0.0;
const G4ElementVector* theElementVector = material->GetElementVector();
G4int numberOfElements = material->GetNumberOfElements();
for (G4int i = 0; i<numberOfElements; i++) {
AMaterial = (*theElementVector)[i]->GetA()*mole/g;
ZMaterial = (*theElementVector)[i]->GetZ();
G4double X = 137.0 * 137.0 * beta2 / ZMaterial;
// Variables to compute L_1
G4double Eta0Chi = 0.8;
G4double EtaChi = Eta0Chi * ( 1.0 + 6.02*pow( ZMaterial,-1.19 ) );
G4double W = ( EtaChi * pow( ZMaterial,1.0/6.0 ) ) / sqrt(X);
G4double FunctionOfW = FTable[46][1]*FTable[46][0]/W ;
for(G4int j=0; j<47; j++) {
if( W < FTable[j][0] ) {
if(0 == j) {
FunctionOfW = FTable[0][1] ;
} else {
FunctionOfW = (FTable[j][1] - FTable[j-1][1]) * (W - FTable[j-1][0])
/ (FTable[j][0] - FTable[j-1][0])
+ FTable[j-1][1] ;
}
break;
}
}
BarkasTerm += FunctionOfW /( sqrt(ZMaterial * X) * X);
}
BarkasTerm *= twopi_mc2_rcl2 * (material->GetElectronDensity()) / beta2 ;
return BarkasTerm;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4double G4hLowEnergyIonisation::BlochTerm(const G4Material* material,
G4double kineticEnergy,
G4double cSquare) const
//Function to compute the Bloch term for protons:
//
//Ref. Z_1^3 effect in the stopping power of matter for charged particles
// J.C Ashley and R.H.Ritchie
// Physical review B Vol.5 No.7 1 April 1972 pagg. 2393-2397
//
{
G4double eloss = 0.0 ;
G4double gamma = 1.0 + kineticEnergy / proton_mass_c2 ;
G4double beta2 = 1.0 - 1.0/(gamma*gamma) ;
G4double y = cSquare / (137.0*137.0*beta2) ;
if(y < 0.05) {
eloss = 1.202 ;
} else {
eloss = 1.0 / (1.0 + y) ;
G4double de = eloss ;
for(G4int i=2; de>eloss*0.01; i++) {
de = 1.0/( i * (i*i + y)) ;
eloss += de ;
}
}
eloss *= -1.0 * y * cSquare * twopi_mc2_rcl2 *
(material->GetElectronDensity()) / beta2 ;
return eloss;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4double G4hLowEnergyIonisation::ElectronicLossFluctuation(
const G4DynamicParticle* particle,
const G4MaterialCutsCouple* couple,
G4double meanLoss,
G4double step) const
// calculate actual loss from the mean loss
// The model used to get the fluctuation is essentially the same
// as in Glandz in Geant3.
{
// data members to speed up the fluctuation calculation
// G4int imat ;
// G4double f1Fluct,f2Fluct,e1Fluct,e2Fluct,rateFluct,ipotFluct;
// G4double e1LogFluct,e2LogFluct,ipotLogFluct;
static const G4double minLoss = 1.*eV ;
static const G4double kappa = 10. ;
static const G4double theBohrBeta2 = 50.0 * keV/proton_mass_c2 ;
const G4Material* material = couple->GetMaterial();
G4int imaterial = couple->GetIndex() ;
G4double ipotFluct = material->GetIonisation()->GetMeanExcitationEnergy() ;
G4double electronDensity = material->GetElectronDensity() ;
G4double zeff = electronDensity/(material->GetTotNbOfAtomsPerVolume()) ;
// get particle data
G4double tkin = particle->GetKineticEnergy();
G4double particleMass = particle->GetMass() ;
G4double deltaCutInKineticEnergyNow = cutForDelta[imaterial];
// shortcut for very very small loss
if(meanLoss < minLoss) return meanLoss ;
// Validity range for delta electron cross section
G4double threshold = G4std::max(deltaCutInKineticEnergyNow,ipotFluct);
G4double loss, siga;
G4double rmass = electron_mass_c2/particleMass;
G4double tau = tkin/particleMass;
G4double tau1 = tau+1.0;
G4double tau2 = tau*(tau+2.);
G4double tmax = 2.*electron_mass_c2*tau2/(1.+2.*tau1*rmass+rmass*rmass);
if(tmax > threshold) tmax = threshold;
G4double beta2 = tau2/(tau1*tau1);
// Gaussian fluctuation
if(meanLoss > kappa*tmax || tmax < kappa*ipotFluct )
{
siga = tmax * (1.0-0.5*beta2) * step * twopi_mc2_rcl2
* electronDensity / beta2 ;
// High velocity or negatively charged particle
if( beta2 > 3.0*theBohrBeta2*zeff || charge < 0.0) {
siga = sqrt( siga * chargeSquare ) ;
// Low velocity - additional ion charge fluctuations according to
// Q.Yang et al., NIM B61(1991)149-155.
} else {
G4double chu = theIonChuFluctuationModel->TheValue(particle, material);
G4double yang = theIonYangFluctuationModel->TheValue(particle, material);
siga = sqrt( siga * (chargeSquare * chu + yang)) ;
}
do {
loss = G4RandGauss::shoot(meanLoss,siga);
} while (loss < 0. || loss > 2.0*meanLoss);
return loss;
}
// Non Gaussian fluctuation
static const G4double probLim = 0.01 ;
static const G4double sumaLim = -log(probLim) ;
static const G4double alim = 10.;
G4double suma,w1,w2,C,e0,lossc,w;
G4double a1,a2,a3;
G4int p1,p2,p3;
G4int nb;
G4double corrfac, na,alfa,rfac,namean,sa,alfa1,ea,sea;
G4double dp3;
G4double f1Fluct = material->GetIonisation()->GetF1fluct();
G4double f2Fluct = material->GetIonisation()->GetF2fluct();
G4double e1Fluct = material->GetIonisation()->GetEnergy1fluct();
G4double e2Fluct = material->GetIonisation()->GetEnergy2fluct();
G4double e1LogFluct = material->GetIonisation()->GetLogEnergy1fluct();
G4double e2LogFluct = material->GetIonisation()->GetLogEnergy2fluct();
G4double rateFluct = material->GetIonisation()->GetRateionexcfluct();
G4double ipotLogFluct= material->GetIonisation()->GetLogMeanExcEnergy();
w1 = tmax/ipotFluct;
w2 = log(2.*electron_mass_c2*tau2);
C = meanLoss*(1.-rateFluct)/(w2-ipotLogFluct-beta2);
a1 = C*f1Fluct*(w2-e1LogFluct-beta2)/e1Fluct;
a2 = C*f2Fluct*(w2-e2LogFluct-beta2)/e2Fluct;
a3 = rateFluct*meanLoss*(tmax-ipotFluct)/(ipotFluct*tmax*log(w1));
if(a1 < 0.0) a1 = 0.0;
if(a2 < 0.0) a2 = 0.0;
if(a3 < 0.0) a3 = 0.0;
suma = a1+a2+a3;
loss = 0.;
if(suma < sumaLim) // very small Step
{
e0 = material->GetIonisation()->GetEnergy0fluct();
if(tmax == ipotFluct)
{
a3 = meanLoss/e0;
if(a3>alim)
{
siga=sqrt(a3) ;
p3 = G4std::max(0,G4int(G4RandGauss::shoot(a3,siga)+0.5));
}
else
p3 = G4Poisson(a3);
loss = p3*e0 ;
if(p3 > 0)
loss += (1.-2.*G4UniformRand())*e0 ;
}
else
{
tmax = tmax-ipotFluct+e0 ;
a3 = meanLoss*(tmax-e0)/(tmax*e0*log(tmax/e0));
if(a3>alim)
{
siga=sqrt(a3) ;
p3 = G4std::max(0,int(G4RandGauss::shoot(a3,siga)+0.5));
}
else
p3 = G4Poisson(a3);
if(p3 > 0)
{
w = (tmax-e0)/tmax ;
if(p3 > nmaxCont2)
{
dp3 = G4float(p3) ;
corrfac = dp3/G4float(nmaxCont2) ;
p3 = nmaxCont2 ;
}
else
corrfac = 1. ;
for(G4int i=0; i<p3; i++) loss += 1./(1.-w*G4UniformRand()) ;
loss *= e0*corrfac ;
}
}
}
else // not so small Step
{
// excitation type 1
if(a1>alim)
{
siga=sqrt(a1) ;
p1 = G4std::max(0,G4int(G4RandGauss::shoot(a1,siga)+0.5));
}
else
p1 = G4Poisson(a1);
// excitation type 2
if(a2>alim)
{
siga=sqrt(a2) ;
p2 = G4std::max(0,G4int(G4RandGauss::shoot(a2,siga)+0.5));
}
else
p2 = G4Poisson(a2);
loss = p1*e1Fluct+p2*e2Fluct;
// smearing to avoid unphysical peaks
if(p2 > 0)
loss += (1.-2.*G4UniformRand())*e2Fluct;
else if (loss>0.)
loss += (1.-2.*G4UniformRand())*e1Fluct;
// ionisation .......................................
if(a3 > 0.)
{
if(a3>alim)
{
siga=sqrt(a3) ;
p3 = G4std::max(0,G4int(G4RandGauss::shoot(a3,siga)+0.5));
}
else
p3 = G4Poisson(a3);
lossc = 0.;
if(p3 > 0)
{
na = 0.;
alfa = 1.;
if (p3 > nmaxCont2)
{
dp3 = G4float(p3);
rfac = dp3/(G4float(nmaxCont2)+dp3);
namean = G4float(p3)*rfac;
sa = G4float(nmaxCont1)*rfac;
na = G4RandGauss::shoot(namean,sa);
if (na > 0.)
{
alfa = w1*G4float(nmaxCont2+p3)/
(w1*G4float(nmaxCont2)+G4float(p3));
alfa1 = alfa*log(alfa)/(alfa-1.);
ea = na*ipotFluct*alfa1;
sea = ipotFluct*sqrt(na*(alfa-alfa1*alfa1));
lossc += G4RandGauss::shoot(ea,sea);
}
}
nb = G4int(G4float(p3)-na);
if (nb > 0)
{
w2 = alfa*ipotFluct;
w = (tmax-w2)/tmax;
for (G4int k=0; k<nb; k++) lossc += w2/(1.-w*G4UniformRand());
}
}
loss += lossc;
}
}
return loss ;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4hLowEnergyIonisation::SetCutForSecondaryPhotons(G4double cut)
{
minGammaEnergy = cut;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4hLowEnergyIonisation::SetCutForAugerElectrons(G4double cut)
{
minElectronEnergy = cut;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4hLowEnergyIonisation::ActivateAugerElectronProduction(G4bool val)
{
deexcitationManager.ActivateAugerElectronProduction(val);
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4hLowEnergyIonisation::PrintInfoDefinition() const
{
G4String comments = " Knock-on electron cross sections . ";
comments += "\n Good description above the mean excitation energy.\n";
comments += " Delta ray energy sampled from differential Xsection.";
G4cout << G4endl << GetProcessName() << ": " << comments
<< "\n PhysicsTables from " << LowestKineticEnergy / eV << " eV "
<< " to " << HighestKineticEnergy / TeV << " TeV "
<< " in " << TotBin << " bins."
<< "\n Electronic stopping power model is "
<< theProtonTable
<< "\n from " << protonLowEnergy / keV << " keV "
<< " to " << protonHighEnergy / MeV << " MeV " << "." << G4endl ;
G4cout << "\n Parametrisation model for antiprotons is "
<< theAntiProtonTable
<< "\n from " << antiProtonLowEnergy / keV << " keV "
<< " to " << antiProtonHighEnergy / MeV << " MeV " << "." << G4endl ;
if(theBarkas){
G4cout << " Parametrization of the Barkas effect is switched on."
<< G4endl ;
}
if(nStopping) {
G4cout << " Nuclear stopping power model is " << theNuclearTable
<< G4endl ;
}
G4bool printHead = true;
const G4ProductionCutsTable* theCoupleTable=
G4ProductionCutsTable::GetProductionCutsTable();
size_t numOfCouples = theCoupleTable->GetTableSize();
// loop for materials
for (size_t j=0 ; j < numOfCouples; j++) {
const G4MaterialCutsCouple* couple = theCoupleTable->GetMaterialCutsCouple(j);
const G4Material* material= couple->GetMaterial();
G4double deltaCutNow = cutForDelta[(couple->GetIndex())] ;
G4double eexc = material->GetIonisation()->GetMeanExcitationEnergy();
if(eexc > deltaCutNow) {
if(printHead) {
printHead = false ;
G4cout << " material min.delta energy(keV) " << G4endl;
G4cout << G4endl;
}
G4cout << G4std::setw(20) << material->GetName()
<< G4std::setw(15) << eexc/keV << G4endl;
}
}
}