72 :
G4VEmModel(nam),fParticleChange(0),isInitialised(false),
73 fAtomDeexcitation(0),kineticEnergy1(0.*eV),
74 cosThetaPrimary(1.0),energySecondary(0.*eV),
75 cosThetaSecondary(0.0),targetOscillator(-1),
76 theCrossSectionHandler(0)
78 fIntrinsicLowEnergyLimit = 100.0*eV;
79 fIntrinsicHighEnergyLimit = 100.0*GeV;
103 if (theCrossSectionHandler)
104 delete theCrossSectionHandler;
112 if (verboseLevel > 3)
113 G4cout <<
"Calling G4PenelopeIonisationModel::Initialise()" <<
G4endl;
117 if (!fAtomDeexcitation)
120 G4cout <<
"WARNING from G4PenelopeIonisationModel " <<
G4endl;
121 G4cout <<
"Atomic de-excitation module is not instantiated, so there will not be ";
123 G4cout <<
"Please make sure this is intended" <<
G4endl;
128 nBins = std::max(nBins,(
size_t)100);
131 if (theCrossSectionHandler)
133 delete theCrossSectionHandler;
134 theCrossSectionHandler = 0;
139 if (verboseLevel > 2) {
140 G4cout <<
"Penelope Ionisation model v2008 is initialized " <<
G4endl
148 if(isInitialised)
return;
150 isInitialised =
true;
178 if (verboseLevel > 3)
179 G4cout <<
"Calling CrossSectionPerVolume() of G4PenelopeIonisationModel" <<
G4endl;
197 if (verboseLevel > 3)
198 G4cout <<
"Material " << material->
GetName() <<
" has " << atPerMol <<
199 "atoms per molecule" <<
G4endl;
203 moleculeDensity = atomDensity/atPerMol;
205 G4double crossPerVolume = crossPerMolecule*moleculeDensity;
207 if (verboseLevel > 2)
210 G4cout <<
"Mean free path for delta emission > " << cutEnergy/keV <<
" keV at " <<
211 energy/keV <<
" keV = " << (1./crossPerVolume)/mm <<
" mm" <<
G4endl;
214 G4cout <<
"Total free path for ionisation (no threshold) at " <<
215 energy/keV <<
" keV = " << (1./totalCross)/mm <<
" mm" <<
G4endl;
217 return crossPerVolume;
232 G4cout <<
"*** G4PenelopeIonisationModel -- WARNING ***" <<
G4endl;
233 G4cout <<
"Penelope Ionisation model v2008 does not calculate cross section _per atom_ " <<
G4endl;
234 G4cout <<
"so the result is always zero. For physics values, please invoke " <<
G4endl;
235 G4cout <<
"GetCrossSectionPerVolume() or GetMeanFreePath() via the G4EmCalculator" <<
G4endl;
261 if (verboseLevel > 3)
262 G4cout <<
"Calling ComputeDEDX() of G4PenelopeIonisationModel" <<
G4endl;
278 moleculeDensity = atomDensity/atPerMol;
280 G4double sPowerPerVolume = sPowerPerMolecule*moleculeDensity;
282 if (verboseLevel > 2)
285 G4cout <<
"Stopping power < " << cutEnergy/keV <<
" keV at " <<
286 kineticEnergy/keV <<
" keV = " <<
287 sPowerPerVolume/(keV/mm) <<
" keV/mm" <<
G4endl;
289 return sPowerPerVolume;
297 return fIntrinsicLowEnergyLimit;
339 if (verboseLevel > 3)
340 G4cout <<
"Calling SamplingSecondaries() of G4PenelopeIonisationModel" <<
G4endl;
345 if (kineticEnergy0 <= fIntrinsicLowEnergyLimit)
359 kineticEnergy1=kineticEnergy0;
362 cosThetaSecondary=1.0;
363 targetOscillator = -1;
366 SampleFinalStateElectron(material,cutE,kineticEnergy0);
368 SampleFinalStatePositron(material,cutE,kineticEnergy0);
373 G4Exception(
"G4PenelopeIonisationModel::SamplingSecondaries()",
377 if (energySecondary == 0)
return;
379 if (verboseLevel > 3)
381 G4cout <<
"G4PenelopeIonisationModel::SamplingSecondaries() for " <<
383 G4cout <<
"Final eKin = " << kineticEnergy1 <<
" keV" <<
G4endl;
384 G4cout <<
"Final cosTheta = " << cosThetaPrimary <<
G4endl;
385 G4cout <<
"Delta-ray eKin = " << energySecondary <<
" keV" <<
G4endl;
386 G4cout <<
"Delta-ray cosTheta = " << cosThetaSecondary <<
G4endl;
391 G4double sint = std::sqrt(1. - cosThetaPrimary*cosThetaPrimary);
393 G4double dirx = sint * std::cos(phiPrimary);
394 G4double diry = sint * std::sin(phiPrimary);
398 electronDirection1.
rotateUz(particleDirection0);
400 if (kineticEnergy1 > 0)
410 G4double ionEnergyInPenelopeDatabase =
411 (*theTable)[targetOscillator]->GetIonisationEnergy();
415 G4int shFlag = (*theTable)[targetOscillator]->GetShellFlag();
416 G4int Z = (
G4int) (*theTable)[targetOscillator]->GetParentZ();
425 if (Z > 0 && shFlag<30)
427 shell = transitionManager->
Shell(Z,shFlag-1);
435 energySecondary += ionEnergyInPenelopeDatabase-bindingEnergy;
437 G4double localEnergyDeposit = bindingEnergy;
442 if (energySecondary < 0)
448 localEnergyDeposit += energySecondary;
449 energySecondary = 0.0;
454 if (fAtomDeexcitation && shell)
459 size_t nBefore = fvect->size();
461 size_t nAfter = fvect->size();
463 if (nAfter > nBefore)
465 for (
size_t j=nBefore;j<nAfter;j++)
467 G4double itsEnergy = ((*fvect)[j])->GetKineticEnergy();
468 localEnergyDeposit -= itsEnergy;
470 energyInFluorescence += itsEnergy;
472 energyInAuger += itsEnergy;
479 if (energySecondary > cutE)
482 G4double sinThetaE = std::sqrt(1.-cosThetaSecondary*cosThetaSecondary);
484 G4double xEl = sinThetaE * std::cos(phiEl);
485 G4double yEl = sinThetaE * std::sin(phiEl);
488 eDirection.
rotateUz(particleDirection0);
490 eDirection,energySecondary) ;
491 fvect->push_back(electron);
495 localEnergyDeposit += energySecondary;
499 if (localEnergyDeposit < 0)
502 <<
"G4PenelopeIonisationModel::SampleSecondaries - Negative energy deposit"
504 localEnergyDeposit=0.;
508 if (verboseLevel > 1)
510 G4cout <<
"-----------------------------------------------------------" <<
G4endl;
511 G4cout <<
"Energy balance from G4PenelopeIonisation" <<
G4endl;
512 G4cout <<
"Incoming primary energy: " << kineticEnergy0/keV <<
" keV" <<
G4endl;
513 G4cout <<
"-----------------------------------------------------------" <<
G4endl;
514 G4cout <<
"Outgoing primary energy: " << kineticEnergy1/keV <<
" keV" <<
G4endl;
515 G4cout <<
"Delta ray " << energySecondary/keV <<
" keV" <<
G4endl;
516 if (energyInFluorescence)
517 G4cout <<
"Fluorescence x-rays: " << energyInFluorescence/keV <<
" keV" <<
G4endl;
519 G4cout <<
"Auger electrons: " << energyInAuger/keV <<
" keV" <<
G4endl;
520 G4cout <<
"Local energy deposit " << localEnergyDeposit/keV <<
" keV" <<
G4endl;
521 G4cout <<
"Total final state: " << (energySecondary+energyInFluorescence+kineticEnergy1+
522 localEnergyDeposit+energyInAuger)/keV <<
524 G4cout <<
"-----------------------------------------------------------" <<
G4endl;
527 if (verboseLevel > 0)
529 G4double energyDiff = std::fabs(energySecondary+energyInFluorescence+kineticEnergy1+
530 localEnergyDeposit+energyInAuger-kineticEnergy0);
531 if (energyDiff > 0.05*keV)
532 G4cout <<
"Warning from G4PenelopeIonisation: problem with energy conservation: " <<
533 (energySecondary+energyInFluorescence+kineticEnergy1+localEnergyDeposit+energyInAuger)/keV <<
534 " keV (final) vs. " <<
535 kineticEnergy0/keV <<
" keV (initial)" <<
G4endl;
541void G4PenelopeIonisationModel::SampleFinalStateElectron(
const G4Material* mat,
554 size_t numberOfOscillators = theTable->size();
562 targetOscillator = numberOfOscillators-1;
565 for (
size_t i=0;i<numberOfOscillators-1;i++)
577 targetOscillator = (
G4int) i;
583 if (verboseLevel > 3)
585 G4cout <<
"SampleFinalStateElectron: sampled oscillator #" << targetOscillator <<
"." <<
G4endl;
586 G4cout <<
"Ionisation energy: " << (*theTable)[targetOscillator]->GetIonisationEnergy()/eV <<
588 G4cout <<
"Resonance energy: : " << (*theTable)[targetOscillator]->GetResonanceEnergy()/eV <<
" eV "
592 G4double rb = kineticEnergy + 2.0*electron_mass_c2;
599 G4double resEne = (*theTable)[targetOscillator]->GetResonanceEnergy();
601 G4double ionEne = (*theTable)[targetOscillator]->GetIonisationEnergy();
602 G4double cutoffEne = (*theTable)[targetOscillator]->GetCutoffRecoilResonantEnergy();
610 if (resEne > cutEnergy && resEne < kineticEnergy)
612 cps = kineticEnergy*rb;
614 G4double XHDT0 = std::max(std::log(gam2)-beta2-delta,0.);
615 if (resEne > 1.0e-6*kineticEnergy)
617 G4double cpp = std::sqrt((kineticEnergy-resEne)*(kineticEnergy-resEne+2.0*electron_mass_c2));
618 QM = std::sqrt((cp-cpp)*(cp-cpp)+electron_mass_c2*electron_mass_c2)-electron_mass_c2;
622 QM = resEne*resEne/(beta2*2.0*electron_mass_c2);
623 QM *= (1.0-QM*0.5/electron_mass_c2);
627 XHDL = std::log(cutoffEne*(QM+2.0*electron_mass_c2)/(QM*(cutoffEne+2.0*electron_mass_c2)))
629 XHDT = XHDT0*invResEne;
648 G4double EE = kineticEnergy + ionEne;
650 G4double wcl = std::max(cutEnergy,cutoffEne);
657 XHC = (amol*(0.5-rcl)+1.0/rcl-rrl1+
658 (1.0-amol)*std::log(rcl*rrl1))/EE;
665 if (XHTOT < 1.e-14*barn)
667 kineticEnergy1=kineticEnergy;
670 cosThetaSecondary=1.0;
671 targetOscillator = numberOfOscillators-1;
693 rk = rcl/(1.0-fb*(1.0-(rcl+rcl)));
695 rk = rcl + (fb-1.0)*(0.5-rcl)/ARCL;
698 G4double phi = 1.0+rkf*rkf-rkf+amol*(rk2+rkf);
705 kineticEnergy1 = kineticEnergy - deltaE;
706 cosThetaPrimary = std::sqrt(kineticEnergy1*rb/(kineticEnergy*(rb-deltaE)));
708 energySecondary = deltaE - ionEne;
709 cosThetaSecondary= std::sqrt(deltaE*rb/(kineticEnergy*(deltaE+2.0*electron_mass_c2)));
710 if (verboseLevel > 3)
711 G4cout <<
"SampleFinalStateElectron: sampled close collision " <<
G4endl;
718 kineticEnergy1 = kineticEnergy - deltaE;
722 G4double QS = QM/(1.0+QM*0.5/electron_mass_c2);
724 - (QS*0.5/electron_mass_c2));
725 G4double QTREV = Q*(Q+2.0*electron_mass_c2);
726 G4double cpps = kineticEnergy1*(kineticEnergy1+2.0*electron_mass_c2);
727 cosThetaPrimary = (cpps+cps-QTREV)/(2.0*cp*std::sqrt(cpps));
728 if (cosThetaPrimary > 1.)
729 cosThetaPrimary = 1.0;
731 energySecondary = deltaE - ionEne;
732 cosThetaSecondary = 0.5*(deltaE*(kineticEnergy+rb-deltaE)+QTREV)/std::sqrt(cps*QTREV);
733 if (cosThetaSecondary > 1.0)
734 cosThetaSecondary = 1.0;
735 if (verboseLevel > 3)
736 G4cout <<
"SampleFinalStateElectron: sampled distant longitudinal collision " <<
G4endl;
741 cosThetaPrimary = 1.0;
743 energySecondary = deltaE - ionEne;
744 cosThetaSecondary = 0.5;
745 if (verboseLevel > 3)
746 G4cout <<
"SampleFinalStateElectron: sampled distant transverse collision " <<
G4endl;
754void G4PenelopeIonisationModel::SampleFinalStatePositron(
const G4Material* mat,
767 size_t numberOfOscillators = theTable->size();
774 targetOscillator = numberOfOscillators-1;
776 for (
size_t i=0;i<numberOfOscillators-1;i++)
781 targetOscillator = (
G4int) i;
786 if (verboseLevel > 3)
788 G4cout <<
"SampleFinalStatePositron: sampled oscillator #" << targetOscillator <<
"." <<
G4endl;
789 G4cout <<
"Ionisation energy: " << (*theTable)[targetOscillator]->GetIonisationEnergy()/eV
791 G4cout <<
"Resonance energy: : " << (*theTable)[targetOscillator]->GetResonanceEnergy()/eV
796 G4double rb = kineticEnergy + 2.0*electron_mass_c2;
803 G4double bha1 = amol*(2.0*g12-1.0)/(gam2-1.0);
811 G4double resEne = (*theTable)[targetOscillator]->GetResonanceEnergy();
813 G4double ionEne = (*theTable)[targetOscillator]->GetIonisationEnergy();
814 G4double cutoffEne = (*theTable)[targetOscillator]->GetCutoffRecoilResonantEnergy();
823 if (resEne > cutEnergy && resEne < kineticEnergy)
825 cps = kineticEnergy*rb;
827 G4double XHDT0 = std::max(std::log(gam2)-beta2-delta,0.);
828 if (resEne > 1.0e-6*kineticEnergy)
830 G4double cpp = std::sqrt((kineticEnergy-resEne)*(kineticEnergy-resEne+2.0*electron_mass_c2));
831 QM = std::sqrt((cp-cpp)*(cp-cpp)+electron_mass_c2*electron_mass_c2)-electron_mass_c2;
835 QM = resEne*resEne/(beta2*2.0*electron_mass_c2);
836 QM *= (1.0-QM*0.5/electron_mass_c2);
840 XHDL = std::log(cutoffEne*(QM+2.0*electron_mass_c2)/(QM*(cutoffEne+2.0*electron_mass_c2)))
842 XHDT = XHDT0*invResEne;
861 G4double wcl = std::max(cutEnergy,cutoffEne);
867 XHC = ((1.0/rcl-1.0)+bha1*std::log(rcl)+bha2*rl1
868 + (bha3/2.0)*(rcl*rcl-1.0)
869 + (bha4/3.0)*(1.0-rcl*rcl*rcl))/kineticEnergy;
876 if (XHTOT < 1.e-14*barn)
878 kineticEnergy1=kineticEnergy;
881 cosThetaSecondary=1.0;
882 targetOscillator = numberOfOscillators-1;
900 G4double phi = 1.0-rk*(bha1-rk*(bha2-rk*(bha3-bha4*rk)));
906 kineticEnergy1 = kineticEnergy - deltaE;
907 cosThetaPrimary = std::sqrt(kineticEnergy1*rb/(kineticEnergy*(rb-deltaE)));
909 energySecondary = deltaE - ionEne;
910 cosThetaSecondary= std::sqrt(deltaE*rb/(kineticEnergy*(deltaE+2.0*electron_mass_c2)));
911 if (verboseLevel > 3)
912 G4cout <<
"SampleFinalStatePositron: sampled close collision " <<
G4endl;
919 kineticEnergy1 = kineticEnergy - deltaE;
922 G4double QS = QM/(1.0+QM*0.5/electron_mass_c2);
924 - (QS*0.5/electron_mass_c2));
925 G4double QTREV = Q*(Q+2.0*electron_mass_c2);
926 G4double cpps = kineticEnergy1*(kineticEnergy1+2.0*electron_mass_c2);
927 cosThetaPrimary = (cpps+cps-QTREV)/(2.0*cp*std::sqrt(cpps));
928 if (cosThetaPrimary > 1.)
929 cosThetaPrimary = 1.0;
931 energySecondary = deltaE - ionEne;
932 cosThetaSecondary = 0.5*(deltaE*(kineticEnergy+rb-deltaE)+QTREV)/std::sqrt(cps*QTREV);
933 if (cosThetaSecondary > 1.0)
934 cosThetaSecondary = 1.0;
935 if (verboseLevel > 3)
936 G4cout <<
"SampleFinalStatePositron: sampled distant longitudinal collision " <<
G4endl;
941 cosThetaPrimary = 1.0;
943 energySecondary = deltaE - ionEne;
944 cosThetaSecondary = 0.5;
946 if (verboseLevel > 3)
947 G4cout <<
"SampleFinalStatePositron: sampled distant transverse collision " <<
G4endl;
std::vector< G4PenelopeOscillator * > G4PenelopeOscillatorTable
G4DLLIMPORT std::ostream G4cout
Hep3Vector & rotateUz(const Hep3Vector &)
G4double BindingEnergy() const
G4AtomicShell * Shell(G4int Z, size_t shellIndex) const
static G4AtomicTransitionManager * Instance()
const G4ThreeVector & GetMomentumDirection() const
G4ParticleDefinition * GetDefinition() const
G4double GetKineticEnergy() const
static G4Electron * Definition()
static G4Electron * Electron()
static G4Gamma * Definition()
static G4LossTableManager * Instance()
G4VAtomDeexcitation * AtomDeexcitation()
const G4Material * GetMaterial() const
G4double GetTotNbOfAtomsPerVolume() const
const G4String & GetName() const
void SetProposedKineticEnergy(G4double proposedKinEnergy)
void ProposeMomentumDirection(G4double Px, G4double Py, G4double Pz)
const G4String & GetParticleName() const
G4double GetSoftStoppingPower(G4double energy)
Returns the total stopping power due to soft collisions.
G4double GetHardCrossSection(G4double energy)
Returns hard cross section at the given energy.
G4double GetTotalCrossSection(G4double energy)
Returns total cross section at the given energy.
G4double GetNormalizedShellCrossSection(size_t shellID, G4double energy)
Returns the hard cross section for the given shell (normalized to 1)
virtual void Initialise(const G4ParticleDefinition *, const G4DataVector &)
virtual void SampleSecondaries(std::vector< G4DynamicParticle * > *, const G4MaterialCutsCouple *, const G4DynamicParticle *, G4double tmin, G4double maxEnergy)
virtual G4double ComputeDEDXPerVolume(const G4Material *, const G4ParticleDefinition *, G4double kineticEnergy, G4double cutEnergy)
virtual G4double CrossSectionPerVolume(const G4Material *material, const G4ParticleDefinition *theParticle, G4double kineticEnergy, G4double cutEnergy, G4double maxEnergy=DBL_MAX)
G4ParticleChangeForLoss * fParticleChange
virtual ~G4PenelopeIonisationModel()
virtual G4double ComputeCrossSectionPerAtom(const G4ParticleDefinition *, G4double, G4double, G4double, G4double, G4double)
G4PenelopeIonisationModel(const G4ParticleDefinition *p=0, const G4String &processName="PenIoni")
virtual G4double MinEnergyCut(const G4ParticleDefinition *, const G4MaterialCutsCouple *)
G4double GetDensityCorrection(const G4Material *, G4double energy)
Returns the density coeection for the material at the given energy.
G4PenelopeCrossSection * GetCrossSectionTableForCouple(const G4ParticleDefinition *, const G4Material *, G4double cut)
void SetVerboseLevel(G4int vl)
Setter for the verbosity level.
G4double GetAtomsPerMolecule(const G4Material *)
Returns the total number of atoms per molecule.
static G4PenelopeOscillatorManager * GetOscillatorManager()
G4PenelopeOscillatorTable * GetOscillatorTableIonisation(const G4Material *)
static G4Positron * Positron()
G4bool CheckDeexcitationActiveRegion(G4int coupleIndex)
void GenerateParticles(std::vector< G4DynamicParticle * > *secVect, const G4AtomicShell *, G4int Z, G4int coupleIndex)
void SetHighEnergyLimit(G4double)
G4double LowEnergyLimit() const
G4double HighEnergyLimit() const
virtual void SetupForMaterial(const G4ParticleDefinition *, const G4Material *, G4double kineticEnergy)
void SetDeexcitationFlag(G4bool val)
G4ParticleChangeForLoss * GetParticleChangeForLoss()
void ProposeLocalEnergyDeposit(G4double anEnergyPart)
void G4Exception(const char *originOfException, const char *exceptionCode, G4ExceptionSeverity severity, const char *comments)
std::ostringstream G4ExceptionDescription