// 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: G4eLowEnergyLoss.cc,v 1.5 2000/06/22 02:38:13 pia Exp $ // GEANT4 tag $Name: geant4-02-00 $ // // ----------------------------------------------------------- // 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 // ---------- G4eLowEnergyLoss physics process ----------- // by Laszlo Urban, 20 March 1997 // ************************************************************** // It is the first implementation of the NEW UNIFIED ENERGY LOSS PROCESS. // 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 // -------------------------------------------------------------- #include "G4eLowEnergyLoss.hh" #include "G4EnergyLossMessenger.hh" #include "G4Poisson.hh" //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... // 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 = 250.*eV ; G4double G4eLowEnergyLoss::UpperBoundEloss = 100.*GeV ; G4int G4eLowEnergyLoss::NbinEloss = 1000 ; G4double G4eLowEnergyLoss::RTable ; G4double G4eLowEnergyLoss::LOGRTable ; G4EnergyLossMessenger* G4eLowEnergyLoss::eLossMessenger = 0; //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... // constructor and destructor G4eLowEnergyLoss::G4eLowEnergyLoss(const G4String& processName) : G4VeLowEnergyLoss (processName), theLossTable(0), theDEDXTable(0), Charge(-1.),lastCharge(0.), MinKineticEnergy(1.*eV), //linLossLimit(0.02) linLossLimit(0.05), RecorderOfProcess(0), fdEdx(0), fRangeNow(0), CounterOfProcess(0) { //create (only once) EnergyLoss messenger if(!eLossMessenger) eLossMessenger = new G4EnergyLossMessenger(); } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... G4eLowEnergyLoss::~G4eLowEnergyLoss() { if (theLossTable) { theLossTable->clearAndDestroy(); delete theLossTable; } } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... void G4eLowEnergyLoss::BuildDEDXTable( const G4ParticleDefinition& aParticleType) { ParticleMass = aParticleType.GetPDGMass(); Charge = aParticleType.GetPDGCharge()/eplus; // calculate data members LOGRTable,RTable first G4double lrate = log(UpperBoundEloss/LowerBoundEloss); LOGRTable=lrate/NbinEloss; RTable =exp(LOGRTable); // Build energy loss table as a sum of the energy loss due to the // different processes. // const G4MaterialTable* theMaterialTable=G4Material::GetMaterialTable(); G4int numOfMaterials = theMaterialTable->length(); // 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(numOfMaterials); theDEDXTable = theDEDXElectronTable; } } if (&aParticleType==G4Positron::Positron()) { RecorderOfProcess=RecorderOfPositronProcess; CounterOfProcess=CounterOfPositronProcess; if (CounterOfProcess == NbOfProcesses) { if (theDEDXPositronTable) { theDEDXPositronTable->clearAndDestroy(); delete theDEDXPositronTable; } theDEDXPositronTable = new G4PhysicsTable(numOfMaterials); theDEDXTable = theDEDXPositronTable; } } if (CounterOfProcess == NbOfProcesses) { // fill the tables // loop for materials G4double LowEdgeEnergy , Value; G4bool isOutRange; G4PhysicsTable* pointer; for (G4int J=0; JGetLowEdgeEnergy(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); } // 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); } } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... 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() ; // G4cout << "MGP -- Along eInit " << E/keV << " keV " << G4endl; G4Material* aMaterial = trackData.GetMaterial(); G4int index = aMaterial->GetIndex(); G4double Step = stepData.GetStepLength(); 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.-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,aMaterial); else finalT = G4EnergyLossTables::GetPreciseEnergyFromRange (G4Positron::Positron(),fRangeNow-Step,aMaterial); } } if(finalT < MinKineticEnergy) finalT = 0. ; MeanLoss = E-finalT ; // G4cout << "MGP AlongStepDoIt finalT before fluct = " << finalT/keV << " keV" << G4endl; G4double fluc = GetLossWithFluct(aParticle,aMaterial,MeanLoss); // G4cout << "LowerBoundEloss = " << LowerBoundEloss/keV = << " Fluc = " << fluc/keV << G4endl; //now the loss with fluctuation if ((EnlossFlucFlag) && (finalT > 0.) && (finalT < E)&&(E > LowerBoundEloss)) { finalT = E-GetLossWithFluct(aParticle,aMaterial,MeanLoss); if (finalT < 0.) finalT = 0.; } // kill the particle if the kinetic energy <= 0 if (finalT <= 0. ) { finalT = 0.; if (Charge < 0.) fParticleChange.SetStatusChange(fStopAndKill); else fParticleChange.SetStatusChange(fStopButAlive); } // MGP debug // G4cout << "MGP AlongStepDoIt finalT = " << finalT/keV << " keV" << G4endl; fParticleChange.SetEnergyChange(finalT); fParticleChange.SetLocalEnergyDeposit(E-finalT); return &fParticleChange; } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....