Geant4 9.6.0
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
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
48#include "G4SystemOfUnits.hh"
52#include "G4DynamicParticle.hh"
54#include "G4AtomicShell.hh"
55#include "G4Gamma.hh"
56#include "G4Electron.hh"
57#include "G4Positron.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
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
157 theParticle,
158 G4double energy,
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
296{
297 return fIntrinsicLowEnergyLimit;
298}
299
300//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
301
302void 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);
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-
420 G4double bindingEnergy = 0.*eV;
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....
541void 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....
754void 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();
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
@ FatalException
std::vector< G4PenelopeOscillator * > G4PenelopeOscillatorTable
double G4double
Definition: G4Types.hh:64
int G4int
Definition: G4Types.hh:66
bool G4bool
Definition: G4Types.hh:67
#define G4endl
Definition: G4ios.hh:52
G4DLLIMPORT std::ostream G4cout
#define G4UniformRand()
Definition: Randomize.hh:53
Hep3Vector & rotateUz(const Hep3Vector &)
Definition: ThreeVector.cc:72
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()
Definition: G4Electron.cc:49
static G4Electron * Electron()
Definition: G4Electron.cc:94
static G4Gamma * Definition()
Definition: G4Gamma.cc:49
static G4LossTableManager * Instance()
G4VAtomDeexcitation * AtomDeexcitation()
const G4Material * GetMaterial() const
G4double GetTotNbOfAtomsPerVolume() const
Definition: G4Material.hh:208
const G4String & GetName() const
Definition: G4Material.hh:177
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 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()
Definition: G4Positron.cc:94
G4bool CheckDeexcitationActiveRegion(G4int coupleIndex)
void GenerateParticles(std::vector< G4DynamicParticle * > *secVect, const G4AtomicShell *, G4int Z, G4int coupleIndex)
void SetHighEnergyLimit(G4double)
Definition: G4VEmModel.hh:585
G4double LowEnergyLimit() const
Definition: G4VEmModel.hh:529
G4double HighEnergyLimit() const
Definition: G4VEmModel.hh:522
virtual void SetupForMaterial(const G4ParticleDefinition *, const G4Material *, G4double kineticEnergy)
Definition: G4VEmModel.cc:311
void SetDeexcitationFlag(G4bool val)
Definition: G4VEmModel.hh:641
G4ParticleChangeForLoss * GetParticleChangeForLoss()
Definition: G4VEmModel.cc:95
void ProposeLocalEnergyDeposit(G4double anEnergyPart)
void G4Exception(const char *originOfException, const char *exceptionCode, G4ExceptionSeverity severity, const char *comments)
Definition: G4Exception.cc:41
std::ostringstream G4ExceptionDescription
Definition: globals.hh:76