source: trunk/source/processes/electromagnetic/lowenergy/src/G4Penelope08ComptonModel.cc @ 1316

Last change on this file since 1316 was 1316, checked in by garnier, 14 years ago

update geant4-09-04-beta-cand-01 interfaces-V09-03-09 vis-V09-03-08

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