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

520 lines
18 KiB
C++

//
// ********************************************************************
// * License and Disclaimer *
// * *
// * The Geant4 software is copyright of the Copyright Holders of *
// * the Geant4 Collaboration. It is provided under the terms and *
// * conditions of the Geant4 Software License, included in the file *
// * LICENSE and available at http://cern.ch/geant4/license . These *
// * include a list of copyright holders. *
// * *
// * Neither the authors of this software system, nor their employing *
// * institutes,nor the agencies providing financial support for this *
// * work make any representation or warranty, express or implied, *
// * regarding this software system or assume any liability for its *
// * use. Please see the license in the file LICENSE and URL above *
// * for the full disclaimer and the limitation of liability. *
// * *
// * This code implementation is the result of the scientific and *
// * technical work of the GEANT4 collaboration. *
// * By using, copying, modifying or distributing the software (or *
// * any work based on the software) you agree to acknowledge its *
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
//
// $Id: G4eLowEnergyLoss.cc,v 1.37 2009/07/23 09:15:37 vnivanch Exp $
// GEANT4 tag $Name: geant4-09-03 $
//
// -----------------------------------------------------------
// GEANT 4 class implementation file
//
// History: based on object model of
// 2nd December 1995, G.Cosmo
// ---------- G4eLowEnergyLoss physics process -----------
// by Laszlo Urban, 20 March 1997
// **************************************************************
// It calculates the energy loss of e+/e-.
// --------------------------------------------------------------
//
// 08-05-97: small changes by L.Urban
// 27-05-98: several bugs and inconsistencies are corrected,
// new table (the inverse of the range table) added ,
// AlongStepDoit uses now this new table. L.Urban
// 08-09-98: cleanup
// 24-09-98: rndmStepFlag false by default (no randomization of the step)
// 14-10-98: messenger file added.
// 16-10-98: public method SetStepFunction()
// 20-01-99: important correction in AlongStepDoIt , L.Urban
// 10/02/00 modifications , new e.m. structure, L.Urban
// 11/04/00: Bug fix in dE/dx fluctuation simulation, Veronique Lefebure
// 19-09-00 change of fluctuation sampling V.Ivanchenko
// 20/09/00 update fluctuations V.Ivanchenko
// 18/10/01 add fluorescence AlongStepDoIt V.Ivanchenko
// 18/10/01 Revision to improve code quality and consistency with design, MGP
// 19/10/01 update according to new design, V.Ivanchenko
// 24/10/01 MGP - Protection against negative energy loss in AlongStepDoIt
// 26/10/01 VI Clean up access to deexcitation
// 23/11/01 VI Move static member-functions from header to source
// 28/05/02 VI Remove flag fStopAndKill
// 03/06/02 MGP - Restore fStopAndKill
// 28/10/02 VI Optimal binning for dE/dx
// 21/01/03 VI cut per region
// 01/06/04 VI check if stopped particle has AtRest processes
//
// --------------------------------------------------------------
#include "G4eLowEnergyLoss.hh"
#include "G4EnergyLossMessenger.hh"
#include "G4Poisson.hh"
#include "G4ProductionCutsTable.hh"
//
// Initialisation of static data members
// -------------------------------------
// Contributing processes : ion.loss + soft brems->NbOfProcesses is initialized
// to 2 . YOU DO NOT HAVE TO CHANGE this variable for a 'normal' run.
//
// You have to change NbOfProcesses if you invent a new process contributing
// to the continuous energy loss.
// The NbOfProcesses data member can be changed using the (public static)
// functions Get/Set/Plus/MinusNbOfProcesses (see G4eLowEnergyLoss.hh)
G4int G4eLowEnergyLoss::NbOfProcesses = 2;
G4int G4eLowEnergyLoss::CounterOfElectronProcess = 0;
G4int G4eLowEnergyLoss::CounterOfPositronProcess = 0;
G4PhysicsTable** G4eLowEnergyLoss::RecorderOfElectronProcess =
new G4PhysicsTable*[10];
G4PhysicsTable** G4eLowEnergyLoss::RecorderOfPositronProcess =
new G4PhysicsTable*[10];
G4PhysicsTable* G4eLowEnergyLoss::theDEDXElectronTable = 0;
G4PhysicsTable* G4eLowEnergyLoss::theDEDXPositronTable = 0;
G4PhysicsTable* G4eLowEnergyLoss::theRangeElectronTable = 0;
G4PhysicsTable* G4eLowEnergyLoss::theRangePositronTable = 0;
G4PhysicsTable* G4eLowEnergyLoss::theInverseRangeElectronTable = 0;
G4PhysicsTable* G4eLowEnergyLoss::theInverseRangePositronTable = 0;
G4PhysicsTable* G4eLowEnergyLoss::theLabTimeElectronTable = 0;
G4PhysicsTable* G4eLowEnergyLoss::theLabTimePositronTable = 0;
G4PhysicsTable* G4eLowEnergyLoss::theProperTimeElectronTable = 0;
G4PhysicsTable* G4eLowEnergyLoss::theProperTimePositronTable = 0;
G4PhysicsTable* G4eLowEnergyLoss::theeRangeCoeffATable = 0;
G4PhysicsTable* G4eLowEnergyLoss::theeRangeCoeffBTable = 0;
G4PhysicsTable* G4eLowEnergyLoss::theeRangeCoeffCTable = 0;
G4PhysicsTable* G4eLowEnergyLoss::thepRangeCoeffATable = 0;
G4PhysicsTable* G4eLowEnergyLoss::thepRangeCoeffBTable = 0;
G4PhysicsTable* G4eLowEnergyLoss::thepRangeCoeffCTable = 0;
G4double G4eLowEnergyLoss::LowerBoundEloss = 10.*eV ;
G4double G4eLowEnergyLoss::UpperBoundEloss = 100.*GeV ;
G4int G4eLowEnergyLoss::NbinEloss = 360 ;
G4double G4eLowEnergyLoss::RTable ;
G4double G4eLowEnergyLoss::LOGRTable ;
G4EnergyLossMessenger* G4eLowEnergyLoss::eLossMessenger = 0;
//
// constructor and destructor
G4eLowEnergyLoss::G4eLowEnergyLoss(const G4String& processName)
: G4VeLowEnergyLoss (processName),
theLossTable(0),
MinKineticEnergy(1.*eV),
Charge(-1.),
lastCharge(0.),
theDEDXTable(0),
CounterOfProcess(0),
RecorderOfProcess(0),
fdEdx(0),
fRangeNow(0),
linLossLimit(0.05),
theFluo(false)
{
//create (only once) EnergyLoss messenger
if(!eLossMessenger) eLossMessenger = new G4EnergyLossMessenger();
}
//
G4eLowEnergyLoss::~G4eLowEnergyLoss()
{
if (theLossTable)
{
theLossTable->clearAndDestroy();
delete theLossTable;
}
}
void G4eLowEnergyLoss::SetNbOfProcesses(G4int nb)
{
NbOfProcesses=nb;
}
void G4eLowEnergyLoss::PlusNbOfProcesses()
{
NbOfProcesses++;
}
void G4eLowEnergyLoss::MinusNbOfProcesses()
{
NbOfProcesses--;
}
G4int G4eLowEnergyLoss::GetNbOfProcesses()
{
return NbOfProcesses;
}
void G4eLowEnergyLoss::SetLowerBoundEloss(G4double val)
{
LowerBoundEloss=val;
}
void G4eLowEnergyLoss::SetUpperBoundEloss(G4double val)
{
UpperBoundEloss=val;
}
void G4eLowEnergyLoss::SetNbinEloss(G4int nb)
{
NbinEloss=nb;
}
G4double G4eLowEnergyLoss::GetLowerBoundEloss()
{
return LowerBoundEloss;
}
G4double G4eLowEnergyLoss::GetUpperBoundEloss()
{
return UpperBoundEloss;
}
G4int G4eLowEnergyLoss::GetNbinEloss()
{
return NbinEloss;
}
//
void G4eLowEnergyLoss::BuildDEDXTable(
const G4ParticleDefinition& aParticleType)
{
ParticleMass = aParticleType.GetPDGMass();
Charge = aParticleType.GetPDGCharge()/eplus;
// calculate data members LOGRTable,RTable first
G4double lrate = std::log(UpperBoundEloss/LowerBoundEloss);
LOGRTable=lrate/NbinEloss;
RTable =std::exp(LOGRTable);
// Build energy loss table as a sum of the energy loss due to the
// different processes.
//
const G4ProductionCutsTable* theCoupleTable=
G4ProductionCutsTable::GetProductionCutsTable();
size_t numOfCouples = theCoupleTable->GetTableSize();
// create table for the total energy loss
if (&aParticleType==G4Electron::Electron())
{
RecorderOfProcess=RecorderOfElectronProcess;
CounterOfProcess=CounterOfElectronProcess;
if (CounterOfProcess == NbOfProcesses)
{
if (theDEDXElectronTable)
{
theDEDXElectronTable->clearAndDestroy();
delete theDEDXElectronTable;
}
theDEDXElectronTable = new G4PhysicsTable(numOfCouples);
theDEDXTable = theDEDXElectronTable;
}
}
if (&aParticleType==G4Positron::Positron())
{
RecorderOfProcess=RecorderOfPositronProcess;
CounterOfProcess=CounterOfPositronProcess;
if (CounterOfProcess == NbOfProcesses)
{
if (theDEDXPositronTable)
{
theDEDXPositronTable->clearAndDestroy();
delete theDEDXPositronTable;
}
theDEDXPositronTable = new G4PhysicsTable(numOfCouples);
theDEDXTable = theDEDXPositronTable;
}
}
if (CounterOfProcess == NbOfProcesses)
{
// fill the tables
// loop for materials
G4double LowEdgeEnergy , Value;
G4bool isOutRange;
G4PhysicsTable* pointer;
for (size_t J=0; J<numOfCouples; J++)
{
// create physics vector and fill it
G4PhysicsLogVector* aVector = new G4PhysicsLogVector(
LowerBoundEloss, UpperBoundEloss, NbinEloss);
// loop for the kinetic energy
for (G4int i=0; i<=NbinEloss; i++)
{
LowEdgeEnergy = aVector->GetLowEdgeEnergy(i) ;
//here comes the sum of the different tables created by the
//processes (ionisation,bremsstrahlung,etc...)
Value = 0.;
for (G4int process=0; process < NbOfProcesses; process++)
{
pointer= RecorderOfProcess[process];
Value += (*pointer)[J]->GetValue(LowEdgeEnergy,isOutRange);
}
aVector->PutValue(i,Value) ;
}
theDEDXTable->insert(aVector) ;
}
//reset counter to zero
if (&aParticleType==G4Electron::Electron()) CounterOfElectronProcess=0;
if (&aParticleType==G4Positron::Positron()) CounterOfPositronProcess=0;
ParticleMass = aParticleType.GetPDGMass();
if (&aParticleType==G4Electron::Electron())
{
// Build range table
theRangeElectronTable = BuildRangeTable(theDEDXElectronTable,
theRangeElectronTable,
LowerBoundEloss,UpperBoundEloss,NbinEloss);
// Build lab/proper time tables
theLabTimeElectronTable = BuildLabTimeTable(theDEDXElectronTable,
theLabTimeElectronTable,
LowerBoundEloss,UpperBoundEloss,NbinEloss);
theProperTimeElectronTable = BuildProperTimeTable(theDEDXElectronTable,
theProperTimeElectronTable,
LowerBoundEloss,UpperBoundEloss,NbinEloss);
// Build coeff tables for the energy loss calculation
theeRangeCoeffATable = BuildRangeCoeffATable(theRangeElectronTable,
theeRangeCoeffATable,
LowerBoundEloss,UpperBoundEloss,NbinEloss);
theeRangeCoeffBTable = BuildRangeCoeffBTable(theRangeElectronTable,
theeRangeCoeffBTable,
LowerBoundEloss,UpperBoundEloss,NbinEloss);
theeRangeCoeffCTable = BuildRangeCoeffCTable(theRangeElectronTable,
theeRangeCoeffCTable,
LowerBoundEloss,UpperBoundEloss,NbinEloss);
// invert the range table
theInverseRangeElectronTable = BuildInverseRangeTable(theRangeElectronTable,
theeRangeCoeffATable,
theeRangeCoeffBTable,
theeRangeCoeffCTable,
theInverseRangeElectronTable,
LowerBoundEloss,UpperBoundEloss,NbinEloss);
}
if (&aParticleType==G4Positron::Positron())
{
// Build range table
theRangePositronTable = BuildRangeTable(theDEDXPositronTable,
theRangePositronTable,
LowerBoundEloss,UpperBoundEloss,NbinEloss);
// Build lab/proper time tables
theLabTimePositronTable = BuildLabTimeTable(theDEDXPositronTable,
theLabTimePositronTable,
LowerBoundEloss,UpperBoundEloss,NbinEloss);
theProperTimePositronTable = BuildProperTimeTable(theDEDXPositronTable,
theProperTimePositronTable,
LowerBoundEloss,UpperBoundEloss,NbinEloss);
// Build coeff tables for the energy loss calculation
thepRangeCoeffATable = BuildRangeCoeffATable(theRangePositronTable,
thepRangeCoeffATable,
LowerBoundEloss,UpperBoundEloss,NbinEloss);
thepRangeCoeffBTable = BuildRangeCoeffBTable(theRangePositronTable,
thepRangeCoeffBTable,
LowerBoundEloss,UpperBoundEloss,NbinEloss);
thepRangeCoeffCTable = BuildRangeCoeffCTable(theRangePositronTable,
thepRangeCoeffCTable,
LowerBoundEloss,UpperBoundEloss,NbinEloss);
// invert the range table
theInverseRangePositronTable = BuildInverseRangeTable(theRangePositronTable,
thepRangeCoeffATable,
thepRangeCoeffBTable,
thepRangeCoeffCTable,
theInverseRangePositronTable,
LowerBoundEloss,UpperBoundEloss,NbinEloss);
}
if(verboseLevel > 1) {
G4cout << (*theDEDXElectronTable) << G4endl;
}
// make the energy loss and the range table available
G4EnergyLossTables::Register(&aParticleType,
(&aParticleType==G4Electron::Electron())?
theDEDXElectronTable: theDEDXPositronTable,
(&aParticleType==G4Electron::Electron())?
theRangeElectronTable: theRangePositronTable,
(&aParticleType==G4Electron::Electron())?
theInverseRangeElectronTable: theInverseRangePositronTable,
(&aParticleType==G4Electron::Electron())?
theLabTimeElectronTable: theLabTimePositronTable,
(&aParticleType==G4Electron::Electron())?
theProperTimeElectronTable: theProperTimePositronTable,
LowerBoundEloss, UpperBoundEloss, 1.,NbinEloss);
}
}
//
G4VParticleChange* G4eLowEnergyLoss::AlongStepDoIt( const G4Track& trackData,
const G4Step& stepData)
{
// compute the energy loss after a Step
static const G4double faclow = 1.5 ;
// get particle and material pointers from trackData
const G4DynamicParticle* aParticle = trackData.GetDynamicParticle();
G4double E = aParticle->GetKineticEnergy();
const G4MaterialCutsCouple* couple = trackData.GetMaterialCutsCouple();
G4double Step = stepData.GetStepLength();
aParticleChange.Initialize(trackData);
//fParticleChange.Initialize(trackData);
G4double MeanLoss, finalT;
if (E < MinKineticEnergy) finalT = 0.;
else if ( E< faclow*LowerBoundEloss)
{
if (Step >= fRangeNow) finalT = 0.;
// else finalT = E*(1.-Step/fRangeNow) ;
else finalT = E*(1.-std::sqrt(Step/fRangeNow)) ;
}
else if (E>=UpperBoundEloss) finalT = E - Step*fdEdx;
else if (Step >= fRangeNow) finalT = 0.;
else
{
if(Step/fRangeNow < linLossLimit) finalT = E-Step*fdEdx ;
else
{
if (Charge<0.) finalT = G4EnergyLossTables::GetPreciseEnergyFromRange
(G4Electron::Electron(),fRangeNow-Step,couple);
else finalT = G4EnergyLossTables::GetPreciseEnergyFromRange
(G4Positron::Positron(),fRangeNow-Step,couple);
}
}
if(finalT < MinKineticEnergy) finalT = 0. ;
MeanLoss = E-finalT ;
//now the loss with fluctuation
if ((EnlossFlucFlag) && (finalT > 0.) && (finalT < E)&&(E > LowerBoundEloss))
{
finalT = E-GetLossWithFluct(aParticle,couple,MeanLoss,Step);
if (finalT < 0.) finalT = 0.;
}
// kill the particle if the kinetic energy <= 0
if (finalT <= 0. )
{
finalT = 0.;
if(Charge > 0.0) aParticleChange.ProposeTrackStatus(fStopButAlive);
else aParticleChange.ProposeTrackStatus(fStopAndKill);
}
G4double edep = E - finalT;
aParticleChange.ProposeEnergy(finalT);
// Deexcitation of ionised atoms
std::vector<G4DynamicParticle*>* deexcitationProducts = 0;
if (theFluo) deexcitationProducts = DeexciteAtom(couple,E,edep);
size_t nSecondaries = 0;
if (deexcitationProducts != 0) nSecondaries = deexcitationProducts->size();
aParticleChange.SetNumberOfSecondaries(nSecondaries);
if (nSecondaries > 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;
G4ThreeVector position;
for (size_t i=0; i<nSecondaries; i++) {
G4DynamicParticle* part = (*deexcitationProducts)[i];
if (part != 0) {
G4double eSecondary = part->GetKineticEnergy();
edep -= eSecondary;
if (edep > 0.)
{
q = G4UniformRand();
time = deltaT*q + t;
position = deltaR*q;
position += r;
G4Track* newTrack = new G4Track(part, time, position);
aParticleChange.AddSecondary(newTrack);
}
else
{
edep += eSecondary;
delete part;
part = 0;
}
}
}
}
delete deexcitationProducts;
aParticleChange.ProposeLocalEnergyDeposit(edep);
return &aParticleChange;
}
//