Geant4  9.6.p02
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
G4PenelopeIonisationModel.cc
Go to the documentation of this file.
1 //
2 // ********************************************************************
3 // * License and Disclaimer *
4 // * *
5 // * The Geant4 software is copyright of the Copyright Holders of *
6 // * the Geant4 Collaboration. It is provided under the terms and *
7 // * conditions of the Geant4 Software License, included in the file *
8 // * LICENSE and available at http://cern.ch/geant4/license . These *
9 // * include a list of copyright holders. *
10 // * *
11 // * Neither the authors of this software system, nor their employing *
12 // * institutes,nor the agencies providing financial support for this *
13 // * work make any representation or warranty, express or implied, *
14 // * regarding this software system or assume any liability for its *
15 // * use. Please see the license in the file LICENSE and URL above *
16 // * for the full disclaimer and the limitation of liability. *
17 // * *
18 // * This code implementation is the result of the scientific and *
19 // * technical work of the GEANT4 collaboration. *
20 // * By using, copying, modifying or distributing the software (or *
21 // * any work based on the software) you agree to acknowledge its *
22 // * use in resulting scientific publications, and indicate your *
23 // * acceptance of all terms of the Geant4 Software license. *
24 // ********************************************************************
25 //
26 // $Id$
27 //
28 // Author: Luciano Pandola
29 //
30 // History:
31 // --------
32 // 27 Jul 2010 L Pandola First complete implementation
33 // 18 Jan 2011 L.Pandola Stricter check on production of sub-treshold delta-rays.
34 // Should never happen now
35 // 01 Feb 2011 L Pandola Suppress fake energy-violation warning when Auger is active.
36 // Make sure that fluorescence/Auger is generated only if
37 // above threshold
38 // 25 May 2011 L Pandola Renamed (make v2008 as default Penelope)
39 // 26 Jan 2012 L Pandola Migration of AtomicDeexcitation to the new interface
40 // 09 Mar 2012 L Pandola Moved the management and calculation of
41 // cross sections to a separate class. Use a different method to
42 // get normalized shell cross sections
43 //
44 //
45 
47 #include "G4PhysicalConstants.hh"
48 #include "G4SystemOfUnits.hh"
49 #include "G4ParticleDefinition.hh"
50 #include "G4MaterialCutsCouple.hh"
51 #include "G4ProductionCutsTable.hh"
52 #include "G4DynamicParticle.hh"
54 #include "G4AtomicShell.hh"
55 #include "G4Gamma.hh"
56 #include "G4Electron.hh"
57 #include "G4Positron.hh"
58 #include "G4AtomicDeexcitation.hh"
60 #include "G4PenelopeOscillator.hh"
62 #include "G4PhysicsFreeVector.hh"
63 #include "G4PhysicsLogVector.hh"
64 #include "G4LossTableManager.hh"
66 
67 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
68 
69 
71  const G4String& nam)
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)
77 {
78  fIntrinsicLowEnergyLimit = 100.0*eV;
79  fIntrinsicHighEnergyLimit = 100.0*GeV;
80  // SetLowEnergyLimit(fIntrinsicLowEnergyLimit);
81  SetHighEnergyLimit(fIntrinsicHighEnergyLimit);
82  nBins = 200;
83  //
85  //
86  verboseLevel= 0;
87 
88  // Verbosity scale:
89  // 0 = nothing
90  // 1 = warning for energy non-conservation
91  // 2 = details of energy budget
92  // 3 = calculation of cross sections, file openings, sampling of atoms
93  // 4 = entering in methods
94 
95  // Atomic deexcitation model activated by default
96  SetDeexcitationFlag(true);
97 }
98 
99 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
100 
102 {
103  if (theCrossSectionHandler)
104  delete theCrossSectionHandler;
105 }
106 
107 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
108 
110  const G4DataVector&)
111 {
112  if (verboseLevel > 3)
113  G4cout << "Calling G4PenelopeIonisationModel::Initialise()" << G4endl;
114 
115  fAtomDeexcitation = G4LossTableManager::Instance()->AtomDeexcitation();
116  //Issue warning if the AtomicDeexcitation has not been declared
117  if (!fAtomDeexcitation)
118  {
119  G4cout << G4endl;
120  G4cout << "WARNING from G4PenelopeIonisationModel " << G4endl;
121  G4cout << "Atomic de-excitation module is not instantiated, so there will not be ";
122  G4cout << "any fluorescence/Auger emission." << G4endl;
123  G4cout << "Please make sure this is intended" << G4endl;
124  }
125 
126  //Set the number of bins for the tables. 20 points per decade
127  nBins = (size_t) (20*std::log10(HighEnergyLimit()/LowEnergyLimit()));
128  nBins = std::max(nBins,(size_t)100);
129 
130  //Clear and re-build the tables
131  if (theCrossSectionHandler)
132  {
133  delete theCrossSectionHandler;
134  theCrossSectionHandler = 0;
135  }
136  theCrossSectionHandler = new G4PenelopeIonisationXSHandler(nBins);
137  theCrossSectionHandler->SetVerboseLevel(verboseLevel);
138 
139  if (verboseLevel > 2) {
140  G4cout << "Penelope Ionisation model v2008 is initialized " << G4endl
141  << "Energy range: "
142  << LowEnergyLimit() / keV << " keV - "
143  << HighEnergyLimit() / GeV << " GeV. Using "
144  << nBins << " bins."
145  << G4endl;
146  }
147 
148  if(isInitialised) return;
150  isInitialised = true;
151 }
152 
153 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
154 
156  const G4ParticleDefinition*
157  theParticle,
159  G4double cutEnergy,
160  G4double)
161 {
162  // Penelope model v2008 to calculate the cross section for inelastic collisions above the
163  // threshold. It makes use of the Generalised Oscillator Strength (GOS) model from
164  // D. Liljequist, J. Phys. D: Appl. Phys. 16 (1983) 1567
165  //
166  // The total cross section is calculated analytically by taking
167  // into account the atomic oscillators coming into the play for a given threshold.
168  //
169  // For incident e- the maximum energy allowed for the delta-rays is energy/2.
170  // because particles are undistinghishable.
171  //
172  // The contribution is splitted in three parts: distant longitudinal collisions,
173  // distant transverse collisions and close collisions. Each term is described by
174  // its own analytical function.
175  // Fermi density correction is calculated analytically according to
176  // U. Fano, Ann. Rev. Nucl. Sci. 13 (1963),1
177  //
178  if (verboseLevel > 3)
179  G4cout << "Calling CrossSectionPerVolume() of G4PenelopeIonisationModel" << G4endl;
180 
181  SetupForMaterial(theParticle, material, energy);
182 
183  G4double totalCross = 0.0;
184  G4double crossPerMolecule = 0.;
185 
186  G4PenelopeCrossSection* theXS =
187  theCrossSectionHandler->GetCrossSectionTableForCouple(theParticle,
188  material,
189  cutEnergy);
190 
191  if (theXS)
192  crossPerMolecule = theXS->GetHardCrossSection(energy);
193 
194  G4double atomDensity = material->GetTotNbOfAtomsPerVolume();
195  G4double atPerMol = oscManager->GetAtomsPerMolecule(material);
196 
197  if (verboseLevel > 3)
198  G4cout << "Material " << material->GetName() << " has " << atPerMol <<
199  "atoms per molecule" << G4endl;
200 
201  G4double moleculeDensity = 0.;
202  if (atPerMol)
203  moleculeDensity = atomDensity/atPerMol;
204 
205  G4double crossPerVolume = crossPerMolecule*moleculeDensity;
206 
207  if (verboseLevel > 2)
208  {
209  G4cout << "G4PenelopeIonisationModel " << G4endl;
210  G4cout << "Mean free path for delta emission > " << cutEnergy/keV << " keV at " <<
211  energy/keV << " keV = " << (1./crossPerVolume)/mm << " mm" << G4endl;
212  if (theXS)
213  totalCross = (theXS->GetTotalCrossSection(energy))*moleculeDensity;
214  G4cout << "Total free path for ionisation (no threshold) at " <<
215  energy/keV << " keV = " << (1./totalCross)/mm << " mm" << G4endl;
216  }
217  return crossPerVolume;
218 }
219 
220 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
221 
222 //This is a dummy method. Never inkoved by the tracking, it just issues
223 //a warning if one tries to get Cross Sections per Atom via the
224 //G4EmCalculator.
226  G4double,
227  G4double,
228  G4double,
229  G4double,
230  G4double)
231 {
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;
236  return 0;
237 }
238 
239 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
240 
242  const G4ParticleDefinition* theParticle,
243  G4double kineticEnergy,
244  G4double cutEnergy)
245 {
246  // Penelope model v2008 to calculate the stopping power for soft inelastic collisions
247  // below the threshold. It makes use of the Generalised Oscillator Strength (GOS)
248  // model from
249  // D. Liljequist, J. Phys. D: Appl. Phys. 16 (1983) 1567
250  //
251  // The stopping power is calculated analytically using the dsigma/dW cross
252  // section from the GOS models, which includes separate contributions from
253  // distant longitudinal collisions, distant transverse collisions and
254  // close collisions. Only the atomic oscillators that come in the play
255  // (according to the threshold) are considered for the calculation.
256  // Differential cross sections have a different form for e+ and e-.
257  //
258  // Fermi density correction is calculated analytically according to
259  // U. Fano, Ann. Rev. Nucl. Sci. 13 (1963),1
260 
261  if (verboseLevel > 3)
262  G4cout << "Calling ComputeDEDX() of G4PenelopeIonisationModel" << G4endl;
263 
264 
265  G4PenelopeCrossSection* theXS =
266  theCrossSectionHandler->GetCrossSectionTableForCouple(theParticle,material,
267  cutEnergy);
268  G4double sPowerPerMolecule = 0.0;
269  if (theXS)
270  sPowerPerMolecule = theXS->GetSoftStoppingPower(kineticEnergy);
271 
272 
273  G4double atomDensity = material->GetTotNbOfAtomsPerVolume();
274  G4double atPerMol = oscManager->GetAtomsPerMolecule(material);
275 
276  G4double moleculeDensity = 0.;
277  if (atPerMol)
278  moleculeDensity = atomDensity/atPerMol;
279 
280  G4double sPowerPerVolume = sPowerPerMolecule*moleculeDensity;
281 
282  if (verboseLevel > 2)
283  {
284  G4cout << "G4PenelopeIonisationModel " << G4endl;
285  G4cout << "Stopping power < " << cutEnergy/keV << " keV at " <<
286  kineticEnergy/keV << " keV = " <<
287  sPowerPerVolume/(keV/mm) << " keV/mm" << G4endl;
288  }
289  return sPowerPerVolume;
290 }
291 
292 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
293 
295  const G4MaterialCutsCouple*)
296 {
297  return fIntrinsicLowEnergyLimit;
298 }
299 
300 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
301 
302 void G4PenelopeIonisationModel::SampleSecondaries(std::vector<G4DynamicParticle*>* fvect,
303  const G4MaterialCutsCouple* couple,
304  const G4DynamicParticle* aDynamicParticle,
305  G4double cutE, G4double)
306 {
307  // Penelope model v2008 to sample the final state following an hard inelastic interaction.
308  // It makes use of the Generalised Oscillator Strength (GOS) model from
309  // D. Liljequist, J. Phys. D: Appl. Phys. 16 (1983) 1567
310  //
311  // The GOS model is used to calculate the individual cross sections for all
312  // the atomic oscillators coming in the play, taking into account the three
313  // contributions (distant longitudinal collisions, distant transverse collisions and
314  // close collisions). Then the target shell and the interaction channel are
315  // sampled. Final state of the delta-ray (energy, angle) are generated according
316  // to the analytical distributions (dSigma/dW) for the selected interaction
317  // channels.
318  // For e-, the maximum energy for the delta-ray is initialEnergy/2. (because
319  // particles are indistinghusbable), while it is the full initialEnergy for
320  // e+.
321  // The efficiency of the random sampling algorithm (e.g. for close collisions)
322  // decreases when initial and cutoff energy increase (e.g. 87% for 10-keV primary
323  // and 1 keV threshold, 99% for 10-MeV primary and 10-keV threshold).
324  // Differential cross sections have a different form for e+ and e-.
325  //
326  // WARNING: The model provides an _average_ description of inelastic collisions.
327  // Anyway, the energy spectrum associated to distant excitations of a given
328  // atomic shell is approximated as a single resonance. The simulated energy spectra
329  // show _unphysical_ narrow peaks at energies that are multiple of the shell
330  // resonance energies. The spurious speaks are automatically smoothed out after
331  // multiple inelastic collisions.
332  //
333  // The model determines also the original shell from which the delta-ray is expelled,
334  // in order to produce fluorescence de-excitation (from G4DeexcitationManager)
335  //
336  // Fermi density correction is calculated analytically according to
337  // U. Fano, Ann. Rev. Nucl. Sci. 13 (1963),1
338 
339  if (verboseLevel > 3)
340  G4cout << "Calling SamplingSecondaries() of G4PenelopeIonisationModel" << G4endl;
341 
342  G4double kineticEnergy0 = aDynamicParticle->GetKineticEnergy();
343  const G4ParticleDefinition* theParticle = aDynamicParticle->GetDefinition();
344 
345  if (kineticEnergy0 <= fIntrinsicLowEnergyLimit)
346  {
349  return ;
350  }
351 
352  const G4Material* material = couple->GetMaterial();
353  G4PenelopeOscillatorTable* theTable = oscManager->GetOscillatorTableIonisation(material);
354 
355  G4ParticleMomentum particleDirection0 = aDynamicParticle->GetMomentumDirection();
356 
357  //Initialise final-state variables. The proper values will be set by the methods
358  // SampleFinalStateElectron() and SampleFinalStatePositron()
359  kineticEnergy1=kineticEnergy0;
360  cosThetaPrimary=1.0;
361  energySecondary=0.0;
362  cosThetaSecondary=1.0;
363  targetOscillator = -1;
364 
365  if (theParticle == G4Electron::Electron())
366  SampleFinalStateElectron(material,cutE,kineticEnergy0);
367  else if (theParticle == G4Positron::Positron())
368  SampleFinalStatePositron(material,cutE,kineticEnergy0);
369  else
370  {
372  ed << "Invalid particle " << theParticle->GetParticleName() << G4endl;
373  G4Exception("G4PenelopeIonisationModel::SamplingSecondaries()",
374  "em0001",FatalException,ed);
375 
376  }
377  if (energySecondary == 0) return;
378 
379  if (verboseLevel > 3)
380  {
381  G4cout << "G4PenelopeIonisationModel::SamplingSecondaries() for " <<
382  theParticle->GetParticleName() << G4endl;
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;
387  G4cout << "Oscillator: " << targetOscillator << G4endl;
388  }
389 
390  //Update the primary particle
391  G4double sint = std::sqrt(1. - cosThetaPrimary*cosThetaPrimary);
392  G4double phiPrimary = twopi * G4UniformRand();
393  G4double dirx = sint * std::cos(phiPrimary);
394  G4double diry = sint * std::sin(phiPrimary);
395  G4double dirz = cosThetaPrimary;
396 
397  G4ThreeVector electronDirection1(dirx,diry,dirz);
398  electronDirection1.rotateUz(particleDirection0);
399 
400  if (kineticEnergy1 > 0)
401  {
402  fParticleChange->ProposeMomentumDirection(electronDirection1);
403  fParticleChange->SetProposedKineticEnergy(kineticEnergy1);
404  }
405  else
407 
408 
409  //Generate the delta ray
410  G4double ionEnergyInPenelopeDatabase =
411  (*theTable)[targetOscillator]->GetIonisationEnergy();
412 
413  //Now, try to handle fluorescence
414  //Notice: merged levels are indicated with Z=0 and flag=30
415  G4int shFlag = (*theTable)[targetOscillator]->GetShellFlag();
416  G4int Z = (G4int) (*theTable)[targetOscillator]->GetParentZ();
417 
418  //initialize here, then check photons created by Atomic-Deexcitation, and the final state e-
421  //G4int shellId = 0;
422 
423  const G4AtomicShell* shell = 0;
424  //Real level
425  if (Z > 0 && shFlag<30)
426  {
427  shell = transitionManager->Shell(Z,shFlag-1);
428  bindingEnergy = shell->BindingEnergy();
429  //shellId = shell->ShellId();
430  }
431 
432  //correct the energySecondary to account for the fact that the Penelope
433  //database of ionisation energies is in general (slightly) different
434  //from the fluorescence database used in Geant4.
435  energySecondary += ionEnergyInPenelopeDatabase-bindingEnergy;
436 
437  G4double localEnergyDeposit = bindingEnergy;
438  //testing purposes only
439  G4double energyInFluorescence = 0;
440  G4double energyInAuger = 0;
441 
442  if (energySecondary < 0)
443  {
444  //It means that there was some problem/mismatch between the two databases.
445  //In this case, the available energy is ok to excite the level according
446  //to the Penelope database, but not according to the Geant4 database
447  //Full residual energy is deposited locally
448  localEnergyDeposit += energySecondary;
449  energySecondary = 0.0;
450  }
451 
452  //Notice: shell might be NULL (invalid!) if shFlag=30. Must be protected
453  //Now, take care of fluorescence, if required
454  if (fAtomDeexcitation && shell)
455  {
456  G4int index = couple->GetIndex();
457  if (fAtomDeexcitation->CheckDeexcitationActiveRegion(index))
458  {
459  size_t nBefore = fvect->size();
460  fAtomDeexcitation->GenerateParticles(fvect,shell,Z,index);
461  size_t nAfter = fvect->size();
462 
463  if (nAfter > nBefore) //actual production of fluorescence
464  {
465  for (size_t j=nBefore;j<nAfter;j++) //loop on products
466  {
467  G4double itsEnergy = ((*fvect)[j])->GetKineticEnergy();
468  localEnergyDeposit -= itsEnergy;
469  if (((*fvect)[j])->GetParticleDefinition() == G4Gamma::Definition())
470  energyInFluorescence += itsEnergy;
471  else if (((*fvect)[j])->GetParticleDefinition() == G4Electron::Definition())
472  energyInAuger += itsEnergy;
473  }
474  }
475  }
476  }
477 
478  // Generate the delta ray --> to be done only if above cut
479  if (energySecondary > cutE)
480  {
481  G4DynamicParticle* electron = 0;
482  G4double sinThetaE = std::sqrt(1.-cosThetaSecondary*cosThetaSecondary);
483  G4double phiEl = phiPrimary+pi; //pi with respect to the primary electron/positron
484  G4double xEl = sinThetaE * std::cos(phiEl);
485  G4double yEl = sinThetaE * std::sin(phiEl);
486  G4double zEl = cosThetaSecondary;
487  G4ThreeVector eDirection(xEl,yEl,zEl); //electron direction
488  eDirection.rotateUz(particleDirection0);
489  electron = new G4DynamicParticle (G4Electron::Electron(),
490  eDirection,energySecondary) ;
491  fvect->push_back(electron);
492  }
493  else
494  {
495  localEnergyDeposit += energySecondary;
496  energySecondary = 0;
497  }
498 
499  if (localEnergyDeposit < 0)
500  {
501  G4cout << "WARNING-"
502  << "G4PenelopeIonisationModel::SampleSecondaries - Negative energy deposit"
503  << G4endl;
504  localEnergyDeposit=0.;
505  }
506  fParticleChange->ProposeLocalEnergyDeposit(localEnergyDeposit);
507 
508  if (verboseLevel > 1)
509  {
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;
518  if (energyInAuger)
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 <<
523  " keV" << G4endl;
524  G4cout << "-----------------------------------------------------------" << G4endl;
525  }
526 
527  if (verboseLevel > 0)
528  {
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;
536  }
537 
538 }
539 
540 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
541 void G4PenelopeIonisationModel::SampleFinalStateElectron(const G4Material* mat,
542  G4double cutEnergy,
543  G4double kineticEnergy)
544 {
545  // This method sets the final ionisation parameters
546  // kineticEnergy1, cosThetaPrimary (= updates of the primary e-)
547  // energySecondary, cosThetaSecondary (= info of delta-ray)
548  // targetOscillator (= ionised oscillator)
549  //
550  // The method implements SUBROUTINE EINa of Penelope
551  //
552 
553  G4PenelopeOscillatorTable* theTable = oscManager->GetOscillatorTableIonisation(mat);
554  size_t numberOfOscillators = theTable->size();
555  G4PenelopeCrossSection* theXS =
556  theCrossSectionHandler->GetCrossSectionTableForCouple(G4Electron::Electron(),mat,
557  cutEnergy);
558  G4double delta = theCrossSectionHandler->GetDensityCorrection(mat,kineticEnergy);
559 
560  // Selection of the active oscillator
561  G4double TST = G4UniformRand();
562  targetOscillator = numberOfOscillators-1; //initialization, last oscillator
563  G4double XSsum = 0.;
564 
565  for (size_t i=0;i<numberOfOscillators-1;i++)
566  {
567  /* testing purposes
568  G4cout << "sampling: " << i << " " << XSsum << " " << TST << " " <<
569  theXS->GetShellCrossSection(i,kineticEnergy) << " " <<
570  theXS->GetNormalizedShellCrossSection(i,kineticEnergy) << " " <<
571  mat->GetName() << G4endl;
572  */
573  XSsum += theXS->GetNormalizedShellCrossSection(i,kineticEnergy);
574 
575  if (XSsum > TST)
576  {
577  targetOscillator = (G4int) i;
578  break;
579  }
580  }
581 
582 
583  if (verboseLevel > 3)
584  {
585  G4cout << "SampleFinalStateElectron: sampled oscillator #" << targetOscillator << "." << G4endl;
586  G4cout << "Ionisation energy: " << (*theTable)[targetOscillator]->GetIonisationEnergy()/eV <<
587  " eV " << G4endl;
588  G4cout << "Resonance energy: : " << (*theTable)[targetOscillator]->GetResonanceEnergy()/eV << " eV "
589  << G4endl;
590  }
591  //Constants
592  G4double rb = kineticEnergy + 2.0*electron_mass_c2;
593  G4double gam = 1.0+kineticEnergy/electron_mass_c2;
594  G4double gam2 = gam*gam;
595  G4double beta2 = (gam2-1.0)/gam2;
596  G4double amol = ((gam-1.0)/gam)*((gam-1.0)/gam);
597 
598  //Partial cross section of the active oscillator
599  G4double resEne = (*theTable)[targetOscillator]->GetResonanceEnergy();
600  G4double invResEne = 1.0/resEne;
601  G4double ionEne = (*theTable)[targetOscillator]->GetIonisationEnergy();
602  G4double cutoffEne = (*theTable)[targetOscillator]->GetCutoffRecoilResonantEnergy();
603  G4double XHDL = 0.;
604  G4double XHDT = 0.;
605  G4double QM = 0.;
606  G4double cps = 0.;
607  G4double cp = 0.;
608 
609  //Distant excitations
610  if (resEne > cutEnergy && resEne < kineticEnergy)
611  {
612  cps = kineticEnergy*rb;
613  cp = std::sqrt(cps);
614  G4double XHDT0 = std::max(std::log(gam2)-beta2-delta,0.);
615  if (resEne > 1.0e-6*kineticEnergy)
616  {
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;
619  }
620  else
621  {
622  QM = resEne*resEne/(beta2*2.0*electron_mass_c2);
623  QM *= (1.0-QM*0.5/electron_mass_c2);
624  }
625  if (QM < cutoffEne)
626  {
627  XHDL = std::log(cutoffEne*(QM+2.0*electron_mass_c2)/(QM*(cutoffEne+2.0*electron_mass_c2)))
628  *invResEne;
629  XHDT = XHDT0*invResEne;
630  }
631  else
632  {
633  QM = cutoffEne;
634  XHDL = 0.;
635  XHDT = 0.;
636  }
637  }
638  else
639  {
640  QM = cutoffEne;
641  cps = 0.;
642  cp = 0.;
643  XHDL = 0.;
644  XHDT = 0.;
645  }
646 
647  //Close collisions
648  G4double EE = kineticEnergy + ionEne;
649  G4double wmaxc = 0.5*EE;
650  G4double wcl = std::max(cutEnergy,cutoffEne);
651  G4double rcl = wcl/EE;
652  G4double XHC = 0.;
653  if (wcl < wmaxc)
654  {
655  G4double rl1 = 1.0-rcl;
656  G4double rrl1 = 1.0/rl1;
657  XHC = (amol*(0.5-rcl)+1.0/rcl-rrl1+
658  (1.0-amol)*std::log(rcl*rrl1))/EE;
659  }
660 
661  //Total cross section per molecule for the active shell, in cm2
662  G4double XHTOT = XHC + XHDL + XHDT;
663 
664  //very small cross section, do nothing
665  if (XHTOT < 1.e-14*barn)
666  {
667  kineticEnergy1=kineticEnergy;
668  cosThetaPrimary=1.0;
669  energySecondary=0.0;
670  cosThetaSecondary=1.0;
671  targetOscillator = numberOfOscillators-1;
672  return;
673  }
674 
675  //decide which kind of interaction we'll have
676  TST = XHTOT*G4UniformRand();
677 
678 
679  // Hard close collision
680  G4double TS1 = XHC;
681 
682  if (TST < TS1)
683  {
684  G4double A = 5.0*amol;
685  G4double ARCL = A*0.5*rcl;
686  G4double rk=0.;
687  G4bool loopAgain = false;
688  do
689  {
690  loopAgain = false;
691  G4double fb = (1.0+ARCL)*G4UniformRand();
692  if (fb < 1)
693  rk = rcl/(1.0-fb*(1.0-(rcl+rcl)));
694  else
695  rk = rcl + (fb-1.0)*(0.5-rcl)/ARCL;
696  G4double rk2 = rk*rk;
697  G4double rkf = rk/(1.0-rk);
698  G4double phi = 1.0+rkf*rkf-rkf+amol*(rk2+rkf);
699  if (G4UniformRand()*(1.0+A*rk2) > phi)
700  loopAgain = true;
701  }while(loopAgain);
702  //energy and scattering angle (primary electron)
703  G4double deltaE = rk*EE;
704 
705  kineticEnergy1 = kineticEnergy - deltaE;
706  cosThetaPrimary = std::sqrt(kineticEnergy1*rb/(kineticEnergy*(rb-deltaE)));
707  //energy and scattering angle of the delta ray
708  energySecondary = deltaE - ionEne; //subtract ionisation energy
709  cosThetaSecondary= std::sqrt(deltaE*rb/(kineticEnergy*(deltaE+2.0*electron_mass_c2)));
710  if (verboseLevel > 3)
711  G4cout << "SampleFinalStateElectron: sampled close collision " << G4endl;
712  return;
713  }
714 
715  //Hard distant longitudinal collisions
716  TS1 += XHDL;
717  G4double deltaE = resEne;
718  kineticEnergy1 = kineticEnergy - deltaE;
719 
720  if (TST < TS1)
721  {
722  G4double QS = QM/(1.0+QM*0.5/electron_mass_c2);
723  G4double Q = QS/(std::pow((QS/cutoffEne)*(1.0+cutoffEne*0.5/electron_mass_c2),G4UniformRand())
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;
730  //energy and emission angle of the delta ray
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;
737  return;
738  }
739 
740  //Hard distant transverse collisions
741  cosThetaPrimary = 1.0;
742  //energy and emission angle of the delta ray
743  energySecondary = deltaE - ionEne;
744  cosThetaSecondary = 0.5;
745  if (verboseLevel > 3)
746  G4cout << "SampleFinalStateElectron: sampled distant transverse collision " << G4endl;
747 
748  return;
749 }
750 
751 
752 
753 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
754 void G4PenelopeIonisationModel::SampleFinalStatePositron(const G4Material* mat,
755  G4double cutEnergy,
756  G4double kineticEnergy)
757 {
758  // This method sets the final ionisation parameters
759  // kineticEnergy1, cosThetaPrimary (= updates of the primary e-)
760  // energySecondary, cosThetaSecondary (= info of delta-ray)
761  // targetOscillator (= ionised oscillator)
762  //
763  // The method implements SUBROUTINE PINa of Penelope
764  //
765 
766  G4PenelopeOscillatorTable* theTable = oscManager->GetOscillatorTableIonisation(mat);
767  size_t numberOfOscillators = theTable->size();
768  G4PenelopeCrossSection* theXS = theCrossSectionHandler->GetCrossSectionTableForCouple(G4Positron::Positron(),mat,
769  cutEnergy);
770  G4double delta = theCrossSectionHandler->GetDensityCorrection(mat,kineticEnergy);
771 
772  // Selection of the active oscillator
773  G4double TST = G4UniformRand();
774  targetOscillator = numberOfOscillators-1; //initialization, last oscillator
775  G4double XSsum = 0.;
776  for (size_t i=0;i<numberOfOscillators-1;i++)
777  {
778  XSsum += theXS->GetNormalizedShellCrossSection(i,kineticEnergy);
779  if (XSsum > TST)
780  {
781  targetOscillator = (G4int) i;
782  break;
783  }
784  }
785 
786  if (verboseLevel > 3)
787  {
788  G4cout << "SampleFinalStatePositron: sampled oscillator #" << targetOscillator << "." << G4endl;
789  G4cout << "Ionisation energy: " << (*theTable)[targetOscillator]->GetIonisationEnergy()/eV
790  << " eV " << G4endl;
791  G4cout << "Resonance energy: : " << (*theTable)[targetOscillator]->GetResonanceEnergy()/eV
792  << " eV " << G4endl;
793  }
794 
795  //Constants
796  G4double rb = kineticEnergy + 2.0*electron_mass_c2;
797  G4double gam = 1.0+kineticEnergy/electron_mass_c2;
798  G4double gam2 = gam*gam;
799  G4double beta2 = (gam2-1.0)/gam2;
800  G4double g12 = (gam+1.0)*(gam+1.0);
801  G4double amol = ((gam-1.0)/gam)*((gam-1.0)/gam);
802  //Bhabha coefficients
803  G4double bha1 = amol*(2.0*g12-1.0)/(gam2-1.0);
804  G4double bha2 = amol*(3.0+1.0/g12);
805  G4double bha3 = amol*2.0*gam*(gam-1.0)/g12;
806  G4double bha4 = amol*(gam-1.0)*(gam-1.0)/g12;
807 
808  //
809  //Partial cross section of the active oscillator
810  //
811  G4double resEne = (*theTable)[targetOscillator]->GetResonanceEnergy();
812  G4double invResEne = 1.0/resEne;
813  G4double ionEne = (*theTable)[targetOscillator]->GetIonisationEnergy();
814  G4double cutoffEne = (*theTable)[targetOscillator]->GetCutoffRecoilResonantEnergy();
815 
816  G4double XHDL = 0.;
817  G4double XHDT = 0.;
818  G4double QM = 0.;
819  G4double cps = 0.;
820  G4double cp = 0.;
821 
822  //Distant excitations XS (same as for electrons)
823  if (resEne > cutEnergy && resEne < kineticEnergy)
824  {
825  cps = kineticEnergy*rb;
826  cp = std::sqrt(cps);
827  G4double XHDT0 = std::max(std::log(gam2)-beta2-delta,0.);
828  if (resEne > 1.0e-6*kineticEnergy)
829  {
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;
832  }
833  else
834  {
835  QM = resEne*resEne/(beta2*2.0*electron_mass_c2);
836  QM *= (1.0-QM*0.5/electron_mass_c2);
837  }
838  if (QM < cutoffEne)
839  {
840  XHDL = std::log(cutoffEne*(QM+2.0*electron_mass_c2)/(QM*(cutoffEne+2.0*electron_mass_c2)))
841  *invResEne;
842  XHDT = XHDT0*invResEne;
843  }
844  else
845  {
846  QM = cutoffEne;
847  XHDL = 0.;
848  XHDT = 0.;
849  }
850  }
851  else
852  {
853  QM = cutoffEne;
854  cps = 0.;
855  cp = 0.;
856  XHDL = 0.;
857  XHDT = 0.;
858  }
859  //Close collisions (Bhabha)
860  G4double wmaxc = kineticEnergy;
861  G4double wcl = std::max(cutEnergy,cutoffEne);
862  G4double rcl = wcl/kineticEnergy;
863  G4double XHC = 0.;
864  if (wcl < wmaxc)
865  {
866  G4double rl1 = 1.0-rcl;
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;
870  }
871 
872  //Total cross section per molecule for the active shell, in cm2
873  G4double XHTOT = XHC + XHDL + XHDT;
874 
875  //very small cross section, do nothing
876  if (XHTOT < 1.e-14*barn)
877  {
878  kineticEnergy1=kineticEnergy;
879  cosThetaPrimary=1.0;
880  energySecondary=0.0;
881  cosThetaSecondary=1.0;
882  targetOscillator = numberOfOscillators-1;
883  return;
884  }
885 
886  //decide which kind of interaction we'll have
887  TST = XHTOT*G4UniformRand();
888 
889  // Hard close collision
890  G4double TS1 = XHC;
891  if (TST < TS1)
892  {
893  G4double rl1 = 1.0-rcl;
894  G4double rk=0.;
895  G4bool loopAgain = false;
896  do
897  {
898  loopAgain = false;
899  rk = rcl/(1.0-G4UniformRand()*rl1);
900  G4double phi = 1.0-rk*(bha1-rk*(bha2-rk*(bha3-bha4*rk)));
901  if (G4UniformRand() > phi)
902  loopAgain = true;
903  }while(loopAgain);
904  //energy and scattering angle (primary electron)
905  G4double deltaE = rk*kineticEnergy;
906  kineticEnergy1 = kineticEnergy - deltaE;
907  cosThetaPrimary = std::sqrt(kineticEnergy1*rb/(kineticEnergy*(rb-deltaE)));
908  //energy and scattering angle of the delta ray
909  energySecondary = deltaE - ionEne; //subtract ionisation energy
910  cosThetaSecondary= std::sqrt(deltaE*rb/(kineticEnergy*(deltaE+2.0*electron_mass_c2)));
911  if (verboseLevel > 3)
912  G4cout << "SampleFinalStatePositron: sampled close collision " << G4endl;
913  return;
914  }
915 
916  //Hard distant longitudinal collisions
917  TS1 += XHDL;
918  G4double deltaE = resEne;
919  kineticEnergy1 = kineticEnergy - deltaE;
920  if (TST < TS1)
921  {
922  G4double QS = QM/(1.0+QM*0.5/electron_mass_c2);
923  G4double Q = QS/(std::pow((QS/cutoffEne)*(1.0+cutoffEne*0.5/electron_mass_c2),G4UniformRand())
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;
930  //energy and emission angle of the delta ray
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;
937  return;
938  }
939 
940  //Hard distant transverse collisions
941  cosThetaPrimary = 1.0;
942  //energy and emission angle of the delta ray
943  energySecondary = deltaE - ionEne;
944  cosThetaSecondary = 0.5;
945 
946  if (verboseLevel > 3)
947  G4cout << "SampleFinalStatePositron: sampled distant transverse collision " << G4endl;
948 
949  return;
950 }
951