75 :
G4VEmModel(nam),fParticleChange(0),fParticle(0),isInitialised(false),
76 fAtomDeexcitation(0),fPIXEflag(false),kineticEnergy1(0.*eV),
77 cosThetaPrimary(1.0),energySecondary(0.*eV),
78 cosThetaSecondary(0.0),targetOscillator(-1),
79 theCrossSectionHandler(0),fLocalTable(false)
81 fIntrinsicLowEnergyLimit = 100.0*eV;
82 fIntrinsicHighEnergyLimit = 100.0*GeV;
112 if (theCrossSectionHandler)
113 delete theCrossSectionHandler;
122 if (verboseLevel > 3)
123 G4cout <<
"Calling G4PenelopeIonisationModel::Initialise()" <<
G4endl;
127 if (!fAtomDeexcitation)
130 G4cout <<
"WARNING from G4PenelopeIonisationModel " <<
G4endl;
131 G4cout <<
"Atomic de-excitation module is not instantiated, so there will not be ";
133 G4cout <<
"Please make sure this is intended" <<
G4endl;
136 if (fAtomDeexcitation)
145 G4cout <<
"======================================================================" <<
G4endl;
146 G4cout <<
"The G4PenelopeIonisationModel is being used with the PIXE flag ON." <<
G4endl;
147 G4cout <<
"Atomic de-excitation will be produced statistically by the PIXE " <<
G4endl;
148 G4cout <<
"interface by using the shell cross section --> " << theModel <<
G4endl;
149 G4cout <<
"The built-in model procedure for atomic de-excitation is disabled. " <<
G4endl;
150 G4cout <<
"*Please be sure this is intended*, or disable PIXE by" <<
G4endl;
160 G4cout <<
"======================================================================" <<
G4endl;
166 SetParticle(particle);
175 nBins = std::max(nBins,(
size_t)100);
178 if (theCrossSectionHandler)
180 delete theCrossSectionHandler;
181 theCrossSectionHandler = 0;
194 theCrossSectionHandler->
BuildXSTable(theMat,theCuts.at(i),particle,
199 if (verboseLevel > 2) {
200 G4cout <<
"Penelope Ionisation model v2008 is initialized " <<
G4endl
212 isInitialised =
true;
222 if (verboseLevel > 3)
223 G4cout <<
"Calling G4PenelopeIonisationModel::InitialiseLocal()" <<
G4endl;
236 theCrossSectionHandler = theModel->theCrossSectionHandler;
239 nBins = theModel->nBins;
242 verboseLevel = theModel->verboseLevel;
274 if (verboseLevel > 3)
275 G4cout <<
"Calling CrossSectionPerVolume() of G4PenelopeIonisationModel" <<
G4endl;
284 if (!theCrossSectionHandler)
300 if (verboseLevel > 0)
304 ed <<
"Unable to retrieve the cross section table for " << theParticle->
GetParticleName() <<
305 " in " << material->
GetName() <<
", cut = " << cutEnergy/keV <<
" keV " <<
G4endl;
306 ed <<
"This can happen only in Unit Tests or via G4EmCalculator" <<
G4endl;
307 G4Exception(
"G4PenelopeIonisationModel::CrossSectionPerVolume()",
311 G4AutoLock lock(&PenelopeIonisationModelMutex);
312 theCrossSectionHandler->
BuildXSTable(material,cutEnergy,theParticle);
328 if (verboseLevel > 3)
329 G4cout <<
"Material " << material->
GetName() <<
" has " << atPerMol <<
330 "atoms per molecule" <<
G4endl;
334 moleculeDensity = atomDensity/atPerMol;
336 G4double crossPerVolume = crossPerMolecule*moleculeDensity;
338 if (verboseLevel > 2)
341 G4cout <<
"Mean free path for delta emission > " << cutEnergy/keV <<
" keV at " <<
342 energy/keV <<
" keV = " << (1./crossPerVolume)/mm <<
" mm" <<
G4endl;
345 G4cout <<
"Total free path for ionisation (no threshold) at " <<
346 energy/keV <<
" keV = " << (1./totalCross)/mm <<
" mm" <<
G4endl;
348 return crossPerVolume;
363 G4cout <<
"*** G4PenelopeIonisationModel -- WARNING ***" <<
G4endl;
364 G4cout <<
"Penelope Ionisation model v2008 does not calculate cross section _per atom_ " <<
G4endl;
365 G4cout <<
"so the result is always zero. For physics values, please invoke " <<
G4endl;
366 G4cout <<
"GetCrossSectionPerVolume() or GetMeanFreePath() via the G4EmCalculator" <<
G4endl;
392 if (verboseLevel > 3)
393 G4cout <<
"Calling ComputeDEDX() of G4PenelopeIonisationModel" <<
G4endl;
397 if (!theCrossSectionHandler)
413 if (verboseLevel > 0)
417 ed <<
"Unable to retrieve the cross section table for " << theParticle->
GetParticleName() <<
418 " in " << material->
GetName() <<
", cut = " << cutEnergy/keV <<
" keV " <<
G4endl;
419 ed <<
"This can happen only in Unit Tests or via G4EmCalculator" <<
G4endl;
420 G4Exception(
"G4PenelopeIonisationModel::ComputeDEDXPerVolume()",
424 G4AutoLock lock(&PenelopeIonisationModelMutex);
425 theCrossSectionHandler->
BuildXSTable(material,cutEnergy,theParticle);
444 moleculeDensity = atomDensity/atPerMol;
446 G4double sPowerPerVolume = sPowerPerMolecule*moleculeDensity;
448 if (verboseLevel > 2)
451 G4cout <<
"Stopping power < " << cutEnergy/keV <<
" keV at " <<
452 kineticEnergy/keV <<
" keV = " <<
453 sPowerPerVolume/(keV/mm) <<
" keV/mm" <<
G4endl;
455 return sPowerPerVolume;
463 return fIntrinsicLowEnergyLimit;
505 if (verboseLevel > 3)
506 G4cout <<
"Calling SamplingSecondaries() of G4PenelopeIonisationModel" <<
G4endl;
511 if (kineticEnergy0 <= fIntrinsicLowEnergyLimit)
525 kineticEnergy1=kineticEnergy0;
528 cosThetaSecondary=1.0;
529 targetOscillator = -1;
532 SampleFinalStateElectron(material,cutE,kineticEnergy0);
534 SampleFinalStatePositron(material,cutE,kineticEnergy0);
539 G4Exception(
"G4PenelopeIonisationModel::SamplingSecondaries()",
543 if (energySecondary == 0)
return;
545 if (verboseLevel > 3)
547 G4cout <<
"G4PenelopeIonisationModel::SamplingSecondaries() for " <<
549 G4cout <<
"Final eKin = " << kineticEnergy1 <<
" keV" <<
G4endl;
550 G4cout <<
"Final cosTheta = " << cosThetaPrimary <<
G4endl;
551 G4cout <<
"Delta-ray eKin = " << energySecondary <<
" keV" <<
G4endl;
552 G4cout <<
"Delta-ray cosTheta = " << cosThetaSecondary <<
G4endl;
557 G4double sint = std::sqrt(1. - cosThetaPrimary*cosThetaPrimary);
559 G4double dirx = sint * std::cos(phiPrimary);
560 G4double diry = sint * std::sin(phiPrimary);
564 electronDirection1.
rotateUz(particleDirection0);
566 if (kineticEnergy1 > 0)
576 G4double ionEnergyInPenelopeDatabase =
577 (*theTable)[targetOscillator]->GetIonisationEnergy();
581 G4int shFlag = (*theTable)[targetOscillator]->GetShellFlag();
582 G4int Z = (
G4int) (*theTable)[targetOscillator]->GetParentZ();
591 if (Z > 0 && shFlag<30)
593 shell = transitionManager->
Shell(Z,shFlag-1);
601 energySecondary += ionEnergyInPenelopeDatabase-bindingEnergy;
603 G4double localEnergyDeposit = bindingEnergy;
608 if (energySecondary < 0)
614 localEnergyDeposit += energySecondary;
615 energySecondary = 0.0;
623 if (fAtomDeexcitation && !fPIXEflag && shell)
628 size_t nBefore = fvect->size();
630 size_t nAfter = fvect->size();
634 for (
size_t j=nBefore;j<nAfter;j++)
636 G4double itsEnergy = ((*fvect)[j])->GetKineticEnergy();
637 if (itsEnergy < localEnergyDeposit)
639 localEnergyDeposit -= itsEnergy;
641 energyInFluorescence += itsEnergy;
643 energyInAuger += itsEnergy;
648 (*fvect)[j] =
nullptr;
657 if (energySecondary > cutE)
660 G4double sinThetaE = std::sqrt(1.-cosThetaSecondary*cosThetaSecondary);
662 G4double xEl = sinThetaE * std::cos(phiEl);
663 G4double yEl = sinThetaE * std::sin(phiEl);
666 eDirection.
rotateUz(particleDirection0);
668 eDirection,energySecondary) ;
669 fvect->push_back(electron);
673 localEnergyDeposit += energySecondary;
677 if (localEnergyDeposit < 0)
679 G4Exception(
"G4PenelopeIonisationModel::SampleSecondaries()",
680 "em2099",
JustWarning,
"WARNING: Negative local energy deposit");
681 localEnergyDeposit=0.;
685 if (verboseLevel > 1)
687 G4cout <<
"-----------------------------------------------------------" <<
G4endl;
688 G4cout <<
"Energy balance from G4PenelopeIonisation" <<
G4endl;
689 G4cout <<
"Incoming primary energy: " << kineticEnergy0/keV <<
" keV" <<
G4endl;
690 G4cout <<
"-----------------------------------------------------------" <<
G4endl;
691 G4cout <<
"Outgoing primary energy: " << kineticEnergy1/keV <<
" keV" <<
G4endl;
692 G4cout <<
"Delta ray " << energySecondary/keV <<
" keV" <<
G4endl;
693 if (energyInFluorescence)
694 G4cout <<
"Fluorescence x-rays: " << energyInFluorescence/keV <<
" keV" <<
G4endl;
696 G4cout <<
"Auger electrons: " << energyInAuger/keV <<
" keV" <<
G4endl;
697 G4cout <<
"Local energy deposit " << localEnergyDeposit/keV <<
" keV" <<
G4endl;
698 G4cout <<
"Total final state: " << (energySecondary+energyInFluorescence+kineticEnergy1+
699 localEnergyDeposit+energyInAuger)/keV <<
701 G4cout <<
"-----------------------------------------------------------" <<
G4endl;
704 if (verboseLevel > 0)
706 G4double energyDiff = std::fabs(energySecondary+energyInFluorescence+kineticEnergy1+
707 localEnergyDeposit+energyInAuger-kineticEnergy0);
708 if (energyDiff > 0.05*keV)
709 G4cout <<
"Warning from G4PenelopeIonisation: problem with energy conservation: " <<
710 (energySecondary+energyInFluorescence+kineticEnergy1+localEnergyDeposit+energyInAuger)/keV <<
711 " keV (final) vs. " <<
712 kineticEnergy0/keV <<
" keV (initial)" <<
G4endl;
718void G4PenelopeIonisationModel::SampleFinalStateElectron(
const G4Material* mat,
731 size_t numberOfOscillators = theTable->size();
739 targetOscillator = numberOfOscillators-1;
742 for (
size_t i=0;i<numberOfOscillators-1;i++)
754 targetOscillator = (
G4int) i;
760 if (verboseLevel > 3)
762 G4cout <<
"SampleFinalStateElectron: sampled oscillator #" << targetOscillator <<
"." <<
G4endl;
763 G4cout <<
"Ionisation energy: " << (*theTable)[targetOscillator]->GetIonisationEnergy()/eV <<
765 G4cout <<
"Resonance energy: : " << (*theTable)[targetOscillator]->GetResonanceEnergy()/eV <<
" eV "
769 G4double rb = kineticEnergy + 2.0*electron_mass_c2;
776 G4double resEne = (*theTable)[targetOscillator]->GetResonanceEnergy();
778 G4double ionEne = (*theTable)[targetOscillator]->GetIonisationEnergy();
779 G4double cutoffEne = (*theTable)[targetOscillator]->GetCutoffRecoilResonantEnergy();
787 if (resEne > cutEnergy && resEne < kineticEnergy)
789 cps = kineticEnergy*rb;
792 if (resEne > 1.0e-6*kineticEnergy)
794 G4double cpp = std::sqrt((kineticEnergy-resEne)*(kineticEnergy-resEne+2.0*electron_mass_c2));
795 QM = std::sqrt((cp-cpp)*(cp-cpp)+electron_mass_c2*electron_mass_c2)-electron_mass_c2;
799 QM = resEne*resEne/(beta2*2.0*electron_mass_c2);
800 QM *= (1.0-QM*0.5/electron_mass_c2);
804 XHDL =
G4Log(cutoffEne*(QM+2.0*electron_mass_c2)/(QM*(cutoffEne+2.0*electron_mass_c2)))
806 XHDT = XHDT0*invResEne;
825 G4double EE = kineticEnergy + ionEne;
827 G4double wcl = std::max(cutEnergy,cutoffEne);
834 XHC = (amol*(0.5-rcl)+1.0/rcl-rrl1+
835 (1.0-amol)*
G4Log(rcl*rrl1))/EE;
842 if (XHTOT < 1.e-14*barn)
844 kineticEnergy1=kineticEnergy;
847 cosThetaSecondary=1.0;
848 targetOscillator = numberOfOscillators-1;
870 rk = rcl/(1.0-fb*(1.0-(rcl+rcl)));
872 rk = rcl + (fb-1.0)*(0.5-rcl)/ARCL;
875 G4double phi = 1.0+rkf*rkf-rkf+amol*(rk2+rkf);
882 kineticEnergy1 = kineticEnergy - deltaE;
883 cosThetaPrimary = std::sqrt(kineticEnergy1*rb/(kineticEnergy*(rb-deltaE)));
885 energySecondary = deltaE - ionEne;
886 cosThetaSecondary= std::sqrt(deltaE*rb/(kineticEnergy*(deltaE+2.0*electron_mass_c2)));
887 if (verboseLevel > 3)
888 G4cout <<
"SampleFinalStateElectron: sampled close collision " <<
G4endl;
895 kineticEnergy1 = kineticEnergy - deltaE;
899 G4double QS = QM/(1.0+QM*0.5/electron_mass_c2);
901 - (QS*0.5/electron_mass_c2));
902 G4double QTREV = Q*(Q+2.0*electron_mass_c2);
903 G4double cpps = kineticEnergy1*(kineticEnergy1+2.0*electron_mass_c2);
904 cosThetaPrimary = (cpps+cps-QTREV)/(2.0*cp*std::sqrt(cpps));
905 if (cosThetaPrimary > 1.)
906 cosThetaPrimary = 1.0;
908 energySecondary = deltaE - ionEne;
909 cosThetaSecondary = 0.5*(deltaE*(kineticEnergy+rb-deltaE)+QTREV)/std::sqrt(cps*QTREV);
910 if (cosThetaSecondary > 1.0)
911 cosThetaSecondary = 1.0;
912 if (verboseLevel > 3)
913 G4cout <<
"SampleFinalStateElectron: sampled distant longitudinal collision " <<
G4endl;
918 cosThetaPrimary = 1.0;
920 energySecondary = deltaE - ionEne;
921 cosThetaSecondary = 0.5;
922 if (verboseLevel > 3)
923 G4cout <<
"SampleFinalStateElectron: sampled distant transverse collision " <<
G4endl;
931void G4PenelopeIonisationModel::SampleFinalStatePositron(
const G4Material* mat,
944 size_t numberOfOscillators = theTable->size();
952 targetOscillator = numberOfOscillators-1;
954 for (
size_t i=0;i<numberOfOscillators-1;i++)
959 targetOscillator = (
G4int) i;
964 if (verboseLevel > 3)
966 G4cout <<
"SampleFinalStatePositron: sampled oscillator #" << targetOscillator <<
"." <<
G4endl;
967 G4cout <<
"Ionisation energy: " << (*theTable)[targetOscillator]->GetIonisationEnergy()/eV
969 G4cout <<
"Resonance energy: : " << (*theTable)[targetOscillator]->GetResonanceEnergy()/eV
974 G4double rb = kineticEnergy + 2.0*electron_mass_c2;
981 G4double bha1 = amol*(2.0*g12-1.0)/(gam2-1.0);
989 G4double resEne = (*theTable)[targetOscillator]->GetResonanceEnergy();
991 G4double ionEne = (*theTable)[targetOscillator]->GetIonisationEnergy();
992 G4double cutoffEne = (*theTable)[targetOscillator]->GetCutoffRecoilResonantEnergy();
1001 if (resEne > cutEnergy && resEne < kineticEnergy)
1003 cps = kineticEnergy*rb;
1004 cp = std::sqrt(cps);
1006 if (resEne > 1.0e-6*kineticEnergy)
1008 G4double cpp = std::sqrt((kineticEnergy-resEne)*(kineticEnergy-resEne+2.0*electron_mass_c2));
1009 QM = std::sqrt((cp-cpp)*(cp-cpp)+electron_mass_c2*electron_mass_c2)-electron_mass_c2;
1013 QM = resEne*resEne/(beta2*2.0*electron_mass_c2);
1014 QM *= (1.0-QM*0.5/electron_mass_c2);
1018 XHDL =
G4Log(cutoffEne*(QM+2.0*electron_mass_c2)/(QM*(cutoffEne+2.0*electron_mass_c2)))
1020 XHDT = XHDT0*invResEne;
1039 G4double wcl = std::max(cutEnergy,cutoffEne);
1045 XHC = ((1.0/rcl-1.0)+bha1*
G4Log(rcl)+bha2*rl1
1046 + (bha3/2.0)*(rcl*rcl-1.0)
1047 + (bha4/3.0)*(1.0-rcl*rcl*rcl))/kineticEnergy;
1051 G4double XHTOT = XHC + XHDL + XHDT;
1054 if (XHTOT < 1.e-14*barn)
1056 kineticEnergy1=kineticEnergy;
1057 cosThetaPrimary=1.0;
1058 energySecondary=0.0;
1059 cosThetaSecondary=1.0;
1060 targetOscillator = numberOfOscillators-1;
1073 G4bool loopAgain =
false;
1078 G4double phi = 1.0-rk*(bha1-rk*(bha2-rk*(bha3-bha4*rk)));
1083 G4double deltaE = rk*kineticEnergy;
1084 kineticEnergy1 = kineticEnergy - deltaE;
1085 cosThetaPrimary = std::sqrt(kineticEnergy1*rb/(kineticEnergy*(rb-deltaE)));
1087 energySecondary = deltaE - ionEne;
1088 cosThetaSecondary= std::sqrt(deltaE*rb/(kineticEnergy*(deltaE+2.0*electron_mass_c2)));
1089 if (verboseLevel > 3)
1090 G4cout <<
"SampleFinalStatePositron: sampled close collision " <<
G4endl;
1097 kineticEnergy1 = kineticEnergy - deltaE;
1100 G4double QS = QM/(1.0+QM*0.5/electron_mass_c2);
1102 - (QS*0.5/electron_mass_c2));
1103 G4double QTREV = Q*(Q+2.0*electron_mass_c2);
1104 G4double cpps = kineticEnergy1*(kineticEnergy1+2.0*electron_mass_c2);
1105 cosThetaPrimary = (cpps+cps-QTREV)/(2.0*cp*std::sqrt(cpps));
1106 if (cosThetaPrimary > 1.)
1107 cosThetaPrimary = 1.0;
1109 energySecondary = deltaE - ionEne;
1110 cosThetaSecondary = 0.5*(deltaE*(kineticEnergy+rb-deltaE)+QTREV)/std::sqrt(cps*QTREV);
1111 if (cosThetaSecondary > 1.0)
1112 cosThetaSecondary = 1.0;
1113 if (verboseLevel > 3)
1114 G4cout <<
"SampleFinalStatePositron: sampled distant longitudinal collision " <<
G4endl;
1119 cosThetaPrimary = 1.0;
1121 energySecondary = deltaE - ionEne;
1122 cosThetaSecondary = 0.5;
1124 if (verboseLevel > 3)
1125 G4cout <<
"SampleFinalStatePositron: sampled distant transverse collision " <<
G4endl;
double A(double temperature)
void G4Exception(const char *originOfException, const char *exceptionCode, G4ExceptionSeverity severity, const char *description)
std::ostringstream G4ExceptionDescription
G4double G4Log(G4double x)
std::vector< G4PenelopeOscillator * > G4PenelopeOscillatorTable
#define G4MUTEX_INITIALIZER
G4GLOB_DLL 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 G4EmParameters * Instance()
const G4String & PIXEElectronCrossSectionModel()
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 GetTotalCrossSection(G4double energy) const
Returns total cross section at the given energy.
G4double GetSoftStoppingPower(G4double energy) const
Returns the total stopping power due to soft collisions.
G4double GetHardCrossSection(G4double energy) const
Returns hard cross section at the given energy.
G4double GetNormalizedShellCrossSection(size_t shellID, G4double energy) const
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)
const G4ParticleDefinition * fParticle
G4PenelopeIonisationModel(const G4ParticleDefinition *p=0, const G4String &processName="PenIoni")
virtual void InitialiseLocal(const G4ParticleDefinition *, G4VEmModel *)
virtual G4double MinEnergyCut(const G4ParticleDefinition *, const G4MaterialCutsCouple *)
G4double GetDensityCorrection(const G4Material *, const G4double energy) const
Returns the density coeection for the material at the given energy.
void BuildXSTable(const G4Material *, G4double cut, const G4ParticleDefinition *, G4bool isMaster=true)
This can be inkoved only by the master.
const G4PenelopeCrossSection * GetCrossSectionTableForCouple(const G4ParticleDefinition *, const G4Material *, const G4double cut) const
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()
const G4MaterialCutsCouple * GetMaterialCutsCouple(G4int i) const
std::size_t GetTableSize() const
static G4ProductionCutsTable * GetProductionCutsTable()
G4bool CheckDeexcitationActiveRegion(G4int coupleIndex)
void GenerateParticles(std::vector< G4DynamicParticle * > *secVect, const G4AtomicShell *, G4int Z, G4int coupleIndex)
G4bool IsPIXEActive() const
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)