G4PenelopeComptonModel.cc

Go to the documentation of this file.
00001 //
00002 // ********************************************************************
00003 // * License and Disclaimer                                           *
00004 // *                                                                  *
00005 // * The  Geant4 software  is  copyright of the Copyright Holders  of *
00006 // * the Geant4 Collaboration.  It is provided  under  the terms  and *
00007 // * conditions of the Geant4 Software License,  included in the file *
00008 // * LICENSE and available at  http://cern.ch/geant4/license .  These *
00009 // * include a list of copyright holders.                             *
00010 // *                                                                  *
00011 // * Neither the authors of this software system, nor their employing *
00012 // * institutes,nor the agencies providing financial support for this *
00013 // * work  make  any representation or  warranty, express or implied, *
00014 // * regarding  this  software system or assume any liability for its *
00015 // * use.  Please see the license in the file  LICENSE  and URL above *
00016 // * for the full disclaimer and the limitation of liability.         *
00017 // *                                                                  *
00018 // * This  code  implementation is the result of  the  scientific and *
00019 // * technical work of the GEANT4 collaboration.                      *
00020 // * By using,  copying,  modifying or  distributing the software (or *
00021 // * any work based  on the software)  you  agree  to acknowledge its *
00022 // * use  in  resulting  scientific  publications,  and indicate your *
00023 // * acceptance of all terms of the Geant4 Software license.          *
00024 // ********************************************************************
00025 //
00026 // $Id$
00027 //
00028 // Author: Luciano Pandola
00029 //
00030 // History:
00031 // --------
00032 // 15 Feb 2010   L Pandola  Implementation
00033 // 18 Mar 2010   L Pandola  Removed GetAtomsPerMolecule(), now demanded 
00034 //                            to G4PenelopeOscillatorManager
00035 // 01 Feb 2011   L Pandola  Suppress fake energy-violation warning when Auger is active.
00036 //                          Make sure that fluorescence/Auger is generated only if 
00037 //                          above threshold
00038 // 24 May 2011   L Pandola  Renamed (make v2008 as default Penelope)
00039 // 10 Jun 2011   L Pandola  Migrate atomic deexcitation interface
00040 //
00041 #include "G4PenelopeComptonModel.hh"
00042 #include "G4PhysicalConstants.hh"
00043 #include "G4SystemOfUnits.hh"
00044 #include "G4ParticleDefinition.hh"
00045 #include "G4MaterialCutsCouple.hh"
00046 #include "G4DynamicParticle.hh"
00047 #include "G4VEMDataSet.hh"
00048 #include "G4PhysicsTable.hh"
00049 #include "G4PhysicsLogVector.hh"
00050 #include "G4AtomicTransitionManager.hh"
00051 #include "G4AtomicShell.hh"
00052 #include "G4Gamma.hh"
00053 #include "G4Electron.hh"
00054 #include "G4PenelopeOscillatorManager.hh"
00055 #include "G4PenelopeOscillator.hh"
00056 #include "G4LossTableManager.hh"
00057 
00058 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
00059 
00060 
00061 G4PenelopeComptonModel::G4PenelopeComptonModel(const G4ParticleDefinition*,
00062                                                const G4String& nam)
00063   :G4VEmModel(nam),fParticleChange(0),isInitialised(false),fAtomDeexcitation(0),
00064    oscManager(0)
00065 {
00066   fIntrinsicLowEnergyLimit = 100.0*eV;
00067   fIntrinsicHighEnergyLimit = 100.0*GeV;
00068   //  SetLowEnergyLimit(fIntrinsicLowEnergyLimit);
00069   SetHighEnergyLimit(fIntrinsicHighEnergyLimit);
00070   //
00071   oscManager = G4PenelopeOscillatorManager::GetOscillatorManager();
00072 
00073   verboseLevel= 0;
00074   // Verbosity scale:
00075   // 0 = nothing 
00076   // 1 = warning for energy non-conservation 
00077   // 2 = details of energy budget
00078   // 3 = calculation of cross sections, file openings, sampling of atoms
00079   // 4 = entering in methods
00080 
00081   //Mark this model as "applicable" for atomic deexcitation
00082   SetDeexcitationFlag(true);
00083 
00084   fTransitionManager = G4AtomicTransitionManager::Instance();
00085 }
00086 
00087 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
00088 
00089 G4PenelopeComptonModel::~G4PenelopeComptonModel()
00090 {;}
00091 
00092 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
00093 
00094 void G4PenelopeComptonModel::Initialise(const G4ParticleDefinition*,
00095                                           const G4DataVector&)
00096 {
00097   if (verboseLevel > 3)
00098     G4cout << "Calling G4PenelopeComptonModel::Initialise()" << G4endl;
00099 
00100   fAtomDeexcitation = G4LossTableManager::Instance()->AtomDeexcitation();
00101   //Issue warning if the AtomicDeexcitation has not been declared
00102   if (!fAtomDeexcitation)
00103     {
00104       G4cout << G4endl;
00105       G4cout << "WARNING from G4PenelopeComptonModel " << G4endl;
00106       G4cout << "Atomic de-excitation module is not instantiated, so there will not be ";
00107       G4cout << "any fluorescence/Auger emission." << G4endl;
00108       G4cout << "Please make sure this is intended" << G4endl;
00109     }
00110 
00111 
00112   if (verboseLevel > 0) 
00113     {
00114       G4cout << "Penelope Compton model v2008 is initialized " << G4endl
00115              << "Energy range: "
00116              << LowEnergyLimit() / keV << " keV - "
00117              << HighEnergyLimit() / GeV << " GeV";  
00118     }
00119   
00120   if(isInitialised) return;
00121   fParticleChange = GetParticleChangeForGamma();
00122   isInitialised = true; 
00123 
00124 }
00125 
00126 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
00127 
00128 G4double G4PenelopeComptonModel::CrossSectionPerVolume(const G4Material* material,
00129                                                const G4ParticleDefinition* p,
00130                                                G4double energy,
00131                                                G4double,
00132                                                G4double)
00133 {
00134   // Penelope model v2008 to calculate the Compton scattering cross section:
00135   // D. Brusa et al., Nucl. Instrum. Meth. A 379 (1996) 167
00136   // 
00137   // The cross section for Compton scattering is calculated according to the Klein-Nishina 
00138   // formula for energy > 5 MeV.
00139   // For E < 5 MeV it is used a parametrization for the differential cross-section dSigma/dOmega,
00140   // which is integrated numerically in cos(theta), G4PenelopeComptonModel::DifferentialCrossSection().
00141   // The parametrization includes the J(p) 
00142   // distribution profiles for the atomic shells, that are tabulated from Hartree-Fock calculations 
00143   // from F. Biggs et al., At. Data Nucl. Data Tables 16 (1975) 201
00144   //
00145   if (verboseLevel > 3)
00146     G4cout << "Calling CrossSectionPerVolume() of G4PenelopeComptonModel" << G4endl;
00147   SetupForMaterial(p, material, energy);
00148 
00149   //Retrieve the oscillator table for this material
00150   G4PenelopeOscillatorTable* theTable = oscManager->GetOscillatorTableCompton(material);
00151 
00152   G4double cs = 0;
00153 
00154   if (energy < 5*MeV) //explicit calculation for E < 5 MeV
00155     {
00156       size_t numberOfOscillators = theTable->size();
00157       for (size_t i=0;i<numberOfOscillators;i++)
00158         {
00159           G4PenelopeOscillator* theOsc = (*theTable)[i];
00160           //sum contributions coming from each oscillator
00161           cs += OscillatorTotalCrossSection(energy,theOsc);
00162         }
00163     }
00164   else //use Klein-Nishina for E>5 MeV
00165     cs = KleinNishinaCrossSection(energy,material);
00166        
00167   //cross sections are in units of pi*classic_electr_radius^2
00168   cs *= pi*classic_electr_radius*classic_electr_radius;
00169 
00170   //Now, cs is the cross section *per molecule*, let's calculate the 
00171   //cross section per volume
00172 
00173   G4double atomDensity = material->GetTotNbOfAtomsPerVolume();
00174   G4double atPerMol =  oscManager->GetAtomsPerMolecule(material);
00175 
00176   if (verboseLevel > 3)
00177     G4cout << "Material " << material->GetName() << " has " << atPerMol << 
00178       "atoms per molecule" << G4endl;
00179 
00180   G4double moleculeDensity = 0.;
00181 
00182   if (atPerMol)
00183     moleculeDensity = atomDensity/atPerMol;
00184 
00185   G4double csvolume = cs*moleculeDensity;
00186   
00187   if (verboseLevel > 2)
00188     G4cout << "Compton mean free path at " << energy/keV << " keV for material " << 
00189             material->GetName() << " = " << (1./csvolume)/mm << " mm" << G4endl;
00190   return csvolume;
00191 }
00192 
00193 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
00194 
00195 //This is a dummy method. Never inkoved by the tracking, it just issues
00196 //a warning if one tries to get Cross Sections per Atom via the
00197 //G4EmCalculator.
00198 G4double G4PenelopeComptonModel::ComputeCrossSectionPerAtom(const G4ParticleDefinition*,
00199                                                              G4double,
00200                                                              G4double,
00201                                                              G4double,
00202                                                              G4double,
00203                                                              G4double)
00204 {
00205   G4cout << "*** G4PenelopeComptonModel -- WARNING ***" << G4endl;
00206   G4cout << "Penelope Compton model v2008 does not calculate cross section _per atom_ " << G4endl;
00207   G4cout << "so the result is always zero. For physics values, please invoke " << G4endl;
00208   G4cout << "GetCrossSectionPerVolume() or GetMeanFreePath() via the G4EmCalculator" << G4endl;
00209   return 0;
00210 }
00211 
00212 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
00213 
00214 void G4PenelopeComptonModel::SampleSecondaries(std::vector<G4DynamicParticle*>* fvect,
00215                                                const G4MaterialCutsCouple* couple,
00216                                               const G4DynamicParticle* aDynamicGamma,
00217                                               G4double,
00218                                               G4double)
00219 {
00220   
00221   // Penelope model v2008 to sample the Compton scattering final state.
00222   // D. Brusa et al., Nucl. Instrum. Meth. A 379 (1996) 167
00223   // The model determines also the original shell from which the electron is expelled, 
00224   // in order to produce fluorescence de-excitation (from G4DeexcitationManager)
00225   // 
00226   // The final state for Compton scattering is calculated according to the Klein-Nishina 
00227   // formula for energy > 5 MeV. In this case, the Doppler broadening is negligible and 
00228   // one can assume that the target electron is at rest.
00229   // For E < 5 MeV it is used the parametrization for the differential cross-section dSigma/dOmega,
00230   // to sample the scattering angle and the energy of the emerging electron, which is  
00231   // G4PenelopeComptonModel::DifferentialCrossSection(). The rejection method is 
00232   // used to sample cos(theta). The efficiency increases monotonically with photon energy and is 
00233   // nearly independent on the Z; typical values are 35%, 80% and 95% for 1 keV, 1 MeV and 10 MeV, 
00234   // respectively.
00235   // The parametrization includes the J(p) distribution profiles for the atomic shells, that are 
00236   // tabulated 
00237   // from Hartree-Fock calculations from F. Biggs et al., At. Data Nucl. Data Tables 16 (1975) 201. 
00238   // Doppler broadening is included.
00239   //
00240 
00241   if (verboseLevel > 3)
00242     G4cout << "Calling SampleSecondaries() of G4PenelopeComptonModel" << G4endl;
00243   
00244   G4double photonEnergy0 = aDynamicGamma->GetKineticEnergy();
00245 
00246   if (photonEnergy0 <= fIntrinsicLowEnergyLimit)
00247     {
00248       fParticleChange->ProposeTrackStatus(fStopAndKill);
00249       fParticleChange->SetProposedKineticEnergy(0.);
00250       fParticleChange->ProposeLocalEnergyDeposit(photonEnergy0);
00251       return ;
00252     }
00253 
00254   G4ParticleMomentum photonDirection0 = aDynamicGamma->GetMomentumDirection();
00255   const G4Material* material = couple->GetMaterial();
00256 
00257   G4PenelopeOscillatorTable* theTable = oscManager->GetOscillatorTableCompton(material); 
00258 
00259   const G4int nmax = 64;
00260   G4double rn[nmax]={0.0};
00261   G4double pac[nmax]={0.0};
00262   
00263   G4double S=0.0;
00264   G4double epsilon = 0.0;
00265   G4double cosTheta = 1.0;
00266   G4double hartreeFunc = 0.0;
00267   G4double oscStren = 0.0;
00268   size_t numberOfOscillators = theTable->size();
00269   size_t targetOscillator = 0;
00270   G4double ionEnergy = 0.0*eV;
00271 
00272   G4double ek = photonEnergy0/electron_mass_c2;
00273   G4double ek2 = 2.*ek+1.0;
00274   G4double eks = ek*ek;
00275   G4double ek1 = eks-ek2-1.0;
00276 
00277   G4double taumin = 1.0/ek2;
00278   G4double a1 = std::log(ek2);
00279   G4double a2 = a1+2.0*ek*(1.0+ek)/(ek2*ek2);
00280 
00281   G4double TST = 0;
00282   G4double tau = 0.;
00283  
00284   //If the incoming photon is above 5 MeV, the quicker approach based on the 
00285   //pure Klein-Nishina formula is used
00286   if (photonEnergy0 > 5*MeV)
00287     {
00288       do{
00289         do{
00290           if ((a2*G4UniformRand()) < a1)
00291             tau = std::pow(taumin,G4UniformRand());         
00292           else
00293             tau = std::sqrt(1.0+G4UniformRand()*(taumin*taumin-1.0));       
00294           //rejection function
00295           TST = (1.0+tau*(ek1+tau*(ek2+tau*eks)))/(eks*tau*(1.0+tau*tau));
00296         }while (G4UniformRand()> TST);
00297         epsilon=tau;
00298         cosTheta = 1.0 - (1.0-tau)/(ek*tau);
00299 
00300         //Target shell electrons        
00301         TST = oscManager->GetTotalZ(material)*G4UniformRand();
00302         targetOscillator = numberOfOscillators-1; //last level
00303         S=0.0;
00304         G4bool levelFound = false;
00305         for (size_t j=0;j<numberOfOscillators && !levelFound; j++)
00306           {
00307             S += (*theTable)[j]->GetOscillatorStrength();           
00308             if (S > TST) 
00309               {
00310                 targetOscillator = j;
00311                 levelFound = true;
00312               }
00313           }
00314         //check whether the level is valid
00315         ionEnergy = (*theTable)[targetOscillator]->GetIonisationEnergy();
00316       }while((epsilon*photonEnergy0-photonEnergy0+ionEnergy) >0);
00317     }
00318   else //photonEnergy0 < 5 MeV
00319     {
00320       //Incoherent scattering function for theta=PI
00321       G4double s0=0.0;
00322       G4double pzomc=0.0;
00323       G4double rni=0.0;
00324       G4double aux=0.0;
00325       for (size_t i=0;i<numberOfOscillators;i++)
00326         {
00327           ionEnergy = (*theTable)[i]->GetIonisationEnergy();
00328           if (photonEnergy0 > ionEnergy)
00329             {
00330               G4double aux2 = photonEnergy0*(photonEnergy0-ionEnergy)*2.0;
00331               hartreeFunc = (*theTable)[i]->GetHartreeFactor(); 
00332               oscStren = (*theTable)[i]->GetOscillatorStrength();
00333               pzomc = hartreeFunc*(aux2-electron_mass_c2*ionEnergy)/
00334                 (electron_mass_c2*std::sqrt(2.0*aux2+ionEnergy*ionEnergy));
00335               if (pzomc > 0)    
00336                 rni = 1.0-0.5*std::exp(0.5-(std::sqrt(0.5)+std::sqrt(2.0)*pzomc)*
00337                                        (std::sqrt(0.5)+std::sqrt(2.0)*pzomc));          
00338               else                
00339                 rni = 0.5*std::exp(0.5-(std::sqrt(0.5)-std::sqrt(2.0)*pzomc)*
00340                                    (std::sqrt(0.5)-std::sqrt(2.0)*pzomc));          
00341               s0 += oscStren*rni;
00342             }
00343         }      
00344       //Sampling tau
00345       G4double cdt1 = 0.;
00346       do
00347         {
00348           if ((G4UniformRand()*a2) < a1)            
00349             tau = std::pow(taumin,G4UniformRand());         
00350           else      
00351             tau = std::sqrt(1.0+G4UniformRand()*(taumin*taumin-1.0));       
00352           cdt1 = (1.0-tau)/(ek*tau);
00353           //Incoherent scattering function
00354           S = 0.;
00355           for (size_t i=0;i<numberOfOscillators;i++)
00356             {
00357               ionEnergy = (*theTable)[i]->GetIonisationEnergy();
00358               if (photonEnergy0 > ionEnergy) //sum only on excitable levels
00359                 {
00360                   aux = photonEnergy0*(photonEnergy0-ionEnergy)*cdt1;
00361                   hartreeFunc = (*theTable)[i]->GetHartreeFactor(); 
00362                   oscStren = (*theTable)[i]->GetOscillatorStrength();
00363                   pzomc = hartreeFunc*(aux-electron_mass_c2*ionEnergy)/
00364                     (electron_mass_c2*std::sqrt(2.0*aux+ionEnergy*ionEnergy));
00365                   if (pzomc > 0) 
00366                     rn[i] = 1.0-0.5*std::exp(0.5-(std::sqrt(0.5)+std::sqrt(2.0)*pzomc)*
00367                                              (std::sqrt(0.5)+std::sqrt(2.0)*pzomc));                
00368                   else              
00369                     rn[i] = 0.5*std::exp(0.5-(std::sqrt(0.5)-std::sqrt(2.0)*pzomc)*
00370                                          (std::sqrt(0.5)-std::sqrt(2.0)*pzomc));                    
00371                   S += oscStren*rn[i];
00372                   pac[i] = S;
00373                 }
00374               else
00375                 pac[i] = S-1e-6;                
00376             }
00377           //Rejection function
00378           TST = S*(1.0+tau*(ek1+tau*(ek2+tau*eks)))/(eks*tau*(1.0+tau*tau));  
00379         }while ((G4UniformRand()*s0) > TST);
00380 
00381       cosTheta = 1.0 - cdt1;
00382       G4double fpzmax=0.0,fpz=0.0;
00383       G4double A=0.0;
00384       //Target electron shell
00385       do
00386         {
00387           do
00388             {
00389               TST = S*G4UniformRand();
00390               targetOscillator = numberOfOscillators-1; //last level
00391               G4bool levelFound = false;
00392               for (size_t i=0;i<numberOfOscillators && !levelFound;i++)
00393                 {
00394                   if (pac[i]>TST) 
00395                     {                
00396                       targetOscillator = i;
00397                       levelFound = true;
00398                     }
00399                 }
00400               A = G4UniformRand()*rn[targetOscillator];
00401               hartreeFunc = (*theTable)[targetOscillator]->GetHartreeFactor(); 
00402               oscStren = (*theTable)[targetOscillator]->GetOscillatorStrength();
00403               if (A < 0.5) 
00404                 pzomc = (std::sqrt(0.5)-std::sqrt(0.5-std::log(2.0*A)))/
00405                   (std::sqrt(2.0)*hartreeFunc);       
00406               else              
00407                 pzomc = (std::sqrt(0.5-std::log(2.0-2.0*A))-std::sqrt(0.5))/
00408                   (std::sqrt(2.0)*hartreeFunc); 
00409             } while (pzomc < -1);
00410 
00411           // F(EP) rejection
00412           G4double XQC = 1.0+tau*(tau-2.0*cosTheta);
00413           G4double AF = std::sqrt(XQC)*(1.0+tau*(tau-cosTheta)/XQC);
00414           if (AF > 0) 
00415             fpzmax = 1.0+AF*0.2;
00416           else
00417             fpzmax = 1.0-AF*0.2;            
00418           fpz = 1.0+AF*std::max(std::min(pzomc,0.2),-0.2);
00419         }while ((fpzmax*G4UniformRand())>fpz);
00420   
00421       //Energy of the scattered photon
00422       G4double T = pzomc*pzomc;
00423       G4double b1 = 1.0-T*tau*tau;
00424       G4double b2 = 1.0-T*tau*cosTheta;
00425       if (pzomc > 0.0)  
00426         epsilon = (tau/b1)*(b2+std::sqrt(std::abs(b2*b2-b1*(1.0-T))));  
00427       else      
00428         epsilon = (tau/b1)*(b2-std::sqrt(std::abs(b2*b2-b1*(1.0-T))));  
00429     } //energy < 5 MeV
00430   
00431   //Ok, the kinematics has been calculated.
00432   G4double sinTheta = std::sqrt(1-cosTheta*cosTheta);
00433   G4double phi = twopi * G4UniformRand() ;
00434   G4double dirx = sinTheta * std::cos(phi);
00435   G4double diry = sinTheta * std::sin(phi);
00436   G4double dirz = cosTheta ;
00437 
00438   // Update G4VParticleChange for the scattered photon
00439   G4ThreeVector photonDirection1(dirx,diry,dirz);
00440   photonDirection1.rotateUz(photonDirection0);
00441   fParticleChange->ProposeMomentumDirection(photonDirection1) ;
00442 
00443   G4double photonEnergy1 = epsilon * photonEnergy0;
00444 
00445   if (photonEnergy1 > 0.)  
00446     fParticleChange->SetProposedKineticEnergy(photonEnergy1) ;  
00447   else
00448   {
00449     fParticleChange->SetProposedKineticEnergy(0.) ;
00450     fParticleChange->ProposeTrackStatus(fStopAndKill);
00451   }
00452   
00453   //Create scattered electron
00454   G4double diffEnergy = photonEnergy0*(1-epsilon);
00455   ionEnergy = (*theTable)[targetOscillator]->GetIonisationEnergy();
00456 
00457   G4double Q2 = 
00458     photonEnergy0*photonEnergy0+photonEnergy1*(photonEnergy1-2.0*photonEnergy0*cosTheta);
00459   G4double cosThetaE = 0.; //scattering angle for the electron
00460 
00461   if (Q2 > 1.0e-12)    
00462     cosThetaE = (photonEnergy0-photonEnergy1*cosTheta)/std::sqrt(Q2);    
00463   else    
00464     cosThetaE = 1.0;    
00465   G4double sinThetaE = std::sqrt(1-cosThetaE*cosThetaE);
00466 
00467   //Now, try to handle fluorescence
00468   //Notice: merged levels are indicated with Z=0 and flag=30
00469   G4int shFlag = (*theTable)[targetOscillator]->GetShellFlag(); 
00470   G4int Z = (G4int) (*theTable)[targetOscillator]->GetParentZ();
00471 
00472   //initialize here, then check photons created by Atomic-Deexcitation, and the final state e-
00473   G4double bindingEnergy = 0.*eV;
00474   const G4AtomicShell* shell = 0;
00475 
00476   //Real level
00477   if (Z > 0 && shFlag<30)
00478     {
00479       shell = fTransitionManager->Shell(Z,shFlag-1);
00480       bindingEnergy = shell->BindingEnergy();    
00481     }
00482 
00483   G4double ionEnergyInPenelopeDatabase = ionEnergy;
00484   //protection against energy non-conservation
00485   ionEnergy = std::max(bindingEnergy,ionEnergyInPenelopeDatabase);  
00486 
00487   //subtract the excitation energy. If not emitted by fluorescence
00488   //the ionization energy is deposited as local energy deposition
00489   G4double eKineticEnergy = diffEnergy - ionEnergy; 
00490   G4double localEnergyDeposit = ionEnergy; 
00491   G4double energyInFluorescence = 0.; //testing purposes only
00492   G4double energyInAuger = 0; //testing purposes
00493 
00494   if (eKineticEnergy < 0) 
00495     {
00496       //It means that there was some problem/mismatch between the two databases. 
00497       //Try to make it work
00498       //In this case available Energy (diffEnergy) < ionEnergy
00499       //Full residual energy is deposited locally
00500       localEnergyDeposit = diffEnergy;
00501       eKineticEnergy = 0.0;
00502     }
00503 
00504   //the local energy deposit is what remains: part of this may be spent for fluorescence.
00505   //Notice: shell might be NULL (invalid!) if shFlag=30. Must be protected
00506   //Now, take care of fluorescence, if required
00507   if (fAtomDeexcitation && shell)
00508     {      
00509       G4int index = couple->GetIndex();
00510       if (fAtomDeexcitation->CheckDeexcitationActiveRegion(index))
00511         {       
00512           size_t nBefore = fvect->size();
00513           fAtomDeexcitation->GenerateParticles(fvect,shell,Z,index);
00514           size_t nAfter = fvect->size(); 
00515       
00516           if (nAfter > nBefore) //actual production of fluorescence
00517             {
00518               for (size_t j=nBefore;j<nAfter;j++) //loop on products
00519                 {
00520                   G4double itsEnergy = ((*fvect)[j])->GetKineticEnergy();
00521                   localEnergyDeposit -= itsEnergy;
00522                   if (((*fvect)[j])->GetParticleDefinition() == G4Gamma::Definition())
00523                     energyInFluorescence += itsEnergy;
00524                   else if (((*fvect)[j])->GetParticleDefinition() == G4Electron::Definition())
00525                     energyInAuger += itsEnergy;
00526                   
00527                 }
00528             }
00529 
00530         }
00531     }
00532 
00533 
00534   /*
00535   if(DeexcitationFlag() && Z > 5 && shellId>0) {
00536 
00537     const G4ProductionCutsTable* theCoupleTable=
00538       G4ProductionCutsTable::GetProductionCutsTable();
00539 
00540     size_t index = couple->GetIndex();
00541     G4double cutg = (*(theCoupleTable->GetEnergyCutsVector(0)))[index];
00542     G4double cute = (*(theCoupleTable->GetEnergyCutsVector(1)))[index];
00543 
00544     // Generation of fluorescence
00545     // Data in EADL are available only for Z > 5
00546     // Protection to avoid generating photons in the unphysical case of
00547     // shell binding energy > photon energy
00548     if (localEnergyDeposit > cutg || localEnergyDeposit > cute)
00549       { 
00550         G4DynamicParticle* aPhoton;
00551         deexcitationManager.SetCutForSecondaryPhotons(cutg);
00552         deexcitationManager.SetCutForAugerElectrons(cute);
00553 
00554         photonVector = deexcitationManager.GenerateParticles(Z,shellId);
00555         if(photonVector) 
00556           {
00557             size_t nPhotons = photonVector->size();
00558             for (size_t k=0; k<nPhotons; k++)
00559               {
00560                 aPhoton = (*photonVector)[k];
00561                 if (aPhoton)
00562                   {
00563                     G4double itsEnergy = aPhoton->GetKineticEnergy();
00564                     G4bool keepIt = false;
00565                     if (itsEnergy <= localEnergyDeposit)
00566                       {
00567                         //check if good! 
00568                         if(aPhoton->GetDefinition() == G4Gamma::Gamma()
00569                            && itsEnergy >= cutg)
00570                           {
00571                             keepIt = true;
00572                             energyInFluorescence += itsEnergy;                    
00573                           }
00574                         if (aPhoton->GetDefinition() == G4Electron::Electron() && 
00575                             itsEnergy >= cute)
00576                           {
00577                             energyInAuger += itsEnergy;
00578                             keepIt = true;
00579                           }
00580                       }
00581                     //good secondary, register it
00582                     if (keepIt)
00583                       {
00584                         localEnergyDeposit -= itsEnergy;
00585                         fvect->push_back(aPhoton);
00586                       }             
00587                     else
00588                       {
00589                         delete aPhoton;
00590                         (*photonVector)[k] = 0;
00591                       }
00592                   }
00593               }
00594             delete photonVector;
00595           }
00596       }
00597   }
00598   */
00599 
00600 
00601   //Always produce explicitely the electron 
00602   G4DynamicParticle* electron = 0;
00603 
00604   G4double xEl = sinThetaE * std::cos(phi+pi); 
00605   G4double yEl = sinThetaE * std::sin(phi+pi);
00606   G4double zEl = cosThetaE;
00607   G4ThreeVector eDirection(xEl,yEl,zEl); //electron direction
00608   eDirection.rotateUz(photonDirection0);
00609   electron = new G4DynamicParticle (G4Electron::Electron(),
00610                                     eDirection,eKineticEnergy) ;
00611   fvect->push_back(electron);
00612     
00613 
00614   if (localEnergyDeposit < 0)
00615     {
00616       G4cout << "WARNING-" 
00617              << "G4PenelopeComptonModel::SampleSecondaries - Negative energy deposit"
00618              << G4endl;
00619       localEnergyDeposit=0.;
00620     }
00621   fParticleChange->ProposeLocalEnergyDeposit(localEnergyDeposit);
00622   
00623   G4double electronEnergy = 0.;
00624   if (electron)
00625     electronEnergy = eKineticEnergy;
00626   if (verboseLevel > 1)
00627     {
00628       G4cout << "-----------------------------------------------------------" << G4endl;
00629       G4cout << "Energy balance from G4PenelopeCompton" << G4endl;
00630       G4cout << "Incoming photon energy: " << photonEnergy0/keV << " keV" << G4endl;
00631       G4cout << "-----------------------------------------------------------" << G4endl;
00632       G4cout << "Scattered photon: " << photonEnergy1/keV << " keV" << G4endl;
00633       G4cout << "Scattered electron " << electronEnergy/keV << " keV" << G4endl;
00634       if (energyInFluorescence)
00635         G4cout << "Fluorescence x-rays: " << energyInFluorescence/keV << " keV" << G4endl;
00636       if (energyInAuger)
00637         G4cout << "Auger electrons: " << energyInAuger/keV << " keV" << G4endl;
00638       G4cout << "Local energy deposit " << localEnergyDeposit/keV << " keV" << G4endl;
00639       G4cout << "Total final state: " << (photonEnergy1+electronEnergy+energyInFluorescence+
00640                                           localEnergyDeposit+energyInAuger)/keV << 
00641         " keV" << G4endl;
00642       G4cout << "-----------------------------------------------------------" << G4endl;
00643     }
00644   if (verboseLevel > 0)
00645     {
00646       G4double energyDiff = std::fabs(photonEnergy1+
00647                                       electronEnergy+energyInFluorescence+
00648                                       localEnergyDeposit+energyInAuger-photonEnergy0);
00649       if (energyDiff > 0.05*keV)
00650         G4cout << "Warning from G4PenelopeCompton: problem with energy conservation: " << 
00651           (photonEnergy1+electronEnergy+energyInFluorescence+energyInAuger+localEnergyDeposit)/keV << 
00652           " keV (final) vs. " << 
00653           photonEnergy0/keV << " keV (initial)" << G4endl;
00654     }    
00655 }
00656 
00657 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
00658 
00659 G4double G4PenelopeComptonModel::DifferentialCrossSection(G4double cosTheta,G4double energy,
00660                                                             G4PenelopeOscillator* osc)
00661 {
00662   //
00663   // Penelope model v2008. Single differential cross section *per electron* 
00664   // for photon Compton scattering by 
00665   // electrons in the given atomic oscillator, differential in the direction of the 
00666   // scattering photon. This is in units of pi*classic_electr_radius**2 
00667   //
00668   // D. Brusa et al., Nucl. Instrum. Meth. A 379 (1996) 167
00669   // The parametrization includes the J(p) distribution profiles for the atomic shells, 
00670   // that are tabulated from Hartree-Fock calculations 
00671   // from F. Biggs et al., At. Data Nucl. Data Tables 16 (1975) 201
00672   //
00673   G4double ionEnergy = osc->GetIonisationEnergy();
00674   G4double harFunc = osc->GetHartreeFactor(); 
00675 
00676   const G4double k2 = std::sqrt(2.);
00677   const G4double k1 = 1./k2; 
00678 
00679   if (energy < ionEnergy)
00680     return 0;
00681 
00682   //energy of the Compton line
00683   G4double cdt1 = 1.0-cosTheta;
00684   G4double EOEC = 1.0+(energy/electron_mass_c2)*cdt1; 
00685   G4double ECOE = 1.0/EOEC;
00686 
00687   //Incoherent scattering function (analytical profile)
00688   G4double aux = energy*(energy-ionEnergy)*cdt1;
00689   G4double Pzimax = 
00690     (aux - electron_mass_c2*ionEnergy)/(electron_mass_c2*std::sqrt(2*aux+ionEnergy*ionEnergy));
00691   G4double sia = 0.0;
00692   G4double x = harFunc*Pzimax;
00693   if (x > 0) 
00694     sia = 1.0-0.5*std::exp(0.5-(k1+k2*x)*(k1+k2*x));    
00695   else    
00696     sia = 0.5*std::exp(0.5-(k1-k2*x)*(k1-k2*x));
00697    
00698   //1st order correction, integral of Pz times the Compton profile.
00699   //Calculated approximately using a free-electron gas profile
00700   G4double pf = 3.0/(4.0*harFunc);
00701   if (std::fabs(Pzimax) < pf)
00702     {
00703       G4double QCOE2 = 1.0+ECOE*ECOE-2.0*ECOE*cosTheta;
00704       G4double p2 = Pzimax*Pzimax;
00705       G4double dspz = std::sqrt(QCOE2)*
00706         (1.0+ECOE*(ECOE-cosTheta)/QCOE2)*harFunc
00707         *0.25*(2*p2-(p2*p2)/(pf*pf)-(pf*pf));
00708       sia += std::max(dspz,-1.0*sia);
00709     }
00710 
00711   G4double XKN = EOEC+ECOE-1.0+cosTheta*cosTheta;
00712 
00713   //Differential cross section (per electron, in units of pi*classic_electr_radius**2)
00714   G4double diffCS = ECOE*ECOE*XKN*sia;
00715 
00716   return diffCS;
00717 }
00718 
00719 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
00720 
00721 G4double G4PenelopeComptonModel::OscillatorTotalCrossSection(G4double energy,G4PenelopeOscillator* osc)
00722 {
00723   //Total cross section (integrated) for the given oscillator in units of 
00724   //pi*classic_electr_radius^2
00725 
00726   //Integrate differential cross section for each oscillator
00727   G4double stre = osc->GetOscillatorStrength();
00728   
00729   // here one uses the  using the 20-point
00730   // Gauss quadrature method with an adaptive bipartition scheme
00731   const G4int npoints=10;
00732   const G4int ncallsmax=20000;
00733   const G4int nst=256;
00734   static G4double Abscissas[10] = {7.652651133497334e-02,2.2778585114164508e-01,3.7370608871541956e-01,
00735                                    5.1086700195082710e-01,6.3605368072651503e-01,7.4633190646015079e-01,
00736                                    8.3911697182221882e-01,9.1223442825132591e-01,9.6397192727791379e-01,
00737                                    9.9312859918509492e-01};
00738   static G4double Weights[10] = {1.5275338713072585e-01,1.4917298647260375e-01,1.4209610931838205e-01,
00739                                  1.3168863844917663e-01,1.1819453196151842e-01,1.0193011981724044e-01,
00740                                  8.3276741576704749e-02,6.2672048334109064e-02,4.0601429800386941e-02,
00741                                  1.7614007139152118e-02};
00742 
00743   G4double MaxError = 1e-5;
00744   //Error control
00745   G4double Ctol = std::min(std::max(MaxError,1e-13),1e-02);
00746   G4double Ptol = 0.01*Ctol;
00747   G4double Err=1e35;
00748 
00749   //Gauss integration from -1 to 1
00750   G4double LowPoint = -1.0;
00751   G4double HighPoint = 1.0;
00752 
00753   G4double h=HighPoint-LowPoint;
00754   G4double sumga=0.0;
00755   G4double a=0.5*(HighPoint-LowPoint);
00756   G4double b=0.5*(HighPoint+LowPoint);
00757   G4double c=a*Abscissas[0];
00758   G4double d= Weights[0]*
00759     (DifferentialCrossSection(b+c,energy,osc)+DifferentialCrossSection(b-c,energy,osc));
00760   for (G4int i=2;i<=npoints;i++)
00761     {
00762       c=a*Abscissas[i-1];
00763       d += Weights[i-1]*
00764         (DifferentialCrossSection(b+c,energy,osc)+DifferentialCrossSection(b-c,energy,osc));
00765     }
00766   G4int icall = 2*npoints;
00767   G4int LH=1;
00768   G4double S[nst],x[nst],sn[nst],xrn[nst];
00769   S[0]=d*a;
00770   x[0]=LowPoint;
00771 
00772   G4bool loopAgain = true;
00773 
00774   //Adaptive bipartition scheme
00775   do{
00776     G4double h0=h;
00777     h=0.5*h; //bipartition
00778     G4double sumr=0;
00779     G4int LHN=0;
00780     G4double si,xa,xb,xc;
00781     for (G4int i=1;i<=LH;i++){
00782       si=S[i-1];
00783       xa=x[i-1];
00784       xb=xa+h;
00785       xc=xa+h0;
00786       a=0.5*(xb-xa);
00787       b=0.5*(xb+xa);
00788       c=a*Abscissas[0];
00789       G4double dLocal = Weights[0]*
00790         (DifferentialCrossSection(b+c,energy,osc)+DifferentialCrossSection(b-c,energy,osc));
00791       
00792       for (G4int j=1;j<npoints;j++)
00793         {
00794           c=a*Abscissas[j];
00795           dLocal += Weights[j]*
00796             (DifferentialCrossSection(b+c,energy,osc)+DifferentialCrossSection(b-c,energy,osc));
00797         }    
00798       G4double s1=dLocal*a;
00799       a=0.5*(xc-xb);
00800       b=0.5*(xc+xb);
00801       c=a*Abscissas[0];
00802       dLocal=Weights[0]*
00803         (DifferentialCrossSection(b+c,energy,osc)+DifferentialCrossSection(b-c,energy,osc));
00804       
00805       for (G4int j=1;j<npoints;j++)
00806         {
00807           c=a*Abscissas[j];
00808           dLocal += Weights[j]*
00809             (DifferentialCrossSection(b+c,energy,osc)+DifferentialCrossSection(b-c,energy,osc));
00810         }    
00811       G4double s2=dLocal*a;
00812       icall=icall+4*npoints;
00813       G4double s12=s1+s2;
00814       if (std::abs(s12-si)<std::max(Ptol*std::abs(s12),1e-35))
00815         sumga += s12;
00816       else
00817         {
00818           sumr += s12;
00819           LHN += 2;
00820           sn[LHN-1]=s2;
00821           xrn[LHN-1]=xb;
00822           sn[LHN-2]=s1;
00823           xrn[LHN-2]=xa;
00824         }
00825       
00826       if (icall>ncallsmax || LHN>nst)
00827         {
00828           G4cout << "G4PenelopeComptonModel: " << G4endl;
00829           G4cout << "LowPoint: " << LowPoint << ", High Point: " << HighPoint << G4endl;
00830           G4cout << "Tolerance: " << MaxError << G4endl;
00831           G4cout << "Calls: " << icall << ", Integral: " << sumga << ", Error: " << Err << G4endl;
00832           G4cout << "Number of open subintervals: " << LHN << G4endl;
00833           G4cout << "WARNING: the required accuracy has not been attained" << G4endl;
00834           loopAgain = false;
00835         }
00836     }
00837     Err=std::abs(sumr)/std::max(std::abs(sumr+sumga),1e-35);
00838     if (Err < Ctol || LHN == 0) 
00839       loopAgain = false; //end of cycle
00840     LH=LHN;
00841     for (G4int i=0;i<LH;i++)
00842       {
00843         S[i]=sn[i];
00844         x[i]=xrn[i];
00845       }
00846   }while(Ctol < 1.0 && loopAgain); 
00847 
00848 
00849   G4double xs = stre*sumga;
00850 
00851   return xs; 
00852 }
00853 
00854 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
00855 
00856 G4double G4PenelopeComptonModel::KleinNishinaCrossSection(G4double energy,
00857                                                    const G4Material* material)
00858 {
00859   // use Klein-Nishina formula
00860   // total cross section in units of pi*classic_electr_radius^2
00861 
00862   G4double cs = 0;
00863 
00864   G4double ek =energy/electron_mass_c2;
00865   G4double eks = ek*ek;
00866   G4double ek2 = 1.0+ek+ek;
00867   G4double ek1 = eks-ek2-1.0;
00868 
00869   G4double t0 = 1.0/ek2;
00870   G4double csl = 0.5*eks*t0*t0+ek2*t0+ek1*std::log(t0)-(1.0/t0);
00871 
00872   G4PenelopeOscillatorTable* theTable = oscManager->GetOscillatorTableCompton(material);
00873 
00874   for (size_t i=0;i<theTable->size();i++)
00875     {
00876       G4PenelopeOscillator* theOsc = (*theTable)[i];
00877       G4double ionEnergy = theOsc->GetIonisationEnergy();
00878       G4double tau=(energy-ionEnergy)/energy;
00879       if (tau > t0)
00880         {
00881           G4double csu = 0.5*eks*tau*tau+ek2*tau+ek1*std::log(tau)-(1.0/tau);
00882           G4double stre = theOsc->GetOscillatorStrength();
00883 
00884           cs += stre*(csu-csl);
00885         }
00886     }
00887 
00888   cs /= (ek*eks);
00889 
00890   return cs;
00891 
00892 }
00893 

Generated on Mon May 27 17:49:17 2013 for Geant4 by  doxygen 1.4.7