64 :
G4VEmModel(nam),fParticleChange(nullptr),fParticle(nullptr),
65 fAtomDeexcitation(nullptr),
66 fOscManager(nullptr),fIsInitialised(false)
68 fIntrinsicLowEnergyLimit = 100.0*eV;
69 fIntrinsicHighEnergyLimit = 100.0*GeV;
101 if (fVerboseLevel > 3)
102 G4cout <<
"Calling G4PenelopeComptonModel::Initialise()" <<
G4endl;
106 if (!fAtomDeexcitation)
109 G4cout <<
"WARNING from G4PenelopeComptonModel " <<
G4endl;
110 G4cout <<
"Atomic de-excitation module is not instantiated, so there will not be ";
112 G4cout <<
"Please make sure this is intended" <<
G4endl;
120 if (fVerboseLevel > 0)
122 G4cout <<
"Penelope Compton model v2008 is initialized " <<
G4endl
132 ed <<
"Using the Penelope Compton model outside its intrinsic validity range. "
135 ed <<
"-> Instrinsic low-energy limit = " << fIntrinsicLowEnergyLimit/keV <<
"keV "
137 ed <<
"Result of the simulation have to be taken with care" <<
G4endl;
138 G4Exception(
"G4PenelopeComptonModel::Initialise()",
143 if(fIsInitialised)
return;
145 fIsInitialised =
true;
154 if (fVerboseLevel > 3)
155 G4cout <<
"Calling G4PenelopeComptonModel::InitialiseLocal()" <<
G4endl;
167 fVerboseLevel = theModel->fVerboseLevel;
192 if (fVerboseLevel > 3)
193 G4cout <<
"Calling CrossSectionPerVolume() of G4PenelopeComptonModel" <<
G4endl;
206 size_t numberOfOscillators = theTable->size();
207 for (
size_t i=0;i<numberOfOscillators;i++)
211 cs += OscillatorTotalCrossSection(energy,theOsc);
215 cs = KleinNishinaCrossSection(energy,material);
218 cs *= pi*classic_electr_radius*classic_electr_radius;
225 if (fVerboseLevel > 3)
226 G4cout <<
"Material " << material->
GetName() <<
" has " << atPerMol <<
227 "atoms per molecule" <<
G4endl;
232 moleculeDensity = atomDensity/atPerMol;
234 G4double csvolume = cs*moleculeDensity;
236 if (fVerboseLevel > 2)
237 G4cout <<
"Compton mean free path at " << energy/keV <<
" keV for material " <<
238 material->
GetName() <<
" = " << (1./csvolume)/mm <<
" mm" <<
G4endl;
254 G4cout <<
"*** G4PenelopeComptonModel -- WARNING ***" <<
G4endl;
255 G4cout <<
"Penelope Compton model v2008 does not calculate cross section _per atom_ " <<
G4endl;
256 G4cout <<
"so the result is always zero. For physics values, please invoke " <<
G4endl;
257 G4cout <<
"GetCrossSectionPerVolume() or GetMeanFreePath() via the G4EmCalculator" <<
G4endl;
289 if (fVerboseLevel > 3)
290 G4cout <<
"Calling SampleSecondaries() of G4PenelopeComptonModel" <<
G4endl;
304 const G4int nmax = 64;
313 size_t numberOfOscillators = theTable->size();
314 size_t targetOscillator = 0;
317 G4double ek = photonEnergy0/electron_mass_c2;
324 G4double a2 = a1+2.0*ek*(1.0+ek)/(ek2*ek2);
331 if (photonEnergy0 > 5*MeV)
340 TST = (1.0+tau*(ek1+tau*(ek2+tau*eks)))/(eks*tau*(1.0+tau*tau));
343 cosTheta = 1.0 - (1.0-tau)/(ek*tau);
347 targetOscillator = numberOfOscillators-1;
349 G4bool levelFound =
false;
350 for (
size_t j=0;j<numberOfOscillators && !levelFound; j++)
352 S += (*theTable)[j]->GetOscillatorStrength();
355 targetOscillator = j;
360 ionEnergy = (*theTable)[targetOscillator]->GetIonisationEnergy();
361 }
while((
epsilon*photonEnergy0-photonEnergy0+ionEnergy) >0);
370 for (
size_t i=0;i<numberOfOscillators;i++)
372 ionEnergy = (*theTable)[i]->GetIonisationEnergy();
373 if (photonEnergy0 > ionEnergy)
375 G4double aux2 = photonEnergy0*(photonEnergy0-ionEnergy)*2.0;
376 hartreeFunc = (*theTable)[i]->GetHartreeFactor();
377 oscStren = (*theTable)[i]->GetOscillatorStrength();
378 pzomc = hartreeFunc*(aux2-electron_mass_c2*ionEnergy)/
379 (electron_mass_c2*std::sqrt(2.0*aux2+ionEnergy*ionEnergy));
381 rni = 1.0-0.5*
G4Exp(0.5-(std::sqrt(0.5)+std::sqrt(2.0)*pzomc)*
382 (std::sqrt(0.5)+std::sqrt(2.0)*pzomc));
384 rni = 0.5*
G4Exp(0.5-(std::sqrt(0.5)-std::sqrt(2.0)*pzomc)*
385 (std::sqrt(0.5)-std::sqrt(2.0)*pzomc));
397 cdt1 = (1.0-tau)/(ek*tau);
400 for (
size_t i=0;i<numberOfOscillators;i++)
402 ionEnergy = (*theTable)[i]->GetIonisationEnergy();
403 if (photonEnergy0 > ionEnergy)
405 aux = photonEnergy0*(photonEnergy0-ionEnergy)*cdt1;
406 hartreeFunc = (*theTable)[i]->GetHartreeFactor();
407 oscStren = (*theTable)[i]->GetOscillatorStrength();
408 pzomc = hartreeFunc*(aux-electron_mass_c2*ionEnergy)/
409 (electron_mass_c2*std::sqrt(2.0*aux+ionEnergy*ionEnergy));
411 rn[i] = 1.0-0.5*
G4Exp(0.5-(std::sqrt(0.5)+std::sqrt(2.0)*pzomc)*
412 (std::sqrt(0.5)+std::sqrt(2.0)*pzomc));
414 rn[i] = 0.5*
G4Exp(0.5-(std::sqrt(0.5)-std::sqrt(2.0)*pzomc)*
415 (std::sqrt(0.5)-std::sqrt(2.0)*pzomc));
423 TST =
S*(1.0+tau*(ek1+tau*(ek2+tau*eks)))/(eks*tau*(1.0+tau*tau));
426 cosTheta = 1.0 - cdt1;
435 targetOscillator = numberOfOscillators-1;
436 G4bool levelFound =
false;
437 for (
size_t i=0;i<numberOfOscillators && !levelFound;i++)
441 targetOscillator = i;
446 hartreeFunc = (*theTable)[targetOscillator]->GetHartreeFactor();
447 oscStren = (*theTable)[targetOscillator]->GetOscillatorStrength();
449 pzomc = (std::sqrt(0.5)-std::sqrt(0.5-
G4Log(2.0*
A)))/
450 (std::sqrt(2.0)*hartreeFunc);
452 pzomc = (std::sqrt(0.5-
G4Log(2.0-2.0*
A))-std::sqrt(0.5))/
453 (std::sqrt(2.0)*hartreeFunc);
454 }
while (pzomc < -1);
457 G4double XQC = 1.0+tau*(tau-2.0*cosTheta);
458 G4double AF = std::sqrt(XQC)*(1.0+tau*(tau-cosTheta)/XQC);
463 fpz = 1.0+AF*std::max(std::min(pzomc,0.2),-0.2);
471 epsilon = (tau/b1)*(b2+std::sqrt(std::abs(b2*b2-b1*(1.0-T))));
473 epsilon = (tau/b1)*(b2-std::sqrt(std::abs(b2*b2-b1*(1.0-T))));
477 G4double sinTheta = std::sqrt(1-cosTheta*cosTheta);
479 G4double dirx = sinTheta * std::cos(phi);
480 G4double diry = sinTheta * std::sin(phi);
485 photonDirection1.
rotateUz(photonDirection0);
490 if (photonEnergy1 > 0.)
500 ionEnergy = (*theTable)[targetOscillator]->GetIonisationEnergy();
503 photonEnergy0*photonEnergy0+photonEnergy1*(photonEnergy1-2.0*photonEnergy0*cosTheta);
507 cosThetaE = (photonEnergy0-photonEnergy1*cosTheta)/std::sqrt(Q2);
510 G4double sinThetaE = std::sqrt(1-cosThetaE*cosThetaE);
514 G4int shFlag = (*theTable)[targetOscillator]->GetShellFlag();
515 G4int Z = (
G4int) (*theTable)[targetOscillator]->GetParentZ();
522 if (
Z > 0 && shFlag<30)
524 shell = fTransitionManager->
Shell(
Z,shFlag-1);
528 G4double ionEnergyInPenelopeDatabase = ionEnergy;
530 ionEnergy = std::max(bindingEnergy,ionEnergyInPenelopeDatabase);
534 G4double eKineticEnergy = diffEnergy - ionEnergy;
535 G4double localEnergyDeposit = ionEnergy;
539 if (eKineticEnergy < 0)
545 localEnergyDeposit = diffEnergy;
546 eKineticEnergy = 0.0;
552 if (fAtomDeexcitation && shell)
557 size_t nBefore = fvect->size();
559 size_t nAfter = fvect->size();
561 if (nAfter > nBefore)
563 for (
size_t j=nBefore;j<nAfter;j++)
565 G4double itsEnergy = ((*fvect)[j])->GetKineticEnergy();
566 if (itsEnergy < localEnergyDeposit)
568 localEnergyDeposit -= itsEnergy;
570 energyInFluorescence += itsEnergy;
571 else if (((*fvect)[j])->GetParticleDefinition() ==
573 energyInAuger += itsEnergy;
578 (*fvect)[j] =
nullptr;
589 G4double xEl = sinThetaE * std::cos(phi+pi);
590 G4double yEl = sinThetaE * std::sin(phi+pi);
593 eDirection.
rotateUz(photonDirection0);
595 eDirection,eKineticEnergy) ;
596 fvect->push_back(electron);
598 if (localEnergyDeposit < 0)
600 G4Exception(
"G4PenelopeComptonModel::SampleSecondaries()",
601 "em2099",
JustWarning,
"WARNING: Negative local energy deposit");
602 localEnergyDeposit=0.;
608 electronEnergy = eKineticEnergy;
609 if (fVerboseLevel > 1)
611 G4cout <<
"-----------------------------------------------------------" <<
G4endl;
612 G4cout <<
"Energy balance from G4PenelopeCompton" <<
G4endl;
613 G4cout <<
"Incoming photon energy: " << photonEnergy0/keV <<
" keV" <<
G4endl;
614 G4cout <<
"-----------------------------------------------------------" <<
G4endl;
615 G4cout <<
"Scattered photon: " << photonEnergy1/keV <<
" keV" <<
G4endl;
616 G4cout <<
"Scattered electron " << electronEnergy/keV <<
" keV" <<
G4endl;
617 if (energyInFluorescence)
618 G4cout <<
"Fluorescence x-rays: " << energyInFluorescence/keV <<
" keV" <<
G4endl;
620 G4cout <<
"Auger electrons: " << energyInAuger/keV <<
" keV" <<
G4endl;
621 G4cout <<
"Local energy deposit " << localEnergyDeposit/keV <<
" keV" <<
G4endl;
622 G4cout <<
"Total final state: " << (photonEnergy1+electronEnergy+energyInFluorescence+
623 localEnergyDeposit+energyInAuger)/keV <<
625 G4cout <<
"-----------------------------------------------------------" <<
G4endl;
627 if (fVerboseLevel > 0)
629 G4double energyDiff = std::fabs(photonEnergy1+
630 electronEnergy+energyInFluorescence+
631 localEnergyDeposit+energyInAuger-photonEnergy0);
632 if (energyDiff > 0.05*keV)
633 G4cout <<
"Warning from G4PenelopeCompton: problem with energy conservation: " <<
634 (photonEnergy1+electronEnergy+energyInFluorescence+energyInAuger+localEnergyDeposit)/keV <<
635 " keV (final) vs. " <<
636 photonEnergy0/keV <<
" keV (initial)" <<
G4endl;
659 static const G4double k2 = std::sqrt(2.);
662 if (energy < ionEnergy)
667 G4double EOEC = 1.0+(energy/electron_mass_c2)*cdt1;
671 G4double aux = energy*(energy-ionEnergy)*cdt1;
673 (aux - electron_mass_c2*ionEnergy)/(electron_mass_c2*std::sqrt(2*aux+ionEnergy*ionEnergy));
677 sia = 1.0-0.5*
G4Exp(0.5-(k1+k2*x)*(k1+k2*x));
679 sia = 0.5*
G4Exp(0.5-(k1-k2*x)*(k1-k2*x));
684 if (std::fabs(Pzimax) < pf)
686 G4double QCOE2 = 1.0+ECOE*ECOE-2.0*ECOE*cosTheta;
689 (1.0+ECOE*(ECOE-cosTheta)/QCOE2)*harFunc
690 *0.25*(2*p2-(p2*p2)/(pf*pf)-(pf*pf));
691 sia += std::max(dspz,-1.0*sia);
694 G4double XKN = EOEC+ECOE-1.0+cosTheta*cosTheta;
697 G4double diffCS = ECOE*ECOE*XKN*sia;
714 const G4int npoints=10;
715 const G4int ncallsmax=20000;
717 static const G4double Abscissas[10] = {7.652651133497334e-02,2.2778585114164508e-01,3.7370608871541956e-01,
718 5.1086700195082710e-01,6.3605368072651503e-01,7.4633190646015079e-01,
719 8.3911697182221882e-01,9.1223442825132591e-01,9.6397192727791379e-01,
720 9.9312859918509492e-01};
721 static const G4double Weights[10] = {1.5275338713072585e-01,1.4917298647260375e-01,1.4209610931838205e-01,
722 1.3168863844917663e-01,1.1819453196151842e-01,1.0193011981724044e-01,
723 8.3276741576704749e-02,6.2672048334109064e-02,4.0601429800386941e-02,
724 1.7614007139152118e-02};
728 G4double Ctol = std::min(std::max(MaxError,1e-13),1e-02);
738 G4double a=0.5*(HighPoint-LowPoint);
739 G4double b=0.5*(HighPoint+LowPoint);
742 (DifferentialCrossSection(b+c,energy,osc)+DifferentialCrossSection(b-c,energy,osc));
743 for (
G4int i=2;i<=npoints;i++)
747 (DifferentialCrossSection(b+c,energy,osc)+DifferentialCrossSection(b-c,energy,osc));
749 G4int icall = 2*npoints;
764 for (
G4int i=1;i<=LH;i++){
773 (DifferentialCrossSection(b+c,energy,osc)+DifferentialCrossSection(b-c,energy,osc));
775 for (
G4int j=1;j<npoints;j++)
778 dLocal += Weights[j]*
779 (DifferentialCrossSection(b+c,energy,osc)+DifferentialCrossSection(b-c,energy,osc));
786 (DifferentialCrossSection(b+c,energy,osc)+DifferentialCrossSection(b-c,energy,osc));
788 for (
G4int j=1;j<npoints;j++)
791 dLocal += Weights[j]*
792 (DifferentialCrossSection(b+c,energy,osc)+DifferentialCrossSection(b-c,energy,osc));
795 icall=icall+4*npoints;
797 if (std::abs(s12-si)<std::max(Ptol*std::abs(s12),1e-35))
809 if (icall>ncallsmax || LHN>nst)
812 G4cout <<
"LowPoint: " << LowPoint <<
", High Point: " << HighPoint <<
G4endl;
814 G4cout <<
"Calls: " << icall <<
", Integral: " << sumga <<
", Error: " << Err <<
G4endl;
815 G4cout <<
"Number of open subintervals: " << LHN <<
G4endl;
816 G4cout <<
"WARNING: the required accuracy has not been attained" <<
G4endl;
820 Err=std::abs(sumr)/std::max(std::abs(sumr+sumga),1e-35);
821 if (Err < Ctol || LHN == 0)
824 for (
G4int i=0;i<LH;i++)
829 }
while(Ctol < 1.0 && loopAgain);
855 for (
size_t i=0;i<theTable->size();i++)
862 G4double csu = 0.5*eks*tau*tau+ek2*tau+ek1*
G4Log(tau)-(1.0/tau);
865 cs += stre*(csu-csl);
G4double epsilon(G4double density, G4double temperature)
G4double S(G4double temp)
void G4Exception(const char *originOfException, const char *exceptionCode, G4ExceptionSeverity severity, const char *description)
std::ostringstream G4ExceptionDescription
G4double G4Exp(G4double initial_x)
Exponential Function double precision.
G4double G4Log(G4double x)
std::vector< G4PenelopeOscillator * > G4PenelopeOscillatorTable
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
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(const G4ThreeVector &Pfinal)
virtual ~G4PenelopeComptonModel()
G4ParticleChangeForGamma * fParticleChange
void SampleSecondaries(std::vector< G4DynamicParticle * > *, const G4MaterialCutsCouple *, const G4DynamicParticle *, G4double tmin, G4double maxEnergy) override
const G4ParticleDefinition * fParticle
G4PenelopeComptonModel(const G4ParticleDefinition *p=nullptr, const G4String &processName="PenCompton")
G4double ComputeCrossSectionPerAtom(const G4ParticleDefinition *, G4double, G4double, G4double, G4double, G4double) override
G4double CrossSectionPerVolume(const G4Material *, const G4ParticleDefinition *, G4double kineticEnergy, G4double cutEnergy=0.0, G4double maxEnergy=DBL_MAX) override
void InitialiseLocal(const G4ParticleDefinition *, G4VEmModel *masterModel) override
void Initialise(const G4ParticleDefinition *, const G4DataVector &) override
G4double GetAtomsPerMolecule(const G4Material *)
Returns the total number of atoms per molecule.
G4PenelopeOscillatorTable * GetOscillatorTableCompton(const G4Material *)
static G4PenelopeOscillatorManager * GetOscillatorManager()
G4double GetTotalZ(const G4Material *)
G4double GetIonisationEnergy()
G4double GetHartreeFactor()
G4double GetOscillatorStrength()
G4bool CheckDeexcitationActiveRegion(G4int coupleIndex)
void GenerateParticles(std::vector< G4DynamicParticle * > *secVect, const G4AtomicShell *, G4int Z, G4int coupleIndex)
void SetHighEnergyLimit(G4double)
G4ParticleChangeForGamma * GetParticleChangeForGamma()
G4double LowEnergyLimit() const
G4double HighEnergyLimit() const
virtual void SetupForMaterial(const G4ParticleDefinition *, const G4Material *, G4double kineticEnergy)
void SetDeexcitationFlag(G4bool val)
void ProposeTrackStatus(G4TrackStatus status)
void ProposeLocalEnergyDeposit(G4double anEnergyPart)
G4double energy(const ThreeVector &p, const G4double m)