Files
geant4/source/processes/electromagnetic/standard/src/G4PAIenergyLoss.cc
T
2016-06-08 15:34:16 +02:00

846 lines
21 KiB
C++

// 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.
//
// $Id: G4PAIenergyLoss.cc,v 1.2.8.1 1999/12/07 20:50:59 gunter Exp $
// GEANT4 tag $Name: geant4-01-01 $
//
// $Id:
// -----------------------------------------------------------
// GEANT 4 class implementation file
//
// For information related to this code contact:
// CERN, IT Division, ASD group
// History: based on object model of
// 2nd December 1995, G.Cosmo
// ---------- G4PAIenergyLoss physics process -----------
// by V. Grichine, 30 Nov 1997
// **************************************************************
// It is the first implementation of the NEW UNIFIED ENERGY LOSS PROCESS.
// It calculates the energy loss of charged hadrons.
// **************************************************************
//
// corrected by V. Grichine on 24/11/97
// corrected by L. Urban on 27/05/98 ( other corrections come soon!)
//
#include "G4PAIenergyLoss.hh"
#include "G4PAIonisation.hh"
#include "G4EnergyLossTables.hh"
////////////////////////////////////////////////////////////////////////////
//
// Initialisation of static members
// ( this stuff should be defined later using RW ..........)
// contributing processes : ion.loss ->NUMBEROFPROCESSES is initialized
// to 1 . YOU DO NOT HAVE TO CHANGE this variable for a 'normal' run.
// You have to change NUMBEROFPROCESSES
// if you invent a new process contributing to the cont. energy loss,
// NUMBEROFPROCESSES should be 2 in this case,
// or for debugging purposes.
// The NUMBEROFPROCESSES data member can be changed using the (public static)
// functions Get/Set/Plus/MinusNUMBEROFPROCESSES (see G4hEnergyLoss.hh)
G4int G4PAIenergyLoss::NUMBEROFPROCESSES = 1 ;
G4PhysicsTable** G4PAIenergyLoss::RecorderOfpProcess =
new G4PhysicsTable*[10] ;
G4int G4PAIenergyLoss::CounterOfpProcess = 0 ;
G4PhysicsTable* G4PAIenergyLoss::theDEDXpTable = NULL ;
G4PhysicsTable* G4PAIenergyLoss::theRangepTable = NULL ;
G4PhysicsTable* G4PAIenergyLoss::theInverseRangepTable = NULL ;
G4PhysicsTable* G4PAIenergyLoss::theLabTimepTable = NULL ;
G4PhysicsTable* G4PAIenergyLoss::theProperTimepTable = NULL ;
G4PhysicsTable* G4PAIenergyLoss::thepRangeCoeffATable = NULL ;
G4PhysicsTable* G4PAIenergyLoss::thepRangeCoeffBTable = NULL ;
G4PhysicsTable* G4PAIenergyLoss::thepRangeCoeffCTable = NULL ;
G4PhysicsTable** G4PAIenergyLoss::RecorderOfpbarProcess =
new G4PhysicsTable*[10] ;
G4int G4PAIenergyLoss::CounterOfpbarProcess = 0 ;
G4PhysicsTable* G4PAIenergyLoss::theDEDXpbarTable = NULL ;
G4PhysicsTable* G4PAIenergyLoss::theRangepbarTable = NULL ;
G4PhysicsTable* G4PAIenergyLoss::theInverseRangepbarTable = NULL ;
G4PhysicsTable* G4PAIenergyLoss::theLabTimepbarTable = NULL ;
G4PhysicsTable* G4PAIenergyLoss::theProperTimepbarTable = NULL ;
G4PhysicsTable* G4PAIenergyLoss::thepbarRangeCoeffATable = NULL ;
G4PhysicsTable* G4PAIenergyLoss::thepbarRangeCoeffBTable = NULL ;
G4PhysicsTable* G4PAIenergyLoss::thepbarRangeCoeffCTable = NULL ;
G4PhysicsTable* G4PAIenergyLoss::theDEDXTable = NULL;
// G4PhysicsTable* G4PAIenergyLoss::fPAItransferBank = NULL ;
G4double G4PAIenergyLoss::Mass,
G4PAIenergyLoss::taulow,
G4PAIenergyLoss::tauhigh,
G4PAIenergyLoss::ltaulow,
G4PAIenergyLoss::ltauhigh;
G4double G4PAIenergyLoss::CutInRange = 0;
const G4double G4PAIenergyLoss::LowestKineticEnergy= 1.00*keV ;
const G4double G4PAIenergyLoss::HighestKineticEnergy= 100.*TeV ;
G4int G4PAIenergyLoss::TotBin ;
G4double G4PAIenergyLoss::RTable,G4PAIenergyLoss::LOGRTable;
// constructor and destructor
G4PAIenergyLoss::G4PAIenergyLoss(const G4String& processName)
: G4VContinuousDiscreteProcess (processName),
dToverTini(0.20), // max.relative range loss in one Step = 20%
// LowestKineticEnergy(1.00*keV),
// HighestKineticEnergy(100.*TeV),
MaxExcitationNumber (1.e6),
probLimFluct (0.01),
nmaxDirectFluct (100),
nmaxCont1(4),
nmaxCont2(16),
theElectron ( G4Electron::Electron() ),
theProton ( G4Proton::Proton() ),
theAntiProton ( G4AntiProton::AntiProton() )
{
theLossTable = NULL ;
lastMaterial = NULL ;
// calculate data members TotBin,LOGRTable,RTable first
G4double lrate ;
G4int nbin ;
// binning corresponds to 2.*dToverTini........................
G4double binning = 2.*dToverTini ;
lrate = log(HighestKineticEnergy/LowestKineticEnergy) ;
// nbin = G4int((lrate/log(1.+dToverTini) + lrate/log(1.+2.*dToverTini))/2.);
nbin = G4int((lrate/log(1.+binning) + lrate/log(1.+2.*binning))/2.);
nbin = (nbin+25)/50 ;
TotBin = 50*nbin ;
if(TotBin<50)
TotBin = 50 ;
if(TotBin>500)
TotBin = 500 ;
LOGRTable=lrate/TotBin;
RTable =exp(LOGRTable);
}
G4PAIenergyLoss::~G4PAIenergyLoss()
{
if(theLossTable) {
theLossTable->clearAndDestroy();
delete theLossTable;
}
}
/////////////////////////////////////////////////////////////////////////
//
//
void G4PAIenergyLoss::BuildDEDXTable(const G4ParticleDefinition& aParticleType)
{
G4bool MakeTable = false ;
G4double newCutInRange = aParticleType.GetLengthCuts();
// Create tables only if there is a new cut value !
// create/fill proton or antiproton tables depending on the charge of the particle
G4double Charge = aParticleType.GetPDGCharge();
if (Charge>0.)
{
theDEDXTable= theDEDXpTable;
}
else
{
theDEDXTable= theDEDXpbarTable;
}
if ((CutInRange != newCutInRange) || (theDEDXTable==NULL))
{
MakeTable = true ;
CutInRange = newCutInRange ;
}
if( MakeTable )
{
// Build energy loss table as a sum of the energy loss due to the
// different processes.
//
// different processes.
const G4MaterialTable* theMaterialTable=
G4Material::GetMaterialTable();
// create table for the total energy loss
G4int numOfMaterials = theMaterialTable->length();
G4PhysicsTable** RecorderOfProcess;
int CounterOfProcess;
if( Charge >0.)
{
RecorderOfProcess=RecorderOfpProcess;
CounterOfProcess=CounterOfpProcess;
if(CounterOfProcess == NUMBEROFPROCESSES)
{
// create tables
if(theDEDXpTable)
{ theDEDXpTable->clearAndDestroy();
delete theDEDXpTable; }
theDEDXpTable = new G4PhysicsTable(numOfMaterials);
theDEDXTable = theDEDXpTable;
}
}
else
{
RecorderOfProcess=RecorderOfpbarProcess;
CounterOfProcess=CounterOfpbarProcess;
if(CounterOfProcess == NUMBEROFPROCESSES)
{
// create tables
if(theDEDXpbarTable)
{ theDEDXpbarTable->clearAndDestroy();
delete theDEDXpbarTable; }
theDEDXpbarTable = new G4PhysicsTable(numOfMaterials);
theDEDXTable = theDEDXpbarTable;
}
}
if(CounterOfProcess == NUMBEROFPROCESSES)
{
// fill the tables
// loop for materials
G4double LowEdgeEnergy , Value ;
G4bool isOutRange ;
G4PhysicsTable* pointer ;
for (G4int J=0; J<numOfMaterials; J++)
{
// create physics vector and fill it
G4PhysicsLogVector* aVector = new G4PhysicsLogVector(
LowestKineticEnergy, HighestKineticEnergy, TotBin);
// loop for the kinetic energy
for (G4int i=0; i<TotBin; i++)
{
LowEdgeEnergy = aVector->GetLowEdgeEnergy(i) ;
// here comes the sum of the different tables created by the
// processes (ionisation,etc...)
Value = 0. ;
for (G4int process=0; process < NUMBEROFPROCESSES; process++)
{
pointer= RecorderOfProcess[process];
Value += (*pointer)[J]->
GetValue(LowEdgeEnergy,isOutRange) ;
}
aVector->PutValue(i,Value) ;
}
theDEDXTable->insert(aVector) ;
}
// reset counter to zero
if( Charge >0.) CounterOfpProcess=0 ;
else CounterOfpbarProcess=0 ;
// Build range table
BuildRangeTable( aParticleType);
// Build coeff tables for the energy loss calculation
BuildRangeCoeffATable( aParticleType);
BuildRangeCoeffBTable( aParticleType);
BuildRangeCoeffCTable( aParticleType);
}
}
// make the energy loss and the range table available
const G4double lowestKineticEnergy(1.00*keV);
const G4double highestKineticEnergy(100.*TeV);
G4EnergyLossTables::Register(&aParticleType,
(Charge>0)?
theDEDXpTable: theDEDXpbarTable,
(Charge>0)?
theRangepTable: theRangepbarTable,
(Charge>0)?
theInverseRangepTable: theInverseRangepbarTable,
(Charge>0)?
theLabTimepTable: theLabTimepbarTable,
(Charge>0)?
theProperTimepTable: theProperTimepbarTable,
lowestKineticEnergy, highestKineticEnergy,
proton_mass_c2/aParticleType.GetPDGMass(),TotBin);
}
/////////////////////////////////////////////////////////////////////////
//
// Build range table from the energy loss table
void G4PAIenergyLoss::BuildRangeTable( const G4ParticleDefinition& aParticleType)
{
G4double Charge = aParticleType.GetPDGCharge() ;
Mass = proton_mass_c2;
// create table
const G4MaterialTable* theMaterialTable=
G4Material::GetMaterialTable();
G4int numOfMaterials = theMaterialTable->length();
G4PhysicsTable* theRangeTable;
if( Charge >0.)
{
if(theRangepTable)
{ theRangepTable->clearAndDestroy();
delete theRangepTable; }
theRangepTable = new G4PhysicsTable(numOfMaterials);
theRangeTable = theRangepTable ;
}
else
{
if(theRangepbarTable)
{ theRangepbarTable->clearAndDestroy();
delete theRangepbarTable; }
theRangepbarTable = new G4PhysicsTable(numOfMaterials);
theRangeTable = theRangepbarTable ;
}
// loop for materials
for (G4int J=0; J<numOfMaterials; J++)
{
// create vector
G4PhysicsLogVector* aVector;
aVector = new G4PhysicsLogVector(LowestKineticEnergy,
HighestKineticEnergy,TotBin);
// fill the vector ( ranges for the actual material)
BuildRangeVector(J, aVector);
// insert vector to the table
theRangeTable->insert(aVector);
}
}
///////////////////////////////////////////////////////////////////
//
// create range vector for a material
//
void G4PAIenergyLoss::BuildRangeVector(G4int materialIndex,
G4PhysicsLogVector* rangeVector)
{
static G4int nbin;
const G4double BigRange = DBL_MAX ;
G4int maxbint=100;
G4bool isOut;
G4double tlim=2.*MeV,t1=0.1*MeV,t2=0.025*MeV ;
G4double loss1,loss2,ca,cb,cba ;
G4double taulim,rangelim,ltaulim,ltaumax,
LowEdgeEnergy,tau,Value,tau1,sqtau1 ;
G4PhysicsVector* physicsVector= (*theDEDXTable)[materialIndex];
const G4MaterialTable* theMaterialTable =
G4Material::GetMaterialTable() ;
// low energy part first...
loss1 = physicsVector->GetValue(t1,isOut);
loss2 = physicsVector->GetValue(t2,isOut);
tau1 = t1/Mass ;
sqtau1 = sqrt(tau1) ;
ca = (4.*loss2-loss1)/sqtau1 ;
cb = (2.*loss1-4.*loss2)/tau1 ;
cba = cb/ca ;
taulim = tlim/Mass ;
ltaulim = log(taulim) ;
ltaumax = log(HighestKineticEnergy/Mass) ;
// loop for kinetic energy
for (G4int i=0; i<TotBin; i++)
{
LowEdgeEnergy = rangeVector->GetLowEdgeEnergy(i);
tau = LowEdgeEnergy/Mass;
if ( tau <= tau1 )
{
Value = 2.*Mass*log(1.+cba*sqrt(tau))/cb ;
}
else
{
Value = 2.*Mass*log(1.+cba*sqtau1)/cb ;
if(tau<=taulim)
{
nbin = (G4int)(maxbint*(tau-tau1)/(taulim-tau1)) ;
if(nbin<1) nbin = 1;
taulow = tau1 ;
tauhigh = tau ;
Value += RangeIntLin(physicsVector,nbin);
}
else
{
taulow = tau1 ;
tauhigh = taulim ;
Value += RangeIntLin(physicsVector,maxbint) ;
ltaulow = ltaulim ;
ltauhigh = log(tau) ;
nbin = (G4int)(maxbint*(ltauhigh-ltaulow)/(ltaumax-ltaulow)) ;
if(nbin<1) nbin= 1 ;
Value += RangeIntLog(physicsVector,nbin);
}
}
rangeVector->PutValue(i,Value);
}
}
///////////////////////////////////////////////////////////////////
//
// num. integration, linear binning
//
G4double G4PAIenergyLoss::RangeIntLin(G4PhysicsVector* physicsVector,
G4int nbin)
{
G4double dtau,Value,taui,ti,lossi,ci;
G4bool isOut;
dtau = (tauhigh-taulow)/nbin;
Value = 0.;
for (G4int i=0; i<=nbin; i++)
{
taui = taulow + dtau*i ;
ti = Mass*taui;
lossi = physicsVector->GetValue(ti,isOut);
if(i==0)
ci=0.5;
else
{
if(i<nbin)
ci=1.;
else
ci=0.5;
}
Value += ci/lossi;
}
Value *= Mass*dtau;
return Value;
}
//////////////////////////////////////////////////////////////////
//
// num. integration, logarithmic binning
//
G4double G4PAIenergyLoss::RangeIntLog(G4PhysicsVector* physicsVector,
G4int nbin)
{
G4double ltt,dltau,Value,ui,taui,ti,lossi,ci;
G4bool isOut;
ltt = ltauhigh-ltaulow;
dltau = ltt/nbin;
Value = 0.;
for (G4int i=0; i<=nbin; i++)
{
ui = ltaulow+dltau*i;
taui = exp(ui);
ti = Mass*taui;
lossi = physicsVector->GetValue(ti,isOut);
if(i==0)
ci=0.5;
else
{
if(i<nbin)
ci=1.;
else
ci=0.5;
}
Value += ci*taui/lossi;
}
Value *= Mass*dltau;
return Value;
}
//////////////////////////////////////////////////////////////////////
//
// returns the range of a particle in a given material
//
G4double G4PAIenergyLoss::OldGetRange(const G4DynamicParticle *aParticle,
G4Material *aMaterial)
{
G4int materialIndex;
G4double KineticEnergy,Range;
G4double BigRange = DBL_MAX;
G4bool isOut;
G4double Charge = aParticle->GetDefinition()->GetPDGCharge() ;
G4double Chargesquare = Charge*Charge ;
G4double MassRatio = proton_mass_c2/aParticle->GetDefinition()->GetPDGMass() ;
G4PhysicsTable* theRangeTable;
if(Charge>0.) theRangeTable=theRangepTable ;
else theRangeTable=theRangepbarTable ;
materialIndex = aMaterial->GetIndex();
KineticEnergy = aParticle->GetKineticEnergy()*MassRatio;
if(KineticEnergy<LowestKineticEnergy)
Range = BigRange ;
else
{
if(KineticEnergy>HighestKineticEnergy) Range = BigRange ;
else Range = (*theRangeTable)[materialIndex]->GetValue(KineticEnergy,isOut) ;
}
return Range/Chargesquare ;
}
///////////////////////////////////////////////////////////////////////
//
// Build tables of coefficients for the energy loss calculation
//
void G4PAIenergyLoss::
BuildRangeCoeffATable(const G4ParticleDefinition& aParticleType)
{
const G4MaterialTable* theMaterialTable = G4Material::GetMaterialTable() ;
// create table for coefficients "A"
G4int numOfMaterials = theMaterialTable->length();
G4double Charge = aParticleType.GetPDGCharge() ;
G4PhysicsTable* theRangeTable;
G4PhysicsTable* theRangeCoeffATable;
if(Charge>0.)
{
if(thepRangeCoeffATable)
{
thepRangeCoeffATable->clearAndDestroy() ;
delete thepRangeCoeffATable ;
}
thepRangeCoeffATable = new G4PhysicsTable(numOfMaterials);
theRangeCoeffATable = thepRangeCoeffATable ;
theRangeTable = theRangepTable ;
}
else
{
if(thepbarRangeCoeffATable)
{
thepbarRangeCoeffATable->clearAndDestroy() ;
delete thepbarRangeCoeffATable ;
}
thepbarRangeCoeffATable = new G4PhysicsTable(numOfMaterials);
theRangeCoeffATable = thepbarRangeCoeffATable ;
theRangeTable = theRangepbarTable ;
}
G4double R2 = RTable*RTable ;
G4double R1 = RTable+1.;
G4double w = R1*(RTable-1.)*(RTable-1.);
G4double w1 = RTable/w , w2 = -RTable*R1/w , w3 = R2/w ;
G4double Ti , Tim , Tip , Ri , Rim , Rip , Value ;
G4bool isOut;
for (G4int J=0; J<numOfMaterials; J++) // loop for materials
{
// create vector
G4int binmax=TotBin ;
G4PhysicsLinearVector* aVector = new G4PhysicsLinearVector(0.,binmax, TotBin);
// loop for kinetic energy
Ti = LowestKineticEnergy ;
G4PhysicsVector* rangeVector= (*theRangeTable)[J];
for ( G4int i=0; i<TotBin; i++)
{
Ri = rangeVector->GetValue(Ti,isOut) ;
if ( i==0 ) Rim = 0. ;
else
{
Tim = Ti/RTable ;
Rim = rangeVector->GetValue(Tim,isOut);
}
if ( i==(TotBin-1)) Rip = Ri ;
else
{
Tip = Ti*RTable ;
Rip = rangeVector->GetValue(Tip,isOut);
}
Value = (w1*Rip + w2*Ri + w3*Rim)/(Ti*Ti) ;
aVector->PutValue(i,Value);
Ti = RTable*Ti ;
}
theRangeCoeffATable->insert(aVector);
}
}
////////////////////////////////////////////////////////////////////////
//
// Build tables of coefficients for the energy loss calculation
//
void G4PAIenergyLoss::
BuildRangeCoeffBTable(const G4ParticleDefinition& aParticleType)
{
const G4MaterialTable* theMaterialTable = G4Material::GetMaterialTable() ;
// create table for coefficients "B"
G4int numOfMaterials = theMaterialTable->length();
G4double Charge = aParticleType.GetPDGCharge() ;
G4PhysicsTable* theRangeTable;
G4PhysicsTable* theRangeCoeffBTable;
if(Charge>0.)
{
if(thepRangeCoeffBTable)
{
thepRangeCoeffBTable->clearAndDestroy();
delete thepRangeCoeffBTable ;
}
thepRangeCoeffBTable = new G4PhysicsTable(numOfMaterials);
theRangeCoeffBTable = thepRangeCoeffBTable ;
theRangeTable = theRangepTable ;
}
else
{
if(thepbarRangeCoeffBTable)
{
thepbarRangeCoeffBTable->clearAndDestroy();
delete thepbarRangeCoeffBTable;
}
thepbarRangeCoeffBTable = new G4PhysicsTable(numOfMaterials);
theRangeCoeffBTable = thepbarRangeCoeffBTable ;
theRangeTable = theRangepbarTable ;
}
G4double R2 = RTable*RTable ;
G4double R1 = RTable+1.;
G4double w = R1*(RTable-1.)*(RTable-1.);
G4double w1 = -R1/w , w2 = R1*(R2+1.)/w , w3 = -R2*R1/w ;
G4double Ti , Tim , Tip , Ri , Rim , Rip , Value ;
G4bool isOut;
// loop for materials
for (G4int J=0; J<numOfMaterials; J++)
{
// create vector
G4int binmax=TotBin ;
G4PhysicsLinearVector* aVector = new G4PhysicsLinearVector(0.,binmax, TotBin);
// loop for kinetic energy
Ti = LowestKineticEnergy ;
G4PhysicsVector* rangeVector= (*theRangeTable)[J];
for ( G4int i=0; i<TotBin; i++)
{
Ri = rangeVector->GetValue(Ti,isOut) ;
if ( i==0 ) Rim = 0. ;
else
{
Tim = Ti/RTable ;
Rim = rangeVector->GetValue(Tim,isOut);
}
if ( i==(TotBin-1)) Rip = Ri ;
else
{
Tip = Ti*RTable ;
Rip = rangeVector->GetValue(Tip,isOut);
}
Value = (w1*Rip + w2*Ri + w3*Rim)/Ti;
aVector->PutValue(i,Value);
Ti = RTable*Ti ;
}
theRangeCoeffBTable->insert(aVector) ;
}
}
///////////////////////////////////////////////////////////////////////////
//
// Build tables of coefficients for the energy loss calculation
//
void G4PAIenergyLoss::BuildRangeCoeffCTable(
const G4ParticleDefinition& aParticleType)
{
const G4MaterialTable* theMaterialTable=
G4Material::GetMaterialTable();
// create table for coefficients "C"
G4int numOfMaterials = theMaterialTable->length();
G4double Charge = aParticleType.GetPDGCharge() ;
G4PhysicsTable* theRangeTable;
G4PhysicsTable* theRangeCoeffCTable;
if(Charge>0.)
{
if(thepRangeCoeffCTable)
{ thepRangeCoeffCTable->clearAndDestroy();
delete thepRangeCoeffCTable; }
thepRangeCoeffCTable = new G4PhysicsTable(numOfMaterials);
theRangeCoeffCTable = thepRangeCoeffCTable ;
theRangeTable = theRangepTable ;
}
else
{
if(thepbarRangeCoeffCTable)
{ thepbarRangeCoeffCTable->clearAndDestroy();
delete thepbarRangeCoeffCTable; }
thepbarRangeCoeffCTable = new G4PhysicsTable(numOfMaterials);
theRangeCoeffCTable = thepbarRangeCoeffCTable ;
theRangeTable = theRangepbarTable ;
}
const G4double BigRange = DBL_MAX ;
G4double R2 = RTable*RTable ;
G4double R1 = RTable+1.;
G4double w = R1*(RTable-1.)*(RTable-1.);
G4double w1 = 1./w , w2 = -RTable*R1/w , w3 = RTable*R2/w ;
G4double Ti , Tim , Tip , Ri , Rim , Rip , Value ;
G4bool isOut;
// loop for materials
for (G4int J=0; J<numOfMaterials; J++)
{
// create vector
G4int binmax=TotBin ;
G4PhysicsLinearVector* aVector = new G4PhysicsLinearVector(0.,binmax, TotBin);
// loop for kinetic energy
Ti = LowestKineticEnergy ;
G4PhysicsVector* rangeVector= (*theRangeTable)[J];
for ( G4int i=0; i<TotBin; i++)
{
Ri = rangeVector->GetValue(Ti,isOut) ;
if ( i==0 ) Rim = 0. ;
else
{
Tim = Ti/RTable ;
Rim = rangeVector->GetValue(Tim,isOut);
}
if ( i==(TotBin-1)) Rip = Ri ;
else
{
Tip = Ti*RTable ;
Rip = rangeVector->GetValue(Tip,isOut);
}
Value = w1*Rip + w2*Ri + w3*Rim ;
aVector->PutValue(i,Value);
Ti = RTable*Ti ;
}
theRangeCoeffCTable->insert(aVector) ;
}
}
//
//
/////////////////////////////////////////////////////////////////////////