// 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: G4VIeEnergyLoss.cc,v 1.1 2000/04/25 14:33:09 maire Exp $ // GEANT4 tag $Name: geant4-02-00 $ // // $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 // ---------- G4VIeEnergyLoss 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 // 26-10-98: revision, TOF tables L.Urban // -------------------------------------------------------------- #include "G4VIeEnergyLoss.hh" #include "G4EnergyLossTables.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 G4VIeEnergyLoss.hh) G4int G4VIeEnergyLoss::NbOfProcesses = 2; G4int G4VIeEnergyLoss::CounterOfElectronProcess = 0; G4int G4VIeEnergyLoss::CounterOfPositronProcess = 0; G4PhysicsTable** G4VIeEnergyLoss::RecorderOfElectronProcess = new G4PhysicsTable*[10]; G4PhysicsTable** G4VIeEnergyLoss::RecorderOfPositronProcess = new G4PhysicsTable*[10]; G4bool G4VIeEnergyLoss::rndmStepFlag = false; G4bool G4VIeEnergyLoss::EnlossFlucFlag = true; G4double G4VIeEnergyLoss::dRoverRange = 20*perCent; G4double G4VIeEnergyLoss::finalRange = 200*micrometer; G4PhysicsTable* G4VIeEnergyLoss::theDEDXElectronTable = NULL; G4PhysicsTable* G4VIeEnergyLoss::theDEDXPositronTable = NULL; G4PhysicsTable* G4VIeEnergyLoss::theRangeElectronTable = NULL; G4PhysicsTable* G4VIeEnergyLoss::theRangePositronTable = NULL; G4PhysicsTable* G4VIeEnergyLoss::theInverseRangeElectronTable = NULL; G4PhysicsTable* G4VIeEnergyLoss::theInverseRangePositronTable = NULL; G4PhysicsTable* G4VIeEnergyLoss::theLabTimeElectronTable = NULL; G4PhysicsTable* G4VIeEnergyLoss::theLabTimePositronTable = NULL; G4PhysicsTable* G4VIeEnergyLoss::theProperTimeElectronTable = NULL; G4PhysicsTable* G4VIeEnergyLoss::theProperTimePositronTable = NULL; G4PhysicsTable* G4VIeEnergyLoss::theeRangeCoeffATable = NULL; G4PhysicsTable* G4VIeEnergyLoss::theeRangeCoeffBTable = NULL; G4PhysicsTable* G4VIeEnergyLoss::theeRangeCoeffCTable = NULL; G4PhysicsTable* G4VIeEnergyLoss::thepRangeCoeffATable = NULL; G4PhysicsTable* G4VIeEnergyLoss::thepRangeCoeffBTable = NULL; G4PhysicsTable* G4VIeEnergyLoss::thepRangeCoeffCTable = NULL; G4EnergyLossMessenger* G4VIeEnergyLoss::eLossMessenger = NULL; //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... // constructor and destructor G4VIeEnergyLoss::G4VIeEnergyLoss(const G4String& processName) : G4IVContinuousDiscreteProcess (processName), theLossTable(NULL), theRangeCoeffATable(NULL), theRangeCoeffBTable(NULL), theRangeCoeffCTable(NULL), lastMaterial(NULL), LowestKineticEnergy(1.00*keV), HighestKineticEnergy(100.*TeV), MaxExcitationNumber (1.e6), probLimFluct (0.01), nmaxDirectFluct (100), nmaxCont1(4), nmaxCont2(16) { //create (only once) EnergyLoss messenger if(!eLossMessenger) eLossMessenger = new G4EnergyLossMessenger(); } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... G4VIeEnergyLoss::~G4VIeEnergyLoss() { if (theLossTable) { theLossTable->clearAndDestroy(); delete theLossTable; } } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... void G4VIeEnergyLoss::BuildDEDXTable( const G4ParticleDefinition& aParticleType) { ParticleMass = aParticleType.GetPDGMass(); // calculate data members TotBin,LOGRTable,RTable first G4double binning = 2.*dRoverRange; //binning is 2.*dRoverRange G4double lrate = log(HighestKineticEnergy/LowestKineticEnergy); G4double nbin = G4int((lrate/log(1.+binning) + lrate/log(1.+2.*binning))/2.); nbin = (nbin+50)/100; TotBin =int(100*nbin) ; if (TotBin<100) TotBin = 100; if (TotBin>500) TotBin = 500; LOGRTable=lrate/TotBin; 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; // Build range table BuildRangeTable(aParticleType); // Build lab/proper time tables BuildTimeTables(aParticleType); // Build coeff tables for the energy loss calculation BuildRangeCoeffATable(aParticleType); BuildRangeCoeffBTable(aParticleType); BuildRangeCoeffCTable(aParticleType); // invert the range table BuildInverseRangeTable(aParticleType); // make the energy loss and the range table available const G4double lowestKineticEnergy (1.00*keV); const G4double highestKineticEnergy(100.*TeV); 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, lowestKineticEnergy, highestKineticEnergy, 1.,TotBin); } } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... void G4VIeEnergyLoss::BuildRangeTable( const G4ParticleDefinition& aParticleType) { // Build range table from the energy loss table const G4MaterialTable* theMaterialTable=G4Material::GetMaterialTable(); G4int numOfMaterials = theMaterialTable->length(); if (&aParticleType == G4Electron::Electron()) { if (theRangeElectronTable) { theRangeElectronTable->clearAndDestroy(); delete theRangeElectronTable; } theRangeElectronTable = new G4PhysicsTable(numOfMaterials); theRangeTable = theRangeElectronTable; } if (&aParticleType == G4Positron::Positron()) { if (theRangePositronTable) { theRangePositronTable->clearAndDestroy(); delete theRangePositronTable; } theRangePositronTable = new G4PhysicsTable(numOfMaterials); theRangeTable = theRangePositronTable ; } // loop for materials for (G4int J=0; Jinsert(aVector); } } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... void G4VIeEnergyLoss::BuildTimeTables( const G4ParticleDefinition& aParticleType) { // Build time tables from the energy loss table const G4MaterialTable* theMaterialTable=G4Material::GetMaterialTable(); G4int numOfMaterials = theMaterialTable->length(); if (&aParticleType == G4Electron::Electron()) { if (theLabTimeElectronTable) { theLabTimeElectronTable->clearAndDestroy(); delete theLabTimeElectronTable; } theLabTimeElectronTable = new G4PhysicsTable(numOfMaterials); theLabTimeTable = theLabTimeElectronTable; if (theProperTimeElectronTable) { theProperTimeElectronTable->clearAndDestroy(); delete theProperTimeElectronTable; } theProperTimeElectronTable = new G4PhysicsTable(numOfMaterials); theProperTimeTable = theProperTimeElectronTable ; } if (&aParticleType == G4Positron::Positron()) { if (theLabTimePositronTable) { theLabTimePositronTable->clearAndDestroy(); delete theLabTimePositronTable; } theLabTimePositronTable = new G4PhysicsTable(numOfMaterials); theLabTimeTable = theLabTimePositronTable ; if (theProperTimePositronTable) { theProperTimePositronTable->clearAndDestroy(); delete theProperTimePositronTable; } theProperTimePositronTable = new G4PhysicsTable(numOfMaterials); theProperTimeTable = theProperTimePositronTable ; } // loop for materials for (G4int J=0; Jinsert(aVector); G4PhysicsLogVector* bVector = new G4PhysicsLogVector(LowestKineticEnergy, HighestKineticEnergy,TotBin); BuildProperTimeVector(J, bVector); theProperTimeTable->insert(bVector); } } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... void G4VIeEnergyLoss::BuildRangeVector(G4int materialIndex, G4PhysicsLogVector* rangeVector) { // create range vector for a material G4int maxbint=100; G4bool isOut; G4double tlim=10.*keV,factor=2.*electron_mass_c2 ; G4PhysicsVector* physicsVector= (*theDEDXTable)(materialIndex); // low energy part first... G4double losslim = physicsVector->GetValue(tlim,isOut); G4double taulim = tlim/electron_mass_c2; G4double clim = losslim/sqrt(taulim); G4double ltaulim = log(taulim); G4double ltaumax = log(HighestKineticEnergy/electron_mass_c2); G4int i=-1; G4double Value, oldValue(0.); G4double LowEdgeEnergy, rangelim; G4double tau,tauold; do { i += 1 ; LowEdgeEnergy = rangeVector->GetLowEdgeEnergy(i); tau = LowEdgeEnergy/electron_mass_c2; if (tau <= taulim) Value = factor*sqrt(tau)/clim; else { rangelim = factor*taulim/losslim ; ltaulow = log(taulim); ltauhigh = log(tau); Value = rangelim+RangeIntLog(physicsVector,maxbint); } rangeVector->PutValue(i,Value); oldValue = Value; tauold = tau; } while (tau<=taulim); i += 1; for (G4int j=i; jGetLowEdgeEnergy(j); tau = LowEdgeEnergy/electron_mass_c2; ltaulow = log(tauold); ltauhigh = log(tau); Value = oldValue+RangeIntLog(physicsVector,maxbint); rangeVector->PutValue(j,Value); oldValue = Value; tauold = tau; } } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... void G4VIeEnergyLoss::BuildLabTimeVector(G4int materialIndex, G4PhysicsLogVector* timeVector) // create lab time vector for a material { G4int maxbint=100; G4bool isOut; G4double tlim=5.*keV,parlowen=0.4,ppar=0.5-parlowen ; G4PhysicsVector* physicsVector= (*theDEDXTable)(materialIndex); // low energy part first... G4double losslim = physicsVector->GetValue(tlim,isOut); G4double taulim = tlim/ParticleMass ; G4double clim = sqrt(ParticleMass*tlim/2.)/(c_light*losslim*ppar); G4double ltaulim = log(taulim); G4double ltaumax = log(HighestKineticEnergy/ParticleMass) ; G4int i=-1; G4double Value, oldValue(0.); G4double LowEdgeEnergy, timelim; G4double tau,tauold; do { i += 1 ; LowEdgeEnergy = timeVector->GetLowEdgeEnergy(i); tau = LowEdgeEnergy/ParticleMass; if (tau <= taulim) Value = clim*exp(ppar*log(tau/taulim)); else { timelim = clim; ltaulow = log(taulim); ltauhigh = log(tau); Value = timelim+LabTimeIntLog(physicsVector,maxbint); } timeVector->PutValue(i,Value); oldValue = Value; tauold = tau; } while (tau<=taulim) ; i += 1 ; for (G4int j=i; jGetLowEdgeEnergy(j); tau = LowEdgeEnergy/ParticleMass; ltaulow = log(tauold); ltauhigh = log(tau); Value = oldValue+LabTimeIntLog(physicsVector,maxbint); timeVector->PutValue(j,Value); oldValue = Value ; tauold = tau ; } } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... void G4VIeEnergyLoss::BuildProperTimeVector(G4int materialIndex, G4PhysicsLogVector* timeVector) { // create lab time vector for a material G4int maxbint=100; G4bool isOut; G4double tlim=5.*keV,parlowen=0.4,ppar=0.5-parlowen ; G4PhysicsVector* physicsVector= (*theDEDXTable)(materialIndex); // low energy part first... G4double losslim = physicsVector->GetValue(tlim,isOut); G4double taulim = tlim/ParticleMass; G4double clim = sqrt(ParticleMass*tlim/2.)/(c_light*losslim*ppar); G4double ltaulim = log(taulim); G4double ltaumax = log(HighestKineticEnergy/ParticleMass); G4int i=-1; G4double Value, oldValue(0.); G4double LowEdgeEnergy, timelim; G4double tau,tauold; do { i += 1 ; LowEdgeEnergy = timeVector->GetLowEdgeEnergy(i); tau = LowEdgeEnergy/ParticleMass ; if (tau <= taulim) Value = clim*exp(ppar*log(tau/taulim)); else { timelim = clim; ltaulow = log(taulim); ltauhigh = log(tau); Value = timelim+ProperTimeIntLog(physicsVector,maxbint); } timeVector->PutValue(i,Value); oldValue = Value; tauold = tau; } while (tau<=taulim) ; i += 1 ; for (G4int j=i; jGetLowEdgeEnergy(j); tau = LowEdgeEnergy/ParticleMass; ltaulow = log(tauold); ltauhigh = log(tau); Value = oldValue+ProperTimeIntLog(physicsVector,maxbint); timeVector->PutValue(j,Value); oldValue = Value; tauold = tau; } } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... G4double G4VIeEnergyLoss::RangeIntLog(G4PhysicsVector* physicsVector, G4int nbin) // num. integration, logarithmic binning { G4double taui,lossi,ci; G4bool isOut; G4double ltt = ltauhigh-ltaulow; G4double dltau = ltt/nbin; G4double Value = 0.; for (G4int i=0; i<=nbin; i++) { taui = exp(ltaulow+dltau*i); lossi = physicsVector->GetValue(ParticleMass*taui,isOut); if ((i==0)||(i==nbin)) ci=0.5; else ci=1.; Value += ci*taui/lossi; } return Value*ParticleMass*dltau; } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... G4double G4VIeEnergyLoss::LabTimeIntLog(G4PhysicsVector* physicsVector, G4int nbin) // num. integration, logarithmic binning { G4double taui,ti,lossi,ci; G4bool isOut; G4double ltt = ltauhigh-ltaulow; G4double dltau = ltt/nbin; G4double Value = 0.; for (G4int i=0; i<=nbin; i++) { taui = exp(ltaulow+dltau*i); ti = ParticleMass*taui; lossi = physicsVector->GetValue(ti,isOut); if ((i==0)||(i==nbin)) ci=0.5; else ci=1.; Value += ci*taui*(ti+ParticleMass)/(sqrt(ti*(ti+2.*ParticleMass))*lossi); } return Value*ParticleMass*dltau/c_light; } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... G4double G4VIeEnergyLoss::ProperTimeIntLog(G4PhysicsVector* physicsVector, G4int nbin) // num. integration, logarithmic binning { G4double taui,ti,lossi,ci; G4bool isOut; G4double ltt = ltauhigh-ltaulow; G4double dltau = ltt/nbin; G4double Value = 0.; for (G4int i=0; i<=nbin; i++) { taui = exp(ltaulow+dltau*i); ti = ParticleMass*taui; lossi = physicsVector->GetValue(ti,isOut); if ((i==0)||(i==nbin)) ci=0.5; else ci=1.; Value += ci*taui*ParticleMass/(sqrt(ti*(ti+2.*ParticleMass))*lossi); } return Value*ParticleMass*dltau/c_light; } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... void G4VIeEnergyLoss::BuildRangeCoeffATable( const G4ParticleDefinition& aParticleType) { // Build tables of coefficients for the energy loss calculation // create table for coefficients "A" const G4MaterialTable* theMaterialTable = G4Material::GetMaterialTable(); G4int numOfMaterials = theMaterialTable->length(); if (&aParticleType==G4Electron::Electron()) { if (theeRangeCoeffATable) {theeRangeCoeffATable->clearAndDestroy(); delete theeRangeCoeffATable; } theeRangeCoeffATable = new G4PhysicsTable(numOfMaterials); theRangeCoeffATable = theeRangeCoeffATable ; } if (&aParticleType==G4Positron::Positron()) { if (thepRangeCoeffATable) {thepRangeCoeffATable->clearAndDestroy(); delete thepRangeCoeffATable; } thepRangeCoeffATable = new G4PhysicsTable(numOfMaterials); theRangeCoeffATable = thepRangeCoeffATable; } G4double R1 = RTable+1., R2 = RTable*RTable ; 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; // loop for materials for (G4int J=0; JGetValue(Ti,isOut); if (i==0) Rim = Ri/sqrt(RTable); else { Tim = Ti/RTable; Rim = rangeVector->GetValue(Tim,isOut);} Tip = Ti*RTable; Rip = rangeVector->GetValue(Tip,isOut); if (i < (TotBin-1)) Value = (w1*Rip + w2*Ri + w3*Rim)/(Ti*Ti); else Value = 0.; aVector->PutValue(i,Value); Ti *= RTable; } theRangeCoeffATable->insert(aVector); } } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... void G4VIeEnergyLoss::BuildRangeCoeffBTable( const G4ParticleDefinition& aParticleType) { // Build tables of coefficients for the energy loss calculation // create table for coefficients "B" const G4MaterialTable* theMaterialTable = G4Material::GetMaterialTable(); G4int numOfMaterials = theMaterialTable->length(); if (&aParticleType==G4Electron::Electron()) { if (theeRangeCoeffBTable) {theeRangeCoeffBTable->clearAndDestroy(); delete theeRangeCoeffBTable; } theeRangeCoeffBTable = new G4PhysicsTable(numOfMaterials); theRangeCoeffBTable = theeRangeCoeffBTable; } if (&aParticleType==G4Positron::Positron()) { if (thepRangeCoeffBTable) {thepRangeCoeffBTable->clearAndDestroy(); delete thepRangeCoeffBTable; } thepRangeCoeffBTable = new G4PhysicsTable(numOfMaterials); theRangeCoeffBTable = thepRangeCoeffBTable; } G4double R1 = RTable+1., R2 = RTable*RTable; 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; JGetValue(Ti,isOut); if (i==0) Rim = Ri/sqrt(RTable); else { Tim = Ti/RTable; Rim = rangeVector->GetValue(Tim,isOut);} Tip = Ti*RTable; Rip = rangeVector->GetValue(Tip,isOut); if (i < (TotBin-1)) Value = (w1*Rip + w2*Ri + w3*Rim)/Ti; else Value = RTable*(Ri-Rim)/((RTable-1.)*Ti); aVector->PutValue(i,Value); Ti *= RTable; } theRangeCoeffBTable->insert(aVector); } } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... void G4VIeEnergyLoss::BuildRangeCoeffCTable( const G4ParticleDefinition& aParticleType) { // Build tables of coefficients for the energy loss calculation // create table for coefficients "C" const G4MaterialTable* theMaterialTable = G4Material::GetMaterialTable(); G4int numOfMaterials = theMaterialTable->length(); if (&aParticleType==G4Electron::Electron()) { if (theeRangeCoeffCTable) {theeRangeCoeffCTable->clearAndDestroy(); delete theeRangeCoeffCTable; } theeRangeCoeffCTable = new G4PhysicsTable(numOfMaterials); theRangeCoeffCTable = theeRangeCoeffCTable; } if (&aParticleType==G4Positron::Positron()) { if (thepRangeCoeffCTable) {thepRangeCoeffCTable->clearAndDestroy(); delete thepRangeCoeffCTable; } thepRangeCoeffCTable = new G4PhysicsTable(numOfMaterials); theRangeCoeffCTable = thepRangeCoeffCTable ; } G4double R1 = RTable+1., R2 = RTable*RTable; 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; JGetValue(Ti,isOut); if (i==0) Rim = Ri/sqrt(RTable); else { Tim = Ti/RTable; Rim = rangeVector->GetValue(Tim,isOut);} Tip = Ti*RTable; Rip = rangeVector->GetValue(Tip,isOut); if (i < (TotBin-1)) Value = w1*Rip + w2*Ri + w3*Rim; else Value = (-Ri+RTable*Rim)/(RTable-1.); aVector->PutValue(i,Value); Ti *= RTable; } theRangeCoeffCTable->insert(aVector); } } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... void G4VIeEnergyLoss::BuildInverseRangeTable( const G4ParticleDefinition& aParticleType) { // Build inverse table of the range table G4double SmallestRange,BiggestRange; G4bool isOut; // create table const G4MaterialTable* theMaterialTable = G4Material::GetMaterialTable(); G4int numOfMaterials = theMaterialTable->length(); if (&aParticleType == G4Electron::Electron()) { if (theInverseRangeElectronTable) { theInverseRangeElectronTable->clearAndDestroy(); delete theInverseRangeElectronTable; } theInverseRangeElectronTable = new G4PhysicsTable(numOfMaterials); theInverseRangeTable = theInverseRangeElectronTable; theRangeTable = theRangeElectronTable; theDEDXTable = theDEDXElectronTable; theRangeCoeffATable = theeRangeCoeffATable; theRangeCoeffBTable = theeRangeCoeffBTable; theRangeCoeffCTable = theeRangeCoeffCTable; } if (&aParticleType == G4Positron::Positron()) { if (theInverseRangePositronTable) { theInverseRangePositronTable->clearAndDestroy(); delete theInverseRangePositronTable; } theInverseRangePositronTable = new G4PhysicsTable(numOfMaterials); theInverseRangeTable = theInverseRangePositronTable; theRangeTable = theRangePositronTable; theDEDXTable = theDEDXPositronTable; theRangeCoeffATable = thepRangeCoeffATable; theRangeCoeffBTable = thepRangeCoeffBTable; theRangeCoeffCTable = thepRangeCoeffCTable; } // loop for materials for (G4int J=0; JGetValue(LowestKineticEnergy ,isOut); BiggestRange = (*theRangeTable)(J)->GetValue(HighestKineticEnergy,isOut); G4PhysicsLogVector* aVector = new G4PhysicsLogVector(SmallestRange, BiggestRange,TotBin); InvertRangeVector(J, aVector); theInverseRangeTable->insert(aVector); } } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... void G4VIeEnergyLoss::InvertRangeVector(G4int materialIndex, G4PhysicsLogVector* aVector) { // invert range vector for a material G4double LowEdgeRange,A,B,C,discr,KineticEnergy; G4double Tbin = LowestKineticEnergy/RTable; G4double rangebin = 0.0; G4int binnumber = -1; G4bool isOut; //loop for range values for (G4int i=0; iGetLowEdgeEnergy(i); while ((rangebin < LowEdgeRange) && (binnumber < TotBin)) { binnumber += 1; Tbin *= RTable; rangebin = (*theRangeTable)(materialIndex)->GetValue(Tbin,isOut); } if (binnumber == 0) KineticEnergy = LowestKineticEnergy; else if (binnumber == TotBin-1) KineticEnergy = HighestKineticEnergy; else { A = (*(*theRangeCoeffATable)(materialIndex))(binnumber-1); B = (*(*theRangeCoeffBTable)(materialIndex))(binnumber-1); C = (*(*theRangeCoeffCTable)(materialIndex))(binnumber-1); if(A==0.) KineticEnergy = (LowEdgeRange -C )/B ; else { discr = B*B - 4.*A*(C-LowEdgeRange); discr = discr>0. ? sqrt(discr) : 0.; KineticEnergy = 0.5*(discr-B)/A ; } } aVector->PutValue(i,KineticEnergy) ; } } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... G4double G4VIeEnergyLoss::GetConstraints(const G4DynamicParticle* aParticle, G4Material* aMaterial) { // returns the Step limit = range here! // it calculates dEdx and the range as well.... G4double CutInRange,StepLimit; G4bool isOutRange; if (aParticle->GetDefinition()->GetPDGCharge() < 0.) { CutInRange = G4Electron::Electron()->GetCuts(); theDEDXTable = theDEDXElectronTable; theRangeTable = theRangeElectronTable; theRangeCoeffATable = theeRangeCoeffATable; theRangeCoeffBTable = theeRangeCoeffBTable; theRangeCoeffCTable = theeRangeCoeffCTable; } else { CutInRange = G4Positron::Positron()->GetCuts(); theDEDXTable = theDEDXPositronTable; theRangeTable = theRangePositronTable; theRangeCoeffATable = thepRangeCoeffATable; theRangeCoeffBTable = thepRangeCoeffBTable; theRangeCoeffCTable = thepRangeCoeffCTable; } G4double Thigh = HighestKineticEnergy/RTable; G4double KineticEnergy = aParticle->GetKineticEnergy(); EnergyBinNumber = G4int(log(KineticEnergy/LowestKineticEnergy)/LOGRTable); G4int index = aMaterial->GetIndex(); if (KineticEnergy < LowestKineticEnergy) { // extrapolation for very low energy fdEdx = sqrt(KineticEnergy/LowestKineticEnergy)* (*theDEDXTable)(index)->GetValue(LowestKineticEnergy,isOutRange); fRangeNow = sqrt(KineticEnergy/LowestKineticEnergy)* (*theRangeTable)(index)->GetValue(LowestKineticEnergy,isOutRange); StepLimit = fRangeNow; } else if ( KineticEnergy > Thigh) { // extrapolation for very high energy fdEdx = (*theDEDXTable)(index)->GetValue(Thigh,isOutRange); fRangeNow = (*theRangeTable)(index)->GetValue(Thigh,isOutRange); if (fdEdx > 0.) fRangeNow += (KineticEnergy-Thigh)/fdEdx; StepLimit = fRangeNow; } else { // LowestKineticEnergy <= KineticEnergy <= HighestKineticEnergy fdEdx = (*theDEDXTable)(index)->GetValue(KineticEnergy,isOutRange); G4double RgCoefA = (*(*theRangeCoeffATable)(index))(EnergyBinNumber); G4double RgCoefB = (*(*theRangeCoeffBTable)(index))(EnergyBinNumber); G4double RgCoefC = (*(*theRangeCoeffCTable)(index))(EnergyBinNumber); fRangeNow = (RgCoefA*KineticEnergy+RgCoefB)*KineticEnergy+RgCoefC; StepLimit = fRangeNow; } return StepLimit; } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... G4VParticleChange* G4VIeEnergyLoss::AlongStepDoIt( const G4Track& trackData, const G4Step& stepData) { // compute the energy loss after a Step // get particle and material pointers from trackData const G4DynamicParticle* aParticle = trackData.GetDynamicParticle(); G4double E = aParticle->GetKineticEnergy() ; G4double charge = aParticle->GetDefinition()->GetPDGCharge(); G4Material* aMaterial = trackData.GetMaterial(); G4int index = aMaterial->GetIndex(); G4double Step = stepData.GetStepLength(); aParticleChange.Initialize(trackData); // do not track further if kin.energy < 1. eV const G4double MinKineticEnergy = 1.*eV; G4double MeanLoss, finalT; if (E < MinKineticEnergy) { finalT = 0.; MeanLoss = E;} else if (EnergyBinNumber <= 0) { if (Step >= fRangeNow) { finalT = 0.; MeanLoss = E;} else { finalT = E*(1.-Step/fRangeNow)*(1.-Step/fRangeNow); if (finalT < MinKineticEnergy) finalT = 0.; MeanLoss = E - finalT; } } else if (EnergyBinNumber >= (TotBin-1)) { // simple solution for the moment: loss = Step*dE/dx (dE/dx const) MeanLoss = Step*fdEdx; if (MeanLoss > E) MeanLoss = E; finalT = E - MeanLoss; if (finalT < MinKineticEnergy) { finalT = 0.; MeanLoss = E;} } else if (Step >= fRangeNow) { finalT = 0.; MeanLoss = E;} 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; if (MeanLoss < 0.) { MeanLoss = 0.; finalT = E;} //now the loss with fluctuation if ((EnlossFlucFlag) && (finalT > 0.) && (finalT < E)&&(E > LowestKineticEnergy)) { finalT = E-GetLossWithFluct(aParticle,aMaterial,MeanLoss); if (finalT < 0.) finalT = E-MeanLoss; } } // kill the particle if the kinetic energy <= 0 if (finalT <= 0. ) { finalT = 0.; if (charge < 0.) aParticleChange.SetStatusChange(fStopAndKill); else aParticleChange.SetStatusChange(fStopButAlive); } aParticleChange.SetNumberOfSecondaries(0); aParticleChange.SetEnergyChange(finalT); aParticleChange.SetLocalEnergyDeposit(E-finalT); return &aParticleChange; } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... G4double G4VIeEnergyLoss::GetLossWithFluct(const G4DynamicParticle* aParticle, G4Material* aMaterial, G4double MeanLoss) // calculate actual loss from the mean loss // The model used to get the fluctuation is the same as in Glandz in Geant3. { static const G4double Tlow=10.*keV ; // check if the material has changed ( cache mechanism) if (aMaterial != lastMaterial) { lastMaterial = aMaterial; imat = aMaterial->GetIndex(); f1Fluct = aMaterial->GetIonisation()->GetF1fluct(); f2Fluct = aMaterial->GetIonisation()->GetF2fluct(); e1Fluct = aMaterial->GetIonisation()->GetEnergy1fluct(); e2Fluct = aMaterial->GetIonisation()->GetEnergy2fluct(); e1LogFluct = aMaterial->GetIonisation()->GetLogEnergy1fluct(); e2LogFluct = aMaterial->GetIonisation()->GetLogEnergy2fluct(); rateFluct = aMaterial->GetIonisation()->GetRateionexcfluct(); ipotFluct = aMaterial->GetIonisation()->GetMeanExcitationEnergy(); ipotLogFluct = aMaterial->GetIonisation()->GetLogMeanExcEnergy(); } G4double threshold,w1,w2,w3,lnw3,C,prob, beta2,suma,e0,Em,loss,lossc ,w; G4double a1,a2,a3; G4long p1,p2,p3; G4int nb; G4double Corrfac, na,alfa,rfac,namean,sa,alfa1,ea,sea; G4double dp1,dnmaxDirectFluct,dp3,dnmaxCont2; // get particle data G4double Tkin = aParticle->GetKineticEnergy(); G4double charge = aParticle->GetDefinition()->GetPDGCharge(); if (charge<0.) threshold =((*G4Electron::Electron()).GetCutsInEnergy())[imat]; else threshold =((*G4Positron::Positron()).GetCutsInEnergy())[imat]; G4double rmass = electron_mass_c2/ParticleMass; G4double tau = Tkin/ParticleMass, tau1 = tau+1., tau2 = tau*(tau+2.); G4double Tm = 2.*electron_mass_c2*tau2/(1.+2.*tau1*rmass+rmass*rmass) -ipotFluct; if (Tm < 0.) Tm = 0.; else if (Tm > threshold) Tm = threshold; w1 = Tm+ipotFluct; w2 = w1/ipotFluct; w3 = 2.*electron_mass_c2*tau2; lnw3 = log(w3); beta2 = tau2/(tau1*tau1); C = (1.-rateFluct)*MeanLoss/(lnw3-ipotLogFluct-beta2); a1 = C*f1Fluct*(lnw3-e1LogFluct-beta2)/e1Fluct; a2 = C*f2Fluct*(lnw3-e2LogFluct-beta2)/e2Fluct; if (Tm > 0.) a3 = rateFluct*MeanLoss*Tm/(ipotFluct*w1*log(w2)); else { a1 /= rateFluct; a2 /= rateFluct; a3 = 0.;} suma = a1+a2+a3; //no fluctuation if the loss is too big if (suma > MaxExcitationNumber) return MeanLoss; suma<50.? prob = exp(-suma) : prob = 0.; if (prob > probLimFluct) // very small Step { e0 = aMaterial->GetIonisation()->GetEnergy0fluct(); if (Tm <= 0.) { a1 = MeanLoss/e0; p1 = G4Poisson(a1); loss = p1*e0 ; } else { Em = Tm+e0; a1 = MeanLoss*(Em-e0)/(Em*e0*log(Em/e0)); p1 = G4Poisson(a1); w = (Em-e0)/Em; // just to save time if (p1 > nmaxDirectFluct) { dp1 = p1; dnmaxDirectFluct=nmaxDirectFluct; Corrfac = dp1/dnmaxDirectFluct; p1 = nmaxDirectFluct; } else Corrfac = 1.; loss = 0.; for (long i=0; i0.) loss += (1.-2.*G4UniformRand())*e1Fluct; p3 = G4Poisson(a3); lossc = 0.; na = 0.; alfa = 1.; if (p3 > nmaxCont2) { dp3 = p3; dnmaxCont2 = nmaxCont2; rfac = dp3/(dnmaxCont2+dp3); namean = p3*rfac; sa = nmaxCont1*rfac; na = RandGauss::shoot(namean,sa); if (na > 0.) { alfa = w2*(nmaxCont2+p3)/(w2*nmaxCont2+p3); alfa1 = alfa*log(alfa)/(alfa-1.); ea = na*ipotFluct*alfa1; sea = ipotFluct*sqrt(na*(alfa-alfa1*alfa1)); lossc += RandGauss::shoot(ea,sea); } } nb = G4int(p3-na); if (nb > 0) { w2 = alfa*ipotFluct; w = (w1-w2)/w1; for (G4int k=0; k