Geant4 9.6.0
Toolkit for the simulation of the passage of particles through matter
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
G4PenelopeComptonModel.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// 15 Feb 2010 L Pandola Implementation
33// 18 Mar 2010 L Pandola Removed GetAtomsPerMolecule(), now demanded
34// to G4PenelopeOscillatorManager
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// 24 May 2011 L Pandola Renamed (make v2008 as default Penelope)
39// 10 Jun 2011 L Pandola Migrate atomic deexcitation interface
40//
43#include "G4SystemOfUnits.hh"
46#include "G4DynamicParticle.hh"
47#include "G4VEMDataSet.hh"
48#include "G4PhysicsTable.hh"
49#include "G4PhysicsLogVector.hh"
51#include "G4AtomicShell.hh"
52#include "G4Gamma.hh"
53#include "G4Electron.hh"
56#include "G4LossTableManager.hh"
57
58//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
59
60
62 const G4String& nam)
63 :G4VEmModel(nam),fParticleChange(0),isInitialised(false),fAtomDeexcitation(0),
64 oscManager(0)
65{
66 fIntrinsicLowEnergyLimit = 100.0*eV;
67 fIntrinsicHighEnergyLimit = 100.0*GeV;
68 // SetLowEnergyLimit(fIntrinsicLowEnergyLimit);
69 SetHighEnergyLimit(fIntrinsicHighEnergyLimit);
70 //
72
73 verboseLevel= 0;
74 // Verbosity scale:
75 // 0 = nothing
76 // 1 = warning for energy non-conservation
77 // 2 = details of energy budget
78 // 3 = calculation of cross sections, file openings, sampling of atoms
79 // 4 = entering in methods
80
81 //Mark this model as "applicable" for atomic deexcitation
83
84 fTransitionManager = G4AtomicTransitionManager::Instance();
85}
86
87//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
88
90{;}
91
92//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
93
95 const G4DataVector&)
96{
97 if (verboseLevel > 3)
98 G4cout << "Calling G4PenelopeComptonModel::Initialise()" << G4endl;
99
100 fAtomDeexcitation = G4LossTableManager::Instance()->AtomDeexcitation();
101 //Issue warning if the AtomicDeexcitation has not been declared
102 if (!fAtomDeexcitation)
103 {
104 G4cout << G4endl;
105 G4cout << "WARNING from G4PenelopeComptonModel " << G4endl;
106 G4cout << "Atomic de-excitation module is not instantiated, so there will not be ";
107 G4cout << "any fluorescence/Auger emission." << G4endl;
108 G4cout << "Please make sure this is intended" << G4endl;
109 }
110
111
112 if (verboseLevel > 0)
113 {
114 G4cout << "Penelope Compton model v2008 is initialized " << G4endl
115 << "Energy range: "
116 << LowEnergyLimit() / keV << " keV - "
117 << HighEnergyLimit() / GeV << " GeV";
118 }
119
120 if(isInitialised) return;
122 isInitialised = true;
123
124}
125
126//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
127
129 const G4ParticleDefinition* p,
130 G4double energy,
131 G4double,
132 G4double)
133{
134 // Penelope model v2008 to calculate the Compton scattering cross section:
135 // D. Brusa et al., Nucl. Instrum. Meth. A 379 (1996) 167
136 //
137 // The cross section for Compton scattering is calculated according to the Klein-Nishina
138 // formula for energy > 5 MeV.
139 // For E < 5 MeV it is used a parametrization for the differential cross-section dSigma/dOmega,
140 // which is integrated numerically in cos(theta), G4PenelopeComptonModel::DifferentialCrossSection().
141 // The parametrization includes the J(p)
142 // distribution profiles for the atomic shells, that are tabulated from Hartree-Fock calculations
143 // from F. Biggs et al., At. Data Nucl. Data Tables 16 (1975) 201
144 //
145 if (verboseLevel > 3)
146 G4cout << "Calling CrossSectionPerVolume() of G4PenelopeComptonModel" << G4endl;
147 SetupForMaterial(p, material, energy);
148
149 //Retrieve the oscillator table for this material
150 G4PenelopeOscillatorTable* theTable = oscManager->GetOscillatorTableCompton(material);
151
152 G4double cs = 0;
153
154 if (energy < 5*MeV) //explicit calculation for E < 5 MeV
155 {
156 size_t numberOfOscillators = theTable->size();
157 for (size_t i=0;i<numberOfOscillators;i++)
158 {
159 G4PenelopeOscillator* theOsc = (*theTable)[i];
160 //sum contributions coming from each oscillator
161 cs += OscillatorTotalCrossSection(energy,theOsc);
162 }
163 }
164 else //use Klein-Nishina for E>5 MeV
165 cs = KleinNishinaCrossSection(energy,material);
166
167 //cross sections are in units of pi*classic_electr_radius^2
168 cs *= pi*classic_electr_radius*classic_electr_radius;
169
170 //Now, cs is the cross section *per molecule*, let's calculate the
171 //cross section per volume
172
173 G4double atomDensity = material->GetTotNbOfAtomsPerVolume();
174 G4double atPerMol = oscManager->GetAtomsPerMolecule(material);
175
176 if (verboseLevel > 3)
177 G4cout << "Material " << material->GetName() << " has " << atPerMol <<
178 "atoms per molecule" << G4endl;
179
180 G4double moleculeDensity = 0.;
181
182 if (atPerMol)
183 moleculeDensity = atomDensity/atPerMol;
184
185 G4double csvolume = cs*moleculeDensity;
186
187 if (verboseLevel > 2)
188 G4cout << "Compton mean free path at " << energy/keV << " keV for material " <<
189 material->GetName() << " = " << (1./csvolume)/mm << " mm" << G4endl;
190 return csvolume;
191}
192
193//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
194
195//This is a dummy method. Never inkoved by the tracking, it just issues
196//a warning if one tries to get Cross Sections per Atom via the
197//G4EmCalculator.
199 G4double,
200 G4double,
201 G4double,
202 G4double,
203 G4double)
204{
205 G4cout << "*** G4PenelopeComptonModel -- WARNING ***" << G4endl;
206 G4cout << "Penelope Compton model v2008 does not calculate cross section _per atom_ " << G4endl;
207 G4cout << "so the result is always zero. For physics values, please invoke " << G4endl;
208 G4cout << "GetCrossSectionPerVolume() or GetMeanFreePath() via the G4EmCalculator" << G4endl;
209 return 0;
210}
211
212//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
213
214void G4PenelopeComptonModel::SampleSecondaries(std::vector<G4DynamicParticle*>* fvect,
215 const G4MaterialCutsCouple* couple,
216 const G4DynamicParticle* aDynamicGamma,
217 G4double,
218 G4double)
219{
220
221 // Penelope model v2008 to sample the Compton scattering final state.
222 // D. Brusa et al., Nucl. Instrum. Meth. A 379 (1996) 167
223 // The model determines also the original shell from which the electron is expelled,
224 // in order to produce fluorescence de-excitation (from G4DeexcitationManager)
225 //
226 // The final state for Compton scattering is calculated according to the Klein-Nishina
227 // formula for energy > 5 MeV. In this case, the Doppler broadening is negligible and
228 // one can assume that the target electron is at rest.
229 // For E < 5 MeV it is used the parametrization for the differential cross-section dSigma/dOmega,
230 // to sample the scattering angle and the energy of the emerging electron, which is
231 // G4PenelopeComptonModel::DifferentialCrossSection(). The rejection method is
232 // used to sample cos(theta). The efficiency increases monotonically with photon energy and is
233 // nearly independent on the Z; typical values are 35%, 80% and 95% for 1 keV, 1 MeV and 10 MeV,
234 // respectively.
235 // The parametrization includes the J(p) distribution profiles for the atomic shells, that are
236 // tabulated
237 // from Hartree-Fock calculations from F. Biggs et al., At. Data Nucl. Data Tables 16 (1975) 201.
238 // Doppler broadening is included.
239 //
240
241 if (verboseLevel > 3)
242 G4cout << "Calling SampleSecondaries() of G4PenelopeComptonModel" << G4endl;
243
244 G4double photonEnergy0 = aDynamicGamma->GetKineticEnergy();
245
246 if (photonEnergy0 <= fIntrinsicLowEnergyLimit)
247 {
251 return ;
252 }
253
254 G4ParticleMomentum photonDirection0 = aDynamicGamma->GetMomentumDirection();
255 const G4Material* material = couple->GetMaterial();
256
257 G4PenelopeOscillatorTable* theTable = oscManager->GetOscillatorTableCompton(material);
258
259 const G4int nmax = 64;
260 G4double rn[nmax]={0.0};
261 G4double pac[nmax]={0.0};
262
263 G4double S=0.0;
264 G4double epsilon = 0.0;
265 G4double cosTheta = 1.0;
266 G4double hartreeFunc = 0.0;
267 G4double oscStren = 0.0;
268 size_t numberOfOscillators = theTable->size();
269 size_t targetOscillator = 0;
270 G4double ionEnergy = 0.0*eV;
271
272 G4double ek = photonEnergy0/electron_mass_c2;
273 G4double ek2 = 2.*ek+1.0;
274 G4double eks = ek*ek;
275 G4double ek1 = eks-ek2-1.0;
276
277 G4double taumin = 1.0/ek2;
278 G4double a1 = std::log(ek2);
279 G4double a2 = a1+2.0*ek*(1.0+ek)/(ek2*ek2);
280
281 G4double TST = 0;
282 G4double tau = 0.;
283
284 //If the incoming photon is above 5 MeV, the quicker approach based on the
285 //pure Klein-Nishina formula is used
286 if (photonEnergy0 > 5*MeV)
287 {
288 do{
289 do{
290 if ((a2*G4UniformRand()) < a1)
291 tau = std::pow(taumin,G4UniformRand());
292 else
293 tau = std::sqrt(1.0+G4UniformRand()*(taumin*taumin-1.0));
294 //rejection function
295 TST = (1.0+tau*(ek1+tau*(ek2+tau*eks)))/(eks*tau*(1.0+tau*tau));
296 }while (G4UniformRand()> TST);
297 epsilon=tau;
298 cosTheta = 1.0 - (1.0-tau)/(ek*tau);
299
300 //Target shell electrons
301 TST = oscManager->GetTotalZ(material)*G4UniformRand();
302 targetOscillator = numberOfOscillators-1; //last level
303 S=0.0;
304 G4bool levelFound = false;
305 for (size_t j=0;j<numberOfOscillators && !levelFound; j++)
306 {
307 S += (*theTable)[j]->GetOscillatorStrength();
308 if (S > TST)
309 {
310 targetOscillator = j;
311 levelFound = true;
312 }
313 }
314 //check whether the level is valid
315 ionEnergy = (*theTable)[targetOscillator]->GetIonisationEnergy();
316 }while((epsilon*photonEnergy0-photonEnergy0+ionEnergy) >0);
317 }
318 else //photonEnergy0 < 5 MeV
319 {
320 //Incoherent scattering function for theta=PI
321 G4double s0=0.0;
322 G4double pzomc=0.0;
323 G4double rni=0.0;
324 G4double aux=0.0;
325 for (size_t i=0;i<numberOfOscillators;i++)
326 {
327 ionEnergy = (*theTable)[i]->GetIonisationEnergy();
328 if (photonEnergy0 > ionEnergy)
329 {
330 G4double aux2 = photonEnergy0*(photonEnergy0-ionEnergy)*2.0;
331 hartreeFunc = (*theTable)[i]->GetHartreeFactor();
332 oscStren = (*theTable)[i]->GetOscillatorStrength();
333 pzomc = hartreeFunc*(aux2-electron_mass_c2*ionEnergy)/
334 (electron_mass_c2*std::sqrt(2.0*aux2+ionEnergy*ionEnergy));
335 if (pzomc > 0)
336 rni = 1.0-0.5*std::exp(0.5-(std::sqrt(0.5)+std::sqrt(2.0)*pzomc)*
337 (std::sqrt(0.5)+std::sqrt(2.0)*pzomc));
338 else
339 rni = 0.5*std::exp(0.5-(std::sqrt(0.5)-std::sqrt(2.0)*pzomc)*
340 (std::sqrt(0.5)-std::sqrt(2.0)*pzomc));
341 s0 += oscStren*rni;
342 }
343 }
344 //Sampling tau
345 G4double cdt1 = 0.;
346 do
347 {
348 if ((G4UniformRand()*a2) < a1)
349 tau = std::pow(taumin,G4UniformRand());
350 else
351 tau = std::sqrt(1.0+G4UniformRand()*(taumin*taumin-1.0));
352 cdt1 = (1.0-tau)/(ek*tau);
353 //Incoherent scattering function
354 S = 0.;
355 for (size_t i=0;i<numberOfOscillators;i++)
356 {
357 ionEnergy = (*theTable)[i]->GetIonisationEnergy();
358 if (photonEnergy0 > ionEnergy) //sum only on excitable levels
359 {
360 aux = photonEnergy0*(photonEnergy0-ionEnergy)*cdt1;
361 hartreeFunc = (*theTable)[i]->GetHartreeFactor();
362 oscStren = (*theTable)[i]->GetOscillatorStrength();
363 pzomc = hartreeFunc*(aux-electron_mass_c2*ionEnergy)/
364 (electron_mass_c2*std::sqrt(2.0*aux+ionEnergy*ionEnergy));
365 if (pzomc > 0)
366 rn[i] = 1.0-0.5*std::exp(0.5-(std::sqrt(0.5)+std::sqrt(2.0)*pzomc)*
367 (std::sqrt(0.5)+std::sqrt(2.0)*pzomc));
368 else
369 rn[i] = 0.5*std::exp(0.5-(std::sqrt(0.5)-std::sqrt(2.0)*pzomc)*
370 (std::sqrt(0.5)-std::sqrt(2.0)*pzomc));
371 S += oscStren*rn[i];
372 pac[i] = S;
373 }
374 else
375 pac[i] = S-1e-6;
376 }
377 //Rejection function
378 TST = S*(1.0+tau*(ek1+tau*(ek2+tau*eks)))/(eks*tau*(1.0+tau*tau));
379 }while ((G4UniformRand()*s0) > TST);
380
381 cosTheta = 1.0 - cdt1;
382 G4double fpzmax=0.0,fpz=0.0;
383 G4double A=0.0;
384 //Target electron shell
385 do
386 {
387 do
388 {
389 TST = S*G4UniformRand();
390 targetOscillator = numberOfOscillators-1; //last level
391 G4bool levelFound = false;
392 for (size_t i=0;i<numberOfOscillators && !levelFound;i++)
393 {
394 if (pac[i]>TST)
395 {
396 targetOscillator = i;
397 levelFound = true;
398 }
399 }
400 A = G4UniformRand()*rn[targetOscillator];
401 hartreeFunc = (*theTable)[targetOscillator]->GetHartreeFactor();
402 oscStren = (*theTable)[targetOscillator]->GetOscillatorStrength();
403 if (A < 0.5)
404 pzomc = (std::sqrt(0.5)-std::sqrt(0.5-std::log(2.0*A)))/
405 (std::sqrt(2.0)*hartreeFunc);
406 else
407 pzomc = (std::sqrt(0.5-std::log(2.0-2.0*A))-std::sqrt(0.5))/
408 (std::sqrt(2.0)*hartreeFunc);
409 } while (pzomc < -1);
410
411 // F(EP) rejection
412 G4double XQC = 1.0+tau*(tau-2.0*cosTheta);
413 G4double AF = std::sqrt(XQC)*(1.0+tau*(tau-cosTheta)/XQC);
414 if (AF > 0)
415 fpzmax = 1.0+AF*0.2;
416 else
417 fpzmax = 1.0-AF*0.2;
418 fpz = 1.0+AF*std::max(std::min(pzomc,0.2),-0.2);
419 }while ((fpzmax*G4UniformRand())>fpz);
420
421 //Energy of the scattered photon
422 G4double T = pzomc*pzomc;
423 G4double b1 = 1.0-T*tau*tau;
424 G4double b2 = 1.0-T*tau*cosTheta;
425 if (pzomc > 0.0)
426 epsilon = (tau/b1)*(b2+std::sqrt(std::abs(b2*b2-b1*(1.0-T))));
427 else
428 epsilon = (tau/b1)*(b2-std::sqrt(std::abs(b2*b2-b1*(1.0-T))));
429 } //energy < 5 MeV
430
431 //Ok, the kinematics has been calculated.
432 G4double sinTheta = std::sqrt(1-cosTheta*cosTheta);
433 G4double phi = twopi * G4UniformRand() ;
434 G4double dirx = sinTheta * std::cos(phi);
435 G4double diry = sinTheta * std::sin(phi);
436 G4double dirz = cosTheta ;
437
438 // Update G4VParticleChange for the scattered photon
439 G4ThreeVector photonDirection1(dirx,diry,dirz);
440 photonDirection1.rotateUz(photonDirection0);
441 fParticleChange->ProposeMomentumDirection(photonDirection1) ;
442
443 G4double photonEnergy1 = epsilon * photonEnergy0;
444
445 if (photonEnergy1 > 0.)
447 else
448 {
451 }
452
453 //Create scattered electron
454 G4double diffEnergy = photonEnergy0*(1-epsilon);
455 ionEnergy = (*theTable)[targetOscillator]->GetIonisationEnergy();
456
457 G4double Q2 =
458 photonEnergy0*photonEnergy0+photonEnergy1*(photonEnergy1-2.0*photonEnergy0*cosTheta);
459 G4double cosThetaE = 0.; //scattering angle for the electron
460
461 if (Q2 > 1.0e-12)
462 cosThetaE = (photonEnergy0-photonEnergy1*cosTheta)/std::sqrt(Q2);
463 else
464 cosThetaE = 1.0;
465 G4double sinThetaE = std::sqrt(1-cosThetaE*cosThetaE);
466
467 //Now, try to handle fluorescence
468 //Notice: merged levels are indicated with Z=0 and flag=30
469 G4int shFlag = (*theTable)[targetOscillator]->GetShellFlag();
470 G4int Z = (G4int) (*theTable)[targetOscillator]->GetParentZ();
471
472 //initialize here, then check photons created by Atomic-Deexcitation, and the final state e-
473 G4double bindingEnergy = 0.*eV;
474 const G4AtomicShell* shell = 0;
475
476 //Real level
477 if (Z > 0 && shFlag<30)
478 {
479 shell = fTransitionManager->Shell(Z,shFlag-1);
480 bindingEnergy = shell->BindingEnergy();
481 }
482
483 G4double ionEnergyInPenelopeDatabase = ionEnergy;
484 //protection against energy non-conservation
485 ionEnergy = std::max(bindingEnergy,ionEnergyInPenelopeDatabase);
486
487 //subtract the excitation energy. If not emitted by fluorescence
488 //the ionization energy is deposited as local energy deposition
489 G4double eKineticEnergy = diffEnergy - ionEnergy;
490 G4double localEnergyDeposit = ionEnergy;
491 G4double energyInFluorescence = 0.; //testing purposes only
492 G4double energyInAuger = 0; //testing purposes
493
494 if (eKineticEnergy < 0)
495 {
496 //It means that there was some problem/mismatch between the two databases.
497 //Try to make it work
498 //In this case available Energy (diffEnergy) < ionEnergy
499 //Full residual energy is deposited locally
500 localEnergyDeposit = diffEnergy;
501 eKineticEnergy = 0.0;
502 }
503
504 //the local energy deposit is what remains: part of this may be spent for fluorescence.
505 //Notice: shell might be NULL (invalid!) if shFlag=30. Must be protected
506 //Now, take care of fluorescence, if required
507 if (fAtomDeexcitation && shell)
508 {
509 G4int index = couple->GetIndex();
510 if (fAtomDeexcitation->CheckDeexcitationActiveRegion(index))
511 {
512 size_t nBefore = fvect->size();
513 fAtomDeexcitation->GenerateParticles(fvect,shell,Z,index);
514 size_t nAfter = fvect->size();
515
516 if (nAfter > nBefore) //actual production of fluorescence
517 {
518 for (size_t j=nBefore;j<nAfter;j++) //loop on products
519 {
520 G4double itsEnergy = ((*fvect)[j])->GetKineticEnergy();
521 localEnergyDeposit -= itsEnergy;
522 if (((*fvect)[j])->GetParticleDefinition() == G4Gamma::Definition())
523 energyInFluorescence += itsEnergy;
524 else if (((*fvect)[j])->GetParticleDefinition() == G4Electron::Definition())
525 energyInAuger += itsEnergy;
526
527 }
528 }
529
530 }
531 }
532
533
534 /*
535 if(DeexcitationFlag() && Z > 5 && shellId>0) {
536
537 const G4ProductionCutsTable* theCoupleTable=
538 G4ProductionCutsTable::GetProductionCutsTable();
539
540 size_t index = couple->GetIndex();
541 G4double cutg = (*(theCoupleTable->GetEnergyCutsVector(0)))[index];
542 G4double cute = (*(theCoupleTable->GetEnergyCutsVector(1)))[index];
543
544 // Generation of fluorescence
545 // Data in EADL are available only for Z > 5
546 // Protection to avoid generating photons in the unphysical case of
547 // shell binding energy > photon energy
548 if (localEnergyDeposit > cutg || localEnergyDeposit > cute)
549 {
550 G4DynamicParticle* aPhoton;
551 deexcitationManager.SetCutForSecondaryPhotons(cutg);
552 deexcitationManager.SetCutForAugerElectrons(cute);
553
554 photonVector = deexcitationManager.GenerateParticles(Z,shellId);
555 if(photonVector)
556 {
557 size_t nPhotons = photonVector->size();
558 for (size_t k=0; k<nPhotons; k++)
559 {
560 aPhoton = (*photonVector)[k];
561 if (aPhoton)
562 {
563 G4double itsEnergy = aPhoton->GetKineticEnergy();
564 G4bool keepIt = false;
565 if (itsEnergy <= localEnergyDeposit)
566 {
567 //check if good!
568 if(aPhoton->GetDefinition() == G4Gamma::Gamma()
569 && itsEnergy >= cutg)
570 {
571 keepIt = true;
572 energyInFluorescence += itsEnergy;
573 }
574 if (aPhoton->GetDefinition() == G4Electron::Electron() &&
575 itsEnergy >= cute)
576 {
577 energyInAuger += itsEnergy;
578 keepIt = true;
579 }
580 }
581 //good secondary, register it
582 if (keepIt)
583 {
584 localEnergyDeposit -= itsEnergy;
585 fvect->push_back(aPhoton);
586 }
587 else
588 {
589 delete aPhoton;
590 (*photonVector)[k] = 0;
591 }
592 }
593 }
594 delete photonVector;
595 }
596 }
597 }
598 */
599
600
601 //Always produce explicitely the electron
602 G4DynamicParticle* electron = 0;
603
604 G4double xEl = sinThetaE * std::cos(phi+pi);
605 G4double yEl = sinThetaE * std::sin(phi+pi);
606 G4double zEl = cosThetaE;
607 G4ThreeVector eDirection(xEl,yEl,zEl); //electron direction
608 eDirection.rotateUz(photonDirection0);
609 electron = new G4DynamicParticle (G4Electron::Electron(),
610 eDirection,eKineticEnergy) ;
611 fvect->push_back(electron);
612
613
614 if (localEnergyDeposit < 0)
615 {
616 G4cout << "WARNING-"
617 << "G4PenelopeComptonModel::SampleSecondaries - Negative energy deposit"
618 << G4endl;
619 localEnergyDeposit=0.;
620 }
621 fParticleChange->ProposeLocalEnergyDeposit(localEnergyDeposit);
622
623 G4double electronEnergy = 0.;
624 if (electron)
625 electronEnergy = eKineticEnergy;
626 if (verboseLevel > 1)
627 {
628 G4cout << "-----------------------------------------------------------" << G4endl;
629 G4cout << "Energy balance from G4PenelopeCompton" << G4endl;
630 G4cout << "Incoming photon energy: " << photonEnergy0/keV << " keV" << G4endl;
631 G4cout << "-----------------------------------------------------------" << G4endl;
632 G4cout << "Scattered photon: " << photonEnergy1/keV << " keV" << G4endl;
633 G4cout << "Scattered electron " << electronEnergy/keV << " keV" << G4endl;
634 if (energyInFluorescence)
635 G4cout << "Fluorescence x-rays: " << energyInFluorescence/keV << " keV" << G4endl;
636 if (energyInAuger)
637 G4cout << "Auger electrons: " << energyInAuger/keV << " keV" << G4endl;
638 G4cout << "Local energy deposit " << localEnergyDeposit/keV << " keV" << G4endl;
639 G4cout << "Total final state: " << (photonEnergy1+electronEnergy+energyInFluorescence+
640 localEnergyDeposit+energyInAuger)/keV <<
641 " keV" << G4endl;
642 G4cout << "-----------------------------------------------------------" << G4endl;
643 }
644 if (verboseLevel > 0)
645 {
646 G4double energyDiff = std::fabs(photonEnergy1+
647 electronEnergy+energyInFluorescence+
648 localEnergyDeposit+energyInAuger-photonEnergy0);
649 if (energyDiff > 0.05*keV)
650 G4cout << "Warning from G4PenelopeCompton: problem with energy conservation: " <<
651 (photonEnergy1+electronEnergy+energyInFluorescence+energyInAuger+localEnergyDeposit)/keV <<
652 " keV (final) vs. " <<
653 photonEnergy0/keV << " keV (initial)" << G4endl;
654 }
655}
656
657//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
658
659G4double G4PenelopeComptonModel::DifferentialCrossSection(G4double cosTheta,G4double energy,
661{
662 //
663 // Penelope model v2008. Single differential cross section *per electron*
664 // for photon Compton scattering by
665 // electrons in the given atomic oscillator, differential in the direction of the
666 // scattering photon. This is in units of pi*classic_electr_radius**2
667 //
668 // D. Brusa et al., Nucl. Instrum. Meth. A 379 (1996) 167
669 // The parametrization includes the J(p) distribution profiles for the atomic shells,
670 // that are tabulated from Hartree-Fock calculations
671 // from F. Biggs et al., At. Data Nucl. Data Tables 16 (1975) 201
672 //
673 G4double ionEnergy = osc->GetIonisationEnergy();
674 G4double harFunc = osc->GetHartreeFactor();
675
676 const G4double k2 = std::sqrt(2.);
677 const G4double k1 = 1./k2;
678
679 if (energy < ionEnergy)
680 return 0;
681
682 //energy of the Compton line
683 G4double cdt1 = 1.0-cosTheta;
684 G4double EOEC = 1.0+(energy/electron_mass_c2)*cdt1;
685 G4double ECOE = 1.0/EOEC;
686
687 //Incoherent scattering function (analytical profile)
688 G4double aux = energy*(energy-ionEnergy)*cdt1;
689 G4double Pzimax =
690 (aux - electron_mass_c2*ionEnergy)/(electron_mass_c2*std::sqrt(2*aux+ionEnergy*ionEnergy));
691 G4double sia = 0.0;
692 G4double x = harFunc*Pzimax;
693 if (x > 0)
694 sia = 1.0-0.5*std::exp(0.5-(k1+k2*x)*(k1+k2*x));
695 else
696 sia = 0.5*std::exp(0.5-(k1-k2*x)*(k1-k2*x));
697
698 //1st order correction, integral of Pz times the Compton profile.
699 //Calculated approximately using a free-electron gas profile
700 G4double pf = 3.0/(4.0*harFunc);
701 if (std::fabs(Pzimax) < pf)
702 {
703 G4double QCOE2 = 1.0+ECOE*ECOE-2.0*ECOE*cosTheta;
704 G4double p2 = Pzimax*Pzimax;
705 G4double dspz = std::sqrt(QCOE2)*
706 (1.0+ECOE*(ECOE-cosTheta)/QCOE2)*harFunc
707 *0.25*(2*p2-(p2*p2)/(pf*pf)-(pf*pf));
708 sia += std::max(dspz,-1.0*sia);
709 }
710
711 G4double XKN = EOEC+ECOE-1.0+cosTheta*cosTheta;
712
713 //Differential cross section (per electron, in units of pi*classic_electr_radius**2)
714 G4double diffCS = ECOE*ECOE*XKN*sia;
715
716 return diffCS;
717}
718
719//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
720
721G4double G4PenelopeComptonModel::OscillatorTotalCrossSection(G4double energy,G4PenelopeOscillator* osc)
722{
723 //Total cross section (integrated) for the given oscillator in units of
724 //pi*classic_electr_radius^2
725
726 //Integrate differential cross section for each oscillator
727 G4double stre = osc->GetOscillatorStrength();
728
729 // here one uses the using the 20-point
730 // Gauss quadrature method with an adaptive bipartition scheme
731 const G4int npoints=10;
732 const G4int ncallsmax=20000;
733 const G4int nst=256;
734 static G4double Abscissas[10] = {7.652651133497334e-02,2.2778585114164508e-01,3.7370608871541956e-01,
735 5.1086700195082710e-01,6.3605368072651503e-01,7.4633190646015079e-01,
736 8.3911697182221882e-01,9.1223442825132591e-01,9.6397192727791379e-01,
737 9.9312859918509492e-01};
738 static G4double Weights[10] = {1.5275338713072585e-01,1.4917298647260375e-01,1.4209610931838205e-01,
739 1.3168863844917663e-01,1.1819453196151842e-01,1.0193011981724044e-01,
740 8.3276741576704749e-02,6.2672048334109064e-02,4.0601429800386941e-02,
741 1.7614007139152118e-02};
742
743 G4double MaxError = 1e-5;
744 //Error control
745 G4double Ctol = std::min(std::max(MaxError,1e-13),1e-02);
746 G4double Ptol = 0.01*Ctol;
747 G4double Err=1e35;
748
749 //Gauss integration from -1 to 1
750 G4double LowPoint = -1.0;
751 G4double HighPoint = 1.0;
752
753 G4double h=HighPoint-LowPoint;
754 G4double sumga=0.0;
755 G4double a=0.5*(HighPoint-LowPoint);
756 G4double b=0.5*(HighPoint+LowPoint);
757 G4double c=a*Abscissas[0];
758 G4double d= Weights[0]*
759 (DifferentialCrossSection(b+c,energy,osc)+DifferentialCrossSection(b-c,energy,osc));
760 for (G4int i=2;i<=npoints;i++)
761 {
762 c=a*Abscissas[i-1];
763 d += Weights[i-1]*
764 (DifferentialCrossSection(b+c,energy,osc)+DifferentialCrossSection(b-c,energy,osc));
765 }
766 G4int icall = 2*npoints;
767 G4int LH=1;
768 G4double S[nst],x[nst],sn[nst],xrn[nst];
769 S[0]=d*a;
770 x[0]=LowPoint;
771
772 G4bool loopAgain = true;
773
774 //Adaptive bipartition scheme
775 do{
776 G4double h0=h;
777 h=0.5*h; //bipartition
778 G4double sumr=0;
779 G4int LHN=0;
780 G4double si,xa,xb,xc;
781 for (G4int i=1;i<=LH;i++){
782 si=S[i-1];
783 xa=x[i-1];
784 xb=xa+h;
785 xc=xa+h0;
786 a=0.5*(xb-xa);
787 b=0.5*(xb+xa);
788 c=a*Abscissas[0];
789 G4double dLocal = Weights[0]*
790 (DifferentialCrossSection(b+c,energy,osc)+DifferentialCrossSection(b-c,energy,osc));
791
792 for (G4int j=1;j<npoints;j++)
793 {
794 c=a*Abscissas[j];
795 dLocal += Weights[j]*
796 (DifferentialCrossSection(b+c,energy,osc)+DifferentialCrossSection(b-c,energy,osc));
797 }
798 G4double s1=dLocal*a;
799 a=0.5*(xc-xb);
800 b=0.5*(xc+xb);
801 c=a*Abscissas[0];
802 dLocal=Weights[0]*
803 (DifferentialCrossSection(b+c,energy,osc)+DifferentialCrossSection(b-c,energy,osc));
804
805 for (G4int j=1;j<npoints;j++)
806 {
807 c=a*Abscissas[j];
808 dLocal += Weights[j]*
809 (DifferentialCrossSection(b+c,energy,osc)+DifferentialCrossSection(b-c,energy,osc));
810 }
811 G4double s2=dLocal*a;
812 icall=icall+4*npoints;
813 G4double s12=s1+s2;
814 if (std::abs(s12-si)<std::max(Ptol*std::abs(s12),1e-35))
815 sumga += s12;
816 else
817 {
818 sumr += s12;
819 LHN += 2;
820 sn[LHN-1]=s2;
821 xrn[LHN-1]=xb;
822 sn[LHN-2]=s1;
823 xrn[LHN-2]=xa;
824 }
825
826 if (icall>ncallsmax || LHN>nst)
827 {
828 G4cout << "G4PenelopeComptonModel: " << G4endl;
829 G4cout << "LowPoint: " << LowPoint << ", High Point: " << HighPoint << G4endl;
830 G4cout << "Tolerance: " << MaxError << G4endl;
831 G4cout << "Calls: " << icall << ", Integral: " << sumga << ", Error: " << Err << G4endl;
832 G4cout << "Number of open subintervals: " << LHN << G4endl;
833 G4cout << "WARNING: the required accuracy has not been attained" << G4endl;
834 loopAgain = false;
835 }
836 }
837 Err=std::abs(sumr)/std::max(std::abs(sumr+sumga),1e-35);
838 if (Err < Ctol || LHN == 0)
839 loopAgain = false; //end of cycle
840 LH=LHN;
841 for (G4int i=0;i<LH;i++)
842 {
843 S[i]=sn[i];
844 x[i]=xrn[i];
845 }
846 }while(Ctol < 1.0 && loopAgain);
847
848
849 G4double xs = stre*sumga;
850
851 return xs;
852}
853
854//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
855
856G4double G4PenelopeComptonModel::KleinNishinaCrossSection(G4double energy,
857 const G4Material* material)
858{
859 // use Klein-Nishina formula
860 // total cross section in units of pi*classic_electr_radius^2
861
862 G4double cs = 0;
863
864 G4double ek =energy/electron_mass_c2;
865 G4double eks = ek*ek;
866 G4double ek2 = 1.0+ek+ek;
867 G4double ek1 = eks-ek2-1.0;
868
869 G4double t0 = 1.0/ek2;
870 G4double csl = 0.5*eks*t0*t0+ek2*t0+ek1*std::log(t0)-(1.0/t0);
871
872 G4PenelopeOscillatorTable* theTable = oscManager->GetOscillatorTableCompton(material);
873
874 for (size_t i=0;i<theTable->size();i++)
875 {
876 G4PenelopeOscillator* theOsc = (*theTable)[i];
877 G4double ionEnergy = theOsc->GetIonisationEnergy();
878 G4double tau=(energy-ionEnergy)/energy;
879 if (tau > t0)
880 {
881 G4double csu = 0.5*eks*tau*tau+ek2*tau+ek1*std::log(tau)-(1.0/tau);
882 G4double stre = theOsc->GetOscillatorStrength();
883
884 cs += stre*(csu-csl);
885 }
886 }
887
888 cs /= (ek*eks);
889
890 return cs;
891
892}
893
std::vector< G4PenelopeOscillator * > G4PenelopeOscillatorTable
@ fStopAndKill
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
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)
G4ParticleChangeForGamma * fParticleChange
G4PenelopeComptonModel(const G4ParticleDefinition *p=0, const G4String &processName="PenCompton")
virtual void Initialise(const G4ParticleDefinition *, const G4DataVector &)
virtual G4double ComputeCrossSectionPerAtom(const G4ParticleDefinition *, G4double, G4double, G4double, G4double, G4double)
virtual void SampleSecondaries(std::vector< G4DynamicParticle * > *, const G4MaterialCutsCouple *, const G4DynamicParticle *, G4double tmin, G4double maxEnergy)
virtual G4double CrossSectionPerVolume(const G4Material *, const G4ParticleDefinition *, G4double kineticEnergy, G4double cutEnergy=0.0, G4double maxEnergy=DBL_MAX)
G4double GetAtomsPerMolecule(const G4Material *)
Returns the total number of atoms per molecule.
G4PenelopeOscillatorTable * GetOscillatorTableCompton(const G4Material *)
static G4PenelopeOscillatorManager * GetOscillatorManager()
G4double GetTotalZ(const G4Material *)
G4bool CheckDeexcitationActiveRegion(G4int coupleIndex)
void GenerateParticles(std::vector< G4DynamicParticle * > *secVect, const G4AtomicShell *, G4int Z, G4int coupleIndex)
void SetHighEnergyLimit(G4double)
Definition: G4VEmModel.hh:585
G4ParticleChangeForGamma * GetParticleChangeForGamma()
Definition: G4VEmModel.cc:109
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
void ProposeTrackStatus(G4TrackStatus status)
void ProposeLocalEnergyDeposit(G4double anEnergyPart)