source: trunk/source/processes/electromagnetic/lowenergy/src/G4PenelopeCompton.cc @ 1347

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

geant4 tag 9.4

File size: 26.7 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: G4PenelopeCompton.cc,v 1.36 2009/06/11 15:47:08 mantero Exp $
27// GEANT4 tag $Name: geant4-09-04-ref-00 $
28//
29// Author: Luciano Pandola
30//
31// History:
32// --------
33// 12 Feb 2003   MG Pia       const argument in SelectRandomAtomForCompton
34//                            Migration to "cuts per region"
35// 14 Feb 2003   MG Pia       Corrected compilation errors and warnings
36//                            from SUN
37//                            Modified some variables to lowercase initial
38// 10 Mar 2003 V.Ivanchenko   Remove CutPerMaterial warning
39// 13 Mar 2003 L.Pandola      Code "cleaned" 
40// 20 Mar 2003 L.Pandola      ReadData() changed (performance improved)
41// 26 Mar 2003 L.Pandola      Added fluorescence
42// 24 May 2003 MGP            Removed memory leak
43// 09 Mar 2004 L.Pandola      Bug fixed in the generation of final state
44//                            (bug report # 585)
45// 17 Mar 2004 L.Pandola      Removed unnecessary calls to std::pow(a,b)
46// 18 Mar 2004 L.Pandola      Use of std::map (code review)
47// 26 Mar 2008 L.Pandola      Add boolean flag to control atomic de-excitation
48// 27 Mar 2008 L.Pandola      Re-named some variables to improve readability,
49//                            and check for strict energy conservation
50// 03 Jun 2008 L.Pandola      Added further protection against non-conservation
51//                            of energy: it may happen because ionization energy
52//                            from de-excitation manager and from Penelope internal
53//                            database do not match (difference is <10 eV, but may
54//                            give a e- with negative kinetic energy).
55//
56// -------------------------------------------------------------------
57
58#include "G4PenelopeCompton.hh"
59#include "Randomize.hh"
60#include "G4ParticleDefinition.hh"
61#include "G4Track.hh"
62#include "G4Step.hh"
63#include "G4ForceCondition.hh"
64#include "G4Gamma.hh"
65#include "G4Electron.hh"
66#include "G4DynamicParticle.hh"
67#include "G4VParticleChange.hh"
68#include "G4ThreeVector.hh"
69#include "G4EnergyLossTables.hh"
70#include "G4VCrossSectionHandler.hh"
71#include "G4CrossSectionHandler.hh"
72#include "G4VEMDataSet.hh"
73#include "G4EMDataSet.hh"
74#include "G4CompositeEMDataSet.hh"
75#include "G4VDataSetAlgorithm.hh"
76#include "G4LogLogInterpolation.hh"
77#include "G4VRangeTest.hh"
78#include "G4RangeTest.hh"
79#include "G4ProductionCutsTable.hh"
80#include "G4AtomicTransitionManager.hh"
81#include "G4AtomicShell.hh"
82#include "G4AtomicDeexcitation.hh"
83#include "G4PenelopeIntegrator.hh"
84#include "G4MaterialCutsCouple.hh"
85
86
87G4PenelopeCompton::G4PenelopeCompton(const G4String& processName)
88  : G4VDiscreteProcess(processName),
89    lowEnergyLimit(250*eV),
90    highEnergyLimit(100*GeV),
91    intrinsicLowEnergyLimit(10*eV),
92    intrinsicHighEnergyLimit(100*GeV),
93    energyForIntegration(0.0),
94    ZForIntegration(1),
95    nBins(200),
96    cutForLowEnergySecondaryPhotons(250.0*eV),
97    fUseAtomicDeexcitation(true)
98{
99  if (lowEnergyLimit < intrinsicLowEnergyLimit ||
100      highEnergyLimit > intrinsicHighEnergyLimit)
101    {
102      G4Exception("G4PenelopeCompton::G4PenelopeCompton - energy outside intrinsic process validity range");
103    }
104
105  meanFreePathTable = 0;
106  ionizationEnergy = new std::map<G4int,G4DataVector*>;
107  hartreeFunction  = new std::map<G4int,G4DataVector*>;
108  occupationNumber = new std::map<G4int,G4DataVector*>;
109
110  rangeTest = new G4RangeTest;
111
112  ReadData(); //Read data from file
113
114  if (verboseLevel > 0)
115    {
116      G4cout << GetProcessName() << " is created " << G4endl
117             << "Energy range: "
118             << lowEnergyLimit / keV << " keV - "
119             << highEnergyLimit / GeV << " GeV"
120             << G4endl;
121    }
122
123
124   G4cout << G4endl;
125   G4cout << "*******************************************************************************" << G4endl;
126   G4cout << "*******************************************************************************" << G4endl;
127   G4cout << "   The class G4PenelopeCompton is NOT SUPPORTED ANYMORE. " << G4endl;
128   G4cout << "   It will be REMOVED with the next major release of Geant4. " << G4endl;
129   G4cout << "   Please consult: https://twiki.cern.ch/twiki/bin/view/Geant4/LoweProcesses" << G4endl;
130   G4cout << "*******************************************************************************" << G4endl;
131   G4cout << "*******************************************************************************" << G4endl;
132   G4cout << G4endl;
133
134}
135
136G4PenelopeCompton::~G4PenelopeCompton()
137{
138  delete meanFreePathTable;
139  delete rangeTest;
140
141  for (size_t i=0;i<matCrossSections->size();i++)
142    {
143      delete (*matCrossSections)[i];
144    }
145
146  delete matCrossSections;
147
148  for (G4int Z=1;Z<100;Z++)
149    {
150      if (ionizationEnergy->count(Z)) delete (ionizationEnergy->find(Z)->second);
151      if (hartreeFunction->count(Z)) delete (hartreeFunction->find(Z)->second);
152      if (occupationNumber->count(Z)) delete (occupationNumber->find(Z)->second);
153    }
154  delete ionizationEnergy;
155  delete hartreeFunction;
156  delete occupationNumber;
157}
158
159void G4PenelopeCompton::BuildPhysicsTable(const G4ParticleDefinition& )
160{
161  G4DataVector energyVector;
162  G4double dBin = std::log10(highEnergyLimit/lowEnergyLimit)/nBins;
163  for (G4int i=0;i<nBins;i++)
164    {
165      energyVector.push_back(std::pow(10.,std::log10(lowEnergyLimit)+i*dBin));
166    }
167
168  const G4MaterialTable* materialTable = G4Material::GetMaterialTable();
169  G4int nMaterials = G4Material::GetNumberOfMaterials();
170  G4VDataSetAlgorithm* algo = new G4LogLogInterpolation();
171
172  //size_t nOfBins = energyVector.size();
173  //size_t bin=0;
174
175  G4DataVector* energies;
176  G4DataVector* data;
177
178  matCrossSections = new std::vector<G4VEMDataSet*>;
179
180  for (G4int m=0; m<nMaterials; m++)
181    {
182      const G4Material* material= (*materialTable)[m];
183      G4int nElements = material->GetNumberOfElements();
184      const G4ElementVector* elementVector = material->GetElementVector();
185      const G4double* nAtomsPerVolume = material->GetAtomicNumDensityVector();
186
187      G4VEMDataSet* setForMat = new G4CompositeEMDataSet(algo,1.,1.);
188
189      for (G4int i=0; i<nElements; i++) {
190 
191        G4int Z = (G4int) (*elementVector)[i]->GetZ();
192        G4double density = nAtomsPerVolume[i];
193        G4double cross=0.0;
194        energies = new G4DataVector;
195        data = new G4DataVector;
196
197
198        for (size_t bin=0; bin<energyVector.size(); bin++)
199          {
200            G4double e = energyVector[bin];
201            energies->push_back(e);
202            cross = density * CrossSection(e,Z); 
203            data->push_back(cross);
204          }
205
206        G4VEMDataSet* elSet = new G4EMDataSet(i,energies,data,algo,1.,1.);
207        setForMat->AddComponent(elSet);
208      }
209
210      matCrossSections->push_back(setForMat);
211    }
212
213
214  //Build the mean free path table!
215  G4double matCS = 0.0;
216  G4VEMDataSet* matCrossSet = new G4CompositeEMDataSet(algo,1.,1.);
217  G4VEMDataSet* materialSet = new G4CompositeEMDataSet(algo,1.,1.);
218 
219 
220  for (G4int m=0; m<nMaterials; m++)
221    { 
222      energies = new G4DataVector;
223      data = new G4DataVector;
224      const G4Material* material= (*materialTable)[m];
225      material= (*materialTable)[m];
226      for (size_t bin=0; bin<energyVector.size(); bin++)
227        {
228          G4double energy = energyVector[bin];
229          energies->push_back(energy);
230          matCrossSet = (*matCrossSections)[m]; 
231          matCS = 0.0;
232          G4int nElm = matCrossSet->NumberOfComponents();
233          for(G4int j=0; j<nElm; j++) {
234            matCS += matCrossSet->GetComponent(j)->FindValue(energy);
235          }
236          if (matCS > 0.)
237            {
238              data->push_back(1./matCS);
239            }
240          else
241            {
242              data->push_back(DBL_MAX);
243            }
244        }
245      G4VEMDataSet* dataSet = new G4EMDataSet(m,energies,data,algo,1.,1.);   
246      materialSet->AddComponent(dataSet);
247    }
248  meanFreePathTable = materialSet; 
249}
250
251G4VParticleChange* G4PenelopeCompton::PostStepDoIt(const G4Track& aTrack, 
252                                                   const G4Step&  aStep)
253{
254  //Penelope model
255
256  aParticleChange.Initialize(aTrack);
257 
258  // Dynamic particle quantities 
259  const G4DynamicParticle* incidentPhoton = aTrack.GetDynamicParticle();
260  G4double photonEnergy0 = incidentPhoton->GetKineticEnergy();
261
262  if (photonEnergy0 <= lowEnergyLimit)
263    {
264      aParticleChange.ProposeTrackStatus(fStopAndKill);
265      aParticleChange.ProposeEnergy(0.);
266      aParticleChange.ProposeLocalEnergyDeposit(photonEnergy0);
267      return G4VDiscreteProcess::PostStepDoIt(aTrack,aStep);
268    }
269
270  G4ParticleMomentum photonDirection0 = incidentPhoton->GetMomentumDirection();
271
272  const G4MaterialCutsCouple* couple = aTrack.GetMaterialCutsCouple();
273  const G4Material* material = couple->GetMaterial();
274 
275  G4int Z = SelectRandomAtomForCompton(material,photonEnergy0);
276  const G4int nmax = 64;
277  G4double rn[nmax],pac[nmax];
278 
279  G4double ki,ki1,ki2,ki3,taumin,a1,a2;
280  G4double tau,TST;
281  G4double S=0.0;
282  G4double epsilon,cosTheta;
283  G4double harFunc = 0.0;
284  G4int occupNb= 0;
285  G4double ionEnergy=0.0;
286  G4int nosc = occupationNumber->find(Z)->second->size();
287  G4int iosc = nosc;
288  ki = photonEnergy0/electron_mass_c2;
289  ki2 = 2*ki+1.0;
290  ki3 = ki*ki;
291  ki1 = ki3-ki2-1.0;
292  taumin = 1.0/ki2;
293  a1 = std::log(ki2);
294  a2 = a1+2.0*ki*(1.0+ki)/(ki2*ki2);
295  //If the incoming photon is above 5 MeV, the quicker approach based on the
296  //pure Klein-Nishina formula is used
297  if (photonEnergy0 > 5*MeV)
298    {
299      do{
300        do{
301          if ((a2*G4UniformRand()) < a1)
302            {
303              tau = std::pow(taumin,G4UniformRand());
304            }
305          else
306            {
307              tau = std::sqrt(1.0+G4UniformRand()*(taumin*taumin-1.0));
308            }
309          //rejection function
310          TST = (1+tau*(ki1+tau*(ki2+tau*ki3)))/(ki3*tau*(1.0+tau*tau));
311        }while (G4UniformRand()> TST);
312        epsilon=tau;
313        cosTheta = 1.0 - (1.0-tau)/(ki*tau);
314        //Target shell electrons
315        TST = Z*G4UniformRand();
316        iosc = nosc;
317        S=0.0;
318        for (G4int j=0;j<nosc;j++)
319          {
320            occupNb = (G4int) (*(occupationNumber->find(Z)->second))[j];
321            S = S + occupNb;
322            if (S > TST) iosc = j;
323            if (S > TST) break; 
324          }
325        ionEnergy = (*(ionizationEnergy->find(Z)->second))[iosc];
326      }while((epsilon*photonEnergy0-photonEnergy0+ionEnergy) >0);
327    }
328  else //photonEnergy0<5 MeV
329    {
330      //Incoherent scattering function for theta=PI
331      G4double s0=0.0;
332      G4double pzomc=0.0,rni=0.0;
333      G4double aux=0.0;
334      for (G4int i=0;i<nosc;i++){
335        ionEnergy = (*(ionizationEnergy->find(Z)->second))[i];
336        if (photonEnergy0 > ionEnergy)
337          {
338            G4double aux = photonEnergy0*(photonEnergy0-ionEnergy)*2.0;
339            harFunc = (*(hartreeFunction->find(Z)->second))[i]/fine_structure_const;
340            occupNb = (G4int) (*(occupationNumber->find(Z)->second))[i];
341            pzomc = harFunc*(aux-electron_mass_c2*ionEnergy)/
342               (electron_mass_c2*std::sqrt(2.0*aux+ionEnergy*ionEnergy));
343            if (pzomc > 0) 
344              {
345                rni = 1.0-0.5*std::exp(0.5-(std::sqrt(0.5)+std::sqrt(2.0)*pzomc)*(std::sqrt(0.5)+std::sqrt(2.0)*pzomc));
346              }
347            else
348              {
349                rni = 0.5*std::exp(0.5-(std::sqrt(0.5)-std::sqrt(2.0)*pzomc)*(std::sqrt(0.5)-std::sqrt(2.0)*pzomc));
350              }
351            s0 = s0 + occupNb*rni;
352          }
353      }
354     
355      //Sampling tau
356      G4double cdt1;
357      do
358        {
359          if ((G4UniformRand()*a2) < a1)
360            {
361              tau = std::pow(taumin,G4UniformRand());
362            }
363          else
364            {
365              tau = std::sqrt(1.0+G4UniformRand()*(taumin*taumin-1.0));
366            }
367          cdt1 = (1.0-tau)/(ki*tau);
368          S=0.0;
369          //Incoherent scattering function
370          for (G4int i=0;i<nosc;i++){
371            ionEnergy = (*(ionizationEnergy->find(Z)->second))[i];
372            if (photonEnergy0 > ionEnergy) //sum only on excitable levels
373              {
374                aux = photonEnergy0*(photonEnergy0-ionEnergy)*cdt1;
375                harFunc = (*(hartreeFunction->find(Z)->second))[i]/fine_structure_const;
376                occupNb = (G4int) (*(occupationNumber->find(Z)->second))[i];
377                pzomc = harFunc*(aux-electron_mass_c2*ionEnergy)/
378                  (electron_mass_c2*std::sqrt(2.0*aux+ionEnergy*ionEnergy));
379                if (pzomc > 0) 
380                  {
381                    rn[i] = 1.0-0.5*std::exp(0.5-(std::sqrt(0.5)+std::sqrt(2.0)*pzomc)*
382                                             (std::sqrt(0.5)+std::sqrt(2.0)*pzomc));
383                  }
384                else
385                  {
386                    rn[i] = 0.5*std::exp(0.5-(std::sqrt(0.5)-std::sqrt(2.0)*pzomc)*
387                                         (std::sqrt(0.5)-std::sqrt(2.0)*pzomc));
388                  }
389                S = S + occupNb*rn[i];
390                pac[i] = S;
391              }
392            else
393              {
394                pac[i] = S-(1e-06);
395              }
396          }
397          //Rejection function
398          TST = S*(1.0+tau*(ki1+tau*(ki2+tau*ki3)))/(ki3*tau*(1.0+tau*tau)); 
399        }while ((G4UniformRand()*s0) > TST);
400
401      //Target electron shell
402      cosTheta = 1.0 - cdt1;
403      G4double fpzmax=0.0,fpz=0.0;
404      G4double A=0.0;
405      do
406        {
407          do
408            {
409              TST =S*G4UniformRand();
410              iosc=nosc;
411              for (G4int i=0;i<nosc;i++){
412                if (pac[i]>TST) iosc = i;
413                if (pac[i]>TST) break; 
414              }
415              A = G4UniformRand()*rn[iosc];
416              harFunc = (*(hartreeFunction->find(Z)->second))[iosc]/fine_structure_const;
417              occupNb = (G4int) (*(occupationNumber->find(Z)->second))[iosc];
418              if (A < 0.5) {
419                pzomc = (std::sqrt(0.5)-std::sqrt(0.5-std::log(2.0*A)))/
420                  (std::sqrt(2.0)*harFunc);
421              }
422              else
423                {
424                  pzomc = (std::sqrt(0.5-std::log(2.0-2.0*A))-std::sqrt(0.5))/
425                    (std::sqrt(2.0)*harFunc);
426                }
427            } while (pzomc < -1);
428          // F(EP) rejection
429          G4double XQC = 1.0+tau*(tau-2.0*cosTheta);
430          G4double AF = std::sqrt(XQC)*(1.0+tau*(tau-cosTheta)/XQC);
431          if (AF > 0) {
432            fpzmax = 1.0+AF*0.2;
433          }
434          else
435            {
436              fpzmax = 1.0-AF*0.2;
437            }
438          fpz = 1.0+AF*std::max(std::min(pzomc,0.2),-0.2);
439        }while ((fpzmax*G4UniformRand())>fpz);
440 
441      //Energy of the scattered photon
442      G4double T = pzomc*pzomc;
443      G4double b1 = 1.0-T*tau*tau;
444      G4double b2 = 1.0-T*tau*cosTheta;
445      if (pzomc > 0.0)
446        {
447          epsilon = (tau/b1)*(b2+std::sqrt(std::abs(b2*b2-b1*(1.0-T))));
448        }
449      else
450        {
451          epsilon = (tau/b1)*(b2-std::sqrt(std::abs(b2*b2-b1*(1.0-T))));
452        }
453    }
454 
455  G4double sinTheta = std::sqrt(1-cosTheta*cosTheta);
456  G4double phi = twopi * G4UniformRand() ;
457  G4double dirx = sinTheta * std::cos(phi);
458  G4double diry = sinTheta * std::sin(phi);
459  G4double dirz = cosTheta ;
460
461  // Update G4VParticleChange for the scattered photon
462 
463  G4ThreeVector photonDirection1(dirx,diry,dirz);
464  photonDirection1.rotateUz(photonDirection0);
465  aParticleChange.ProposeMomentumDirection(photonDirection1) ;
466  G4double photonEnergy1 = epsilon * photonEnergy0;   
467
468  if (photonEnergy1 > 0.)
469    {
470      aParticleChange.ProposeEnergy(photonEnergy1) ;
471    }
472  else
473    {   
474      aParticleChange.ProposeEnergy(0.) ;
475      aParticleChange.ProposeTrackStatus(fStopAndKill);
476    }
477
478
479  // Kinematics of the scattered electron   
480  G4double diffEnergy = photonEnergy0*(1-epsilon);
481  ionEnergy = (*(ionizationEnergy->find(Z)->second))[iosc];
482  G4double Q2 = photonEnergy0*photonEnergy0+photonEnergy1*(photonEnergy1-2.0*photonEnergy0*cosTheta);
483  G4double cosThetaE; //scattering angle for the electron
484  if (Q2 > 1.0e-12)
485    {
486      cosThetaE = (photonEnergy0-photonEnergy1*cosTheta)/std::sqrt(Q2);
487    }
488  else
489    {
490      cosThetaE = 1.0;
491    }
492  G4double sinThetaE = std::sqrt(1-cosThetaE*cosThetaE);
493  //initialize here, then check photons created by Atomic-Deexcitation, and the final state e-
494  G4int nbOfSecondaries = 0; 
495 
496  std::vector<G4DynamicParticle*>* photonVector=0;
497
498  const G4AtomicTransitionManager* transitionManager = G4AtomicTransitionManager::Instance();
499  const G4AtomicShell* shell = transitionManager->Shell(Z,iosc);
500  G4double bindingEnergy = shell->BindingEnergy();
501  G4int shellId = shell->ShellId();
502  G4double ionEnergyInPenelopeDatabase = ionEnergy;
503  ionEnergy = std::max(bindingEnergy,ionEnergyInPenelopeDatabase); //protection against energy non-conservation
504
505  G4double eKineticEnergy = diffEnergy - ionEnergy; //subtract the excitation energy. If not emitted by fluorescence,
506  //the ionization energy is deposited as local energy deposition
507  G4double localEnergyDeposit = ionEnergy; 
508  G4double energyInFluorescence = 0.; //testing purposes only
509
510  if (eKineticEnergy < 0) 
511    {
512      //It means that there was some problem/mismatch between the two databases. Try to make it work
513      //In this case available Energy (diffEnergy) < ionEnergy
514      //Full residual energy is deposited locally
515      localEnergyDeposit = diffEnergy;
516      eKineticEnergy = 0.0;
517    }
518
519  //the local energy deposit is what remains: part of this may be spent for fluorescence.
520 
521  if (fUseAtomicDeexcitation)
522    { 
523      G4int nPhotons=0;
524     
525      const G4ProductionCutsTable* theCoupleTable=
526        G4ProductionCutsTable::GetProductionCutsTable();
527      size_t indx = couple->GetIndex();
528
529      G4double cutg = (*(theCoupleTable->GetEnergyCutsVector(0)))[indx];
530      cutg = std::max(cutForLowEnergySecondaryPhotons,cutg);
531
532      G4double cute = (*(theCoupleTable->GetEnergyCutsVector(1)))[indx];
533      cute = std::max(cutForLowEnergySecondaryPhotons,cute);
534     
535      G4DynamicParticle* aPhoton;
536      G4AtomicDeexcitation deexcitationManager;
537     
538      if (Z>5 && (localEnergyDeposit > cutg || localEnergyDeposit > cute))
539        {
540          photonVector = deexcitationManager.GenerateParticles(Z,shellId);
541          for (size_t k=0;k<photonVector->size();k++){
542            aPhoton = (*photonVector)[k];
543            if (aPhoton)
544              {
545                G4double itsCut = cutg;
546                if (aPhoton->GetDefinition() == G4Electron::Electron()) itsCut = cute;
547                G4double itsEnergy = aPhoton->GetKineticEnergy();
548                if (itsEnergy > itsCut && itsEnergy <= localEnergyDeposit)
549                  {
550                    nPhotons++;
551                    localEnergyDeposit -= itsEnergy;
552                    energyInFluorescence += itsEnergy;
553                  }
554                else
555                  {
556                    delete aPhoton;
557                    (*photonVector)[k]=0;
558                  }
559              }
560          }
561        }
562      nbOfSecondaries=nPhotons;
563    }
564
565 
566  // Generate the electron only if with large enough range w.r.t. cuts and safety
567  G4double safety = aStep.GetPostStepPoint()->GetSafety();
568  G4DynamicParticle* electron = 0;
569  if (rangeTest->Escape(G4Electron::Electron(),couple,eKineticEnergy,safety) && 
570      eKineticEnergy>cutForLowEnergySecondaryPhotons)
571    {
572      G4double xEl = sinThetaE * std::cos(phi+pi); 
573      G4double yEl = sinThetaE * std::sin(phi+pi);
574      G4double zEl = cosThetaE;
575      G4ThreeVector eDirection(xEl,yEl,zEl); //electron direction
576      eDirection.rotateUz(photonDirection0);
577      electron = new G4DynamicParticle (G4Electron::Electron(),
578                                        eDirection,eKineticEnergy) ;
579      nbOfSecondaries++;
580    }
581  else
582    {
583      localEnergyDeposit += eKineticEnergy;
584    }
585
586  aParticleChange.SetNumberOfSecondaries(nbOfSecondaries);
587  if (electron) aParticleChange.AddSecondary(electron);
588
589  //This block below is executed only if there is at least one secondary photon produced by
590  //AtomicDeexcitation
591  if (photonVector)
592    {
593      for (size_t ll=0;ll<photonVector->size();ll++)
594        {
595          if ((*photonVector)[ll]) aParticleChange.AddSecondary((*photonVector)[ll]);
596        }
597    }
598  delete photonVector;
599  if (localEnergyDeposit < 0)
600    {
601      G4cout << "WARNING-" 
602             << "G4PenelopeCompton::PostStepDoIt - Negative energy deposit"
603             << G4endl;
604      localEnergyDeposit=0.;
605    }
606  aParticleChange.ProposeLocalEnergyDeposit(localEnergyDeposit);
607 
608
609  if (verboseLevel > 1)
610    {
611      G4cout << "-----------------------------------------------------------" << G4endl;
612      G4cout << "Energy balance from G4PenelopeCompton" << G4endl;
613      G4cout << "Incoming photon energy: " << photonEnergy0/keV << " keV" << G4endl;
614      G4cout << "-----------------------------------------------------------" << G4endl;
615      G4cout << "Scattered photon: " << photonEnergy1/keV << " keV" << G4endl;
616      G4double electronEnergy = 0.;
617      if (electron)
618        electronEnergy = eKineticEnergy;
619      G4cout << "Scattered electron " << electronEnergy/keV << " keV" << G4endl;
620      G4cout << "Fluorescence: " << energyInFluorescence/keV << " keV" << G4endl;
621      G4cout << "Local energy deposit " << localEnergyDeposit/keV << " keV" << G4endl;
622      G4cout << "Total final state: " << (photonEnergy1+electronEnergy+energyInFluorescence+localEnergyDeposit)/keV << 
623        " keV" << G4endl;
624      G4cout << "-----------------------------------------------------------" << G4endl;
625    }
626
627  return G4VDiscreteProcess::PostStepDoIt( aTrack, aStep);
628}
629
630G4bool G4PenelopeCompton::IsApplicable(const G4ParticleDefinition& particle)
631{
632  return ( &particle == G4Gamma::Gamma() ); 
633}
634
635G4double G4PenelopeCompton::GetMeanFreePath(const G4Track& track, 
636                                            G4double, // previousStepSize
637                                            G4ForceCondition*)
638{
639  const G4DynamicParticle* photon = track.GetDynamicParticle();
640  G4double energy = photon->GetKineticEnergy();
641  G4Material* material = track.GetMaterial();
642  size_t materialIndex = material->GetIndex();
643
644  G4double meanFreePath;
645  if (energy > highEnergyLimit) meanFreePath = meanFreePathTable->FindValue(highEnergyLimit,materialIndex);
646  else if (energy < lowEnergyLimit) meanFreePath = DBL_MAX;
647  else meanFreePath = meanFreePathTable->FindValue(energy,materialIndex);
648  return meanFreePath;
649}
650
651
652void G4PenelopeCompton::ReadData()
653{
654  char* path = getenv("G4LEDATA");
655  if (!path)
656    {
657      G4String excep = "G4PenelopeCompton - G4LEDATA environment variable not set!";
658      G4Exception(excep);
659    }
660  G4String pathString(path);
661  G4String pathFile = pathString + "/penelope/compton-pen.dat";
662  std::ifstream file(pathFile);
663  std::filebuf* lsdp = file.rdbuf();
664 
665  if (!(lsdp->is_open()))
666    {
667      G4String excep = "G4PenelopeCompton - data file " + pathFile + " not found!";
668      G4Exception(excep);
669    }
670
671  G4int k1,test,test1;
672  G4double a1,a2;
673  G4int Z=1,nLevels=0;
674  G4DataVector* f;
675  G4DataVector* u;
676  G4DataVector* j;
677
678  do{
679    f = new G4DataVector;
680    u = new G4DataVector;
681    j = new G4DataVector;
682    file >> Z >> nLevels;
683    for (G4int h=0;h<nLevels;h++){
684      file >> k1 >> a1 >> a2;
685      f->push_back((G4double) k1);
686      u->push_back(a1);
687      j->push_back(a2);
688    }
689    ionizationEnergy->insert(std::make_pair(Z,u));
690    hartreeFunction->insert(std::make_pair(Z,j));
691    occupationNumber->insert(std::make_pair(Z,f));
692    file >> test >> test1; //-1 -1 close the data for each Z
693    if (test > 0) {
694      G4String excep = "G4PenelopeCompton - data file corrupted!";
695      G4Exception(excep);
696    }
697  }while (test != -2); //the very last Z is closed with -2 instead of -1
698}
699
700G4double G4PenelopeCompton::CrossSection(G4double energy,G4int Z)
701{
702  G4double cs=0.0;
703  energyForIntegration=energy; 
704  ZForIntegration = Z;
705  if (energy< 5*MeV)
706    {
707      G4PenelopeIntegrator<G4PenelopeCompton,G4double (G4PenelopeCompton::*)(G4double)> theIntegrator;
708      cs = theIntegrator.Calculate(this,&G4PenelopeCompton::DifferentialCrossSection,-1.0,1.0,1e-05);
709    }
710  else
711    {
712      G4double ki=energy/electron_mass_c2;
713      G4double ki3=ki*ki;
714      G4double ki2=1.0+2*ki;
715      G4double ki1=ki3-ki2-1.0;
716      G4double t0=1.0/(ki2);
717      G4double csl = 0.5*ki3*t0*t0+ki2*t0+ki1*std::log(t0)-(1.0/t0);
718      G4int nosc = occupationNumber->find(Z)->second->size();
719      for (G4int i=0;i<nosc;i++)
720        {
721          G4double ionEnergy = (*(ionizationEnergy->find(Z)->second))[i];
722          G4double tau=(energy-ionEnergy)/energy;
723          if (tau > t0)
724            {
725              G4double csu = 0.5*ki3*tau*tau+ki2*tau+ki1*std::log(tau)-(1.0/tau);
726              G4int f = (G4int) (*(occupationNumber->find(Z)->second))[i];
727              cs = cs + f*(csu-csl);
728            }
729        }
730      cs=pi*classic_electr_radius*classic_electr_radius*cs/(ki*ki3);
731    }
732  return cs;
733}
734
735 
736G4double G4PenelopeCompton::DifferentialCrossSection(G4double cosTheta)
737{
738  const G4double k2 = std::sqrt(2.0);
739  const G4double k1 = std::sqrt(0.5);
740  const G4double k12 = 0.5;
741  G4double cdt1 = 1.0-cosTheta;
742  G4double energy = energyForIntegration;
743  G4int Z = ZForIntegration;
744  G4double ionEnergy=0.0,Pzimax=0.0,XKN=0.0;
745  G4double diffCS=0.0;
746  G4double x=0.0,siap=0.0;
747  G4double harFunc=0.0;
748  G4int occupNb;
749  //energy of Compton line;
750  G4double EOEC = 1.0+(energy/electron_mass_c2)*cdt1; 
751  G4double ECOE = 1.0/EOEC;
752  //Incoherent scattering function (analytical profile)
753  G4double sia = 0.0;
754  G4int nosc = occupationNumber->find(Z)->second->size();
755  for (G4int i=0;i<nosc;i++){
756    ionEnergy = (*(ionizationEnergy->find(Z)->second))[i];
757    //Sum only of those shells for which E>Eion
758    if (energy > ionEnergy)
759      {
760        G4double aux = energy * (energy-ionEnergy)*cdt1;
761        Pzimax = (aux - electron_mass_c2*ionEnergy)/(electron_mass_c2*std::sqrt(2*aux+ionEnergy*ionEnergy));
762        harFunc = (*(hartreeFunction->find(Z)->second))[i]/fine_structure_const;
763        occupNb = (G4int) (*(occupationNumber->find(Z)->second))[i];
764        x = harFunc*Pzimax;
765        if (x > 0) 
766          {
767            siap = 1.0-0.5*std::exp(k12-(k1+k2*x)*(k1+k2*x));
768          }
769        else
770          {
771            siap = 0.5*std::exp(k12-(k1-k2*x)*(k1-k2*x));
772          }
773        sia = sia + occupNb*siap; //sum of all contributions;
774      }
775  }
776  XKN = EOEC+ECOE-1+cosTheta*cosTheta;
777  diffCS = pi*classic_electr_radius*classic_electr_radius*ECOE*ECOE*XKN*sia;
778  return diffCS;
779}
780
781G4int G4PenelopeCompton::SelectRandomAtomForCompton(const G4Material* material,G4double energy) const
782{
783  G4int nElements = material->GetNumberOfElements();
784  //Special case: the material consists of one element
785  if (nElements == 1)
786    {
787      G4int Z = (G4int) material->GetZ();
788      return Z;
789    }
790
791  //Composite material
792  const G4ElementVector* elementVector = material->GetElementVector();
793  size_t materialIndex = material->GetIndex();
794
795  G4VEMDataSet* materialSet = (*matCrossSections)[materialIndex]; 
796  G4double materialCrossSection0 = 0.0;
797  G4DataVector cross;
798  cross.clear();
799  G4int i;
800  for (i=0;i<nElements;i++)
801    {
802      G4double cr = (materialSet->GetComponent(i))->FindValue(energy);
803      materialCrossSection0 += cr;
804      cross.push_back(materialCrossSection0); //cumulative cross section
805    }
806
807  G4double random = G4UniformRand()*materialCrossSection0;
808  for (i=0;i<nElements;i++)
809    {
810      if (random <= cross[i]) return (G4int) (*elementVector)[i]->GetZ();
811    }
812  //It should never get here
813  return 0;
814}
815 
Note: See TracBrowser for help on using the repository browser.