Geant4 Cross Reference

Cross-Referencing   Geant4
Geant4/processes/electromagnetic/lowenergy/src/G4PenelopeIonisationModel.cc

Version: [ ReleaseNotes ] [ 1.0 ] [ 1.1 ] [ 2.0 ] [ 3.0 ] [ 3.1 ] [ 3.2 ] [ 4.0 ] [ 4.0.p1 ] [ 4.0.p2 ] [ 4.1 ] [ 4.1.p1 ] [ 5.0 ] [ 5.0.p1 ] [ 5.1 ] [ 5.1.p1 ] [ 5.2 ] [ 5.2.p1 ] [ 5.2.p2 ] [ 6.0 ] [ 6.0.p1 ] [ 6.1 ] [ 6.2 ] [ 6.2.p1 ] [ 6.2.p2 ] [ 7.0 ] [ 7.0.p1 ] [ 7.1 ] [ 7.1.p1 ] [ 8.0 ] [ 8.0.p1 ] [ 8.1 ] [ 8.1.p1 ] [ 8.1.p2 ] [ 8.2 ] [ 8.2.p1 ] [ 8.3 ] [ 8.3.p1 ] [ 8.3.p2 ] [ 9.0 ] [ 9.0.p1 ] [ 9.0.p2 ] [ 9.1 ] [ 9.1.p1 ] [ 9.1.p2 ] [ 9.1.p3 ] [ 9.2 ] [ 9.2.p1 ] [ 9.2.p2 ] [ 9.2.p3 ] [ 9.2.p4 ] [ 9.3 ] [ 9.3.p1 ] [ 9.3.p2 ] [ 9.4 ] [ 9.4.p1 ] [ 9.4.p2 ] [ 9.4.p3 ] [ 9.4.p4 ] [ 9.5 ] [ 9.5.p1 ] [ 9.5.p2 ] [ 9.6 ] [ 9.6.p1 ] [ 9.6.p2 ] [ 9.6.p3 ] [ 9.6.p4 ] [ 10.0 ] [ 10.0.p1 ] [ 10.0.p2 ] [ 10.0.p3 ] [ 10.0.p4 ] [ 10.1 ] [ 10.1.p1 ] [ 10.1.p2 ] [ 10.1.p3 ] [ 10.2 ] [ 10.2.p1 ] [ 10.2.p2 ] [ 10.2.p3 ] [ 10.3 ] [ 10.3.p1 ] [ 10.3.p2 ] [ 10.3.p3 ] [ 10.4 ] [ 10.4.p1 ] [ 10.4.p2 ] [ 10.4.p3 ] [ 10.5 ] [ 10.5.p1 ] [ 10.6 ] [ 10.6.p1 ] [ 10.6.p2 ] [ 10.6.p3 ] [ 10.7 ] [ 10.7.p1 ] [ 10.7.p2 ] [ 10.7.p3 ] [ 10.7.p4 ] [ 11.0 ] [ 11.0.p1 ] [ 11.0.p2 ] [ 11.0.p3, ] [ 11.0.p4 ] [ 11.1 ] [ 11.1.1 ] [ 11.1.2 ] [ 11.1.3 ] [ 11.2 ] [ 11.2.1 ] [ 11.2.2 ] [ 11.3.0 ]

Diff markup

Differences between /processes/electromagnetic/lowenergy/src/G4PenelopeIonisationModel.cc (Version 11.3.0) and /processes/electromagnetic/lowenergy/src/G4PenelopeIonisationModel.cc (Version 3.2)


  1 //                                                  1 
  2 // *******************************************    
  3 // * License and Disclaimer                       
  4 // *                                              
  5 // * The  Geant4 software  is  copyright of th    
  6 // * the Geant4 Collaboration.  It is provided    
  7 // * conditions of the Geant4 Software License    
  8 // * LICENSE and available at  http://cern.ch/    
  9 // * include a list of copyright holders.         
 10 // *                                              
 11 // * Neither the authors of this software syst    
 12 // * institutes,nor the agencies providing fin    
 13 // * work  make  any representation or  warran    
 14 // * regarding  this  software system or assum    
 15 // * use.  Please see the license in the file     
 16 // * for the full disclaimer and the limitatio    
 17 // *                                              
 18 // * This  code  implementation is the result     
 19 // * technical work of the GEANT4 collaboratio    
 20 // * By using,  copying,  modifying or  distri    
 21 // * any work based  on the software)  you  ag    
 22 // * use  in  resulting  scientific  publicati    
 23 // * acceptance of all terms of the Geant4 Sof    
 24 // *******************************************    
 25 //                                                
 26 //                                                
 27 // Author: Luciano Pandola                        
 28 //                                                
 29 // History:                                       
 30 // --------                                       
 31 // 27 Jul 2010   L Pandola    First complete i    
 32 // 18 Jan 2011   L.Pandola    Stricter check o    
 33 //                            Should never hap    
 34 // 01 Feb 2011   L Pandola  Suppress fake ener    
 35 //                          Make sure that flu    
 36 //                          above threshold       
 37 // 25 May 2011   L Pandola  Renamed (make v200    
 38 // 26 Jan 2012   L Pandola  Migration of Atomi    
 39 // 09 Mar 2012   L Pandola  Moved the manageme    
 40 //                          cross sections to     
 41 //                          get normalized she    
 42 // 07 Oct 2013   L. Pandola Migration to MT       
 43 // 23 Jun 2015   L. Pandola Keep track of the     
 44 //                           atomic de-excitat    
 45 // 29 Aug 2018   L. Pandola Fix bug causing en    
 46 //                                                
 47                                                   
 48 #include "G4PenelopeIonisationModel.hh"           
 49 #include "G4PhysicalConstants.hh"                 
 50 #include "G4SystemOfUnits.hh"                     
 51 #include "G4ParticleDefinition.hh"                
 52 #include "G4MaterialCutsCouple.hh"                
 53 #include "G4ProductionCutsTable.hh"               
 54 #include "G4DynamicParticle.hh"                   
 55 #include "G4AtomicTransitionManager.hh"           
 56 #include "G4AtomicShell.hh"                       
 57 #include "G4Gamma.hh"                             
 58 #include "G4Electron.hh"                          
 59 #include "G4Positron.hh"                          
 60 #include "G4PenelopeOscillatorManager.hh"         
 61 #include "G4PenelopeOscillator.hh"                
 62 #include "G4PenelopeCrossSection.hh"              
 63 #include "G4PhysicsFreeVector.hh"                 
 64 #include "G4PhysicsLogVector.hh"                  
 65 #include "G4LossTableManager.hh"                  
 66 #include "G4PenelopeIonisationXSHandler.hh"       
 67 #include "G4EmParameters.hh"                      
 68 #include "G4AutoLock.hh"                          
 69                                                   
 70 //....oooOO0OOooo........oooOO0OOooo........oo    
 71 namespace { G4Mutex  PenelopeIonisationModelMu    
 72                                                   
 73 G4PenelopeIonisationModel::G4PenelopeIonisatio    
 74                  const G4String& nam)             
 75   :G4VEmModel(nam),fParticleChange(nullptr),fP    
 76    fCrossSectionHandler(nullptr),                 
 77    fAtomDeexcitation(nullptr), fKineticEnergy1    
 78    fCosThetaPrimary(1.0),fEnergySecondary(0.*e    
 79    fCosThetaSecondary(0.0),fTargetOscillator(-    
 80    fIsInitialised(false),fPIXEflag(false),fLoc    
 81 {                                                 
 82   fIntrinsicLowEnergyLimit = 100.0*eV;            
 83   fIntrinsicHighEnergyLimit = 100.0*GeV;          
 84   //  SetLowEnergyLimit(fIntrinsicLowEnergyLim    
 85   SetHighEnergyLimit(fIntrinsicHighEnergyLimit    
 86   fNBins = 200;                                   
 87                                                   
 88   if (part)                                       
 89     SetParticle(part);                            
 90                                                   
 91   //                                              
 92   fOscManager = G4PenelopeOscillatorManager::G    
 93   //                                              
 94   fVerboseLevel= 0;                               
 95   // Verbosity scale:                             
 96   // 0 = nothing                                  
 97   // 1 = warning for energy non-conservation      
 98   // 2 = details of energy budget                 
 99   // 3 = calculation of cross sections, file o    
100   // 4 = entering in methods                      
101                                                   
102   // Atomic deexcitation model activated by de    
103   SetDeexcitationFlag(true);                      
104 }                                                 
105                                                   
106 //....oooOO0OOooo........oooOO0OOooo........oo    
107                                                   
108 G4PenelopeIonisationModel::~G4PenelopeIonisati    
109 {                                                 
110   if (IsMaster() || fLocalTable)                  
111     {                                             
112       if (fCrossSectionHandler)                   
113   delete fCrossSectionHandler;                    
114     }                                             
115 }                                                 
116                                                   
117 //....oooOO0OOooo........oooOO0OOooo........oo    
118                                                   
119 void G4PenelopeIonisationModel::Initialise(con    
120              const G4DataVector& theCuts)         
121 {                                                 
122   if (fVerboseLevel > 3)                          
123     G4cout << "Calling G4PenelopeIonisationMod    
124                                                   
125   fAtomDeexcitation = G4LossTableManager::Inst    
126   //Issue warning if the AtomicDeexcitation ha    
127   if (!fAtomDeexcitation)                         
128     {                                             
129       G4cout << G4endl;                           
130       G4cout << "WARNING from G4PenelopeIonisa    
131       G4cout << "Atomic de-excitation module i    
132       G4cout << "any fluorescence/Auger emissi    
133       G4cout << "Please make sure this is inte    
134     }                                             
135                                                   
136   if (fAtomDeexcitation)                          
137     fPIXEflag = fAtomDeexcitation->IsPIXEActiv    
138                                                   
139   //If the PIXE flag is active, the PIXE inter    
140   //atomic de-excitation. The model does not n    
141   //Issue warnings here                           
142   if (fPIXEflag && IsMaster() && particle==G4E    
143     {                                             
144       G4String theModel = G4EmParameters::Inst    
145       G4cout << "=============================    
146       G4cout << "The G4PenelopeIonisationModel    
147       G4cout << "Atomic de-excitation will be     
148       G4cout << "interface by using the shell     
149       G4cout << "The built-in model procedure     
150       G4cout << "*Please be sure this is inten    
151       G4cout << "/process/em/pixe false" << G4    
152       G4cout << "=============================    
153     }                                             
154                                                   
155   SetParticle(particle);                          
156                                                   
157   //Only the master model creates/manages the     
158   //pointer to the table, and use it as readon    
159   if (IsMaster() && particle == fParticle)        
160     {                                             
161       //Set the number of bins for the tables.    
162       fNBins = (std::size_t) (20*std::log10(Hi    
163       fNBins = std::max(fNBins,(std::size_t)10    
164                                                   
165       //Clear and re-build the tables             
166       if (fCrossSectionHandler)                   
167   {                                               
168     delete fCrossSectionHandler;                  
169     fCrossSectionHandler = 0;                     
170   }                                               
171       fCrossSectionHandler = new G4PenelopeIon    
172       fCrossSectionHandler->SetVerboseLevel(fV    
173                                                   
174       //Build tables for all materials            
175       G4ProductionCutsTable* theCoupleTable =     
176   G4ProductionCutsTable::GetProductionCutsTabl    
177       for (G4int i=0;i<(G4int)theCoupleTable->    
178   {                                               
179     const G4Material* theMat =                    
180       theCoupleTable->GetMaterialCutsCouple(i)    
181     //Forces the building of the cross section    
182     fCrossSectionHandler->BuildXSTable(theMat,    
183                  IsMaster());                     
184   }                                               
185                                                   
186       if (fVerboseLevel > 2) {                    
187   G4cout << "Penelope Ionisation model v2008 i    
188          << "Energy range: "                      
189          << LowEnergyLimit() / keV << " keV -     
190          << HighEnergyLimit() / GeV << " GeV.     
191          << fNBins << " bins."                    
192          << G4endl;                               
193       }                                           
194     }                                             
195                                                   
196   if(fIsInitialised)                              
197     return;                                       
198   fParticleChange = GetParticleChangeForLoss()    
199   fIsInitialised = true;                          
200                                                   
201   return;                                         
202 }                                                 
203                                                   
204 //....oooOO0OOooo........oooOO0OOooo........oo    
205                                                   
206 void G4PenelopeIonisationModel::InitialiseLoca    
207              G4VEmModel *masterModel)             
208 {                                                 
209   if (fVerboseLevel > 3)                          
210     G4cout << "Calling  G4PenelopeIonisationMo    
211   //                                              
212   //Check that particle matches: one might hav    
213   //for e+ and e-).                               
214   //                                              
215   if (part == fParticle)                          
216     {                                             
217       //Get the const table pointers from the     
218       const G4PenelopeIonisationModel* theMode    
219   static_cast<G4PenelopeIonisationModel*> (mas    
220                                                   
221       //Copy pointers to the data tables          
222       fCrossSectionHandler = theModel->fCrossS    
223                                                   
224       //copy data                                 
225       fNBins = theModel->fNBins;                  
226                                                   
227       //Same verbosity for all workers, as the    
228       fVerboseLevel = theModel->fVerboseLevel;    
229     }                                             
230   return;                                         
231 }                                                 
232                                                   
233                                                   
234 //....oooOO0OOooo........oooOO0OOooo........oo    
235                                                   
236 G4double G4PenelopeIonisationModel::CrossSecti    
237                 const G4ParticleDefinition*       
238                 theParticle,                      
239                 G4double energy,                  
240                 G4double cutEnergy,               
241                 G4double)                         
242 {                                                 
243   // Penelope model v2008 to calculate the cro    
244   // threshold. It makes use of the Generalise    
245   //  D. Liljequist, J. Phys. D: Appl. Phys. 1    
246   //                                              
247   // The total cross section is calculated ana    
248   // into account the atomic oscillators comin    
249   //                                              
250   // For incident e- the maximum energy allowe    
251   // because particles are undistinghishable.     
252   //                                              
253   // The contribution is splitted in three par    
254   // distant transverse collisions and close c    
255   // its own analytical function.                 
256   // Fermi density correction is calculated an    
257   //  U. Fano, Ann. Rev. Nucl. Sci. 13 (1963),    
258   //                                              
259   if (fVerboseLevel > 3)                          
260     G4cout << "Calling CrossSectionPerVolume()    
261                                                   
262   SetupForMaterial(theParticle, material, ener    
263                                                   
264   G4double totalCross = 0.0;                      
265   G4double crossPerMolecule = 0.;                 
266                                                   
267   //Either Initialize() was not called, or we     
268   //not invoked                                   
269   if (!fCrossSectionHandler)                      
270     {                                             
271       //create a **thread-local** version of t    
272       //Unit Tests                                
273       fLocalTable = true;                         
274       fCrossSectionHandler = new G4PenelopeIon    
275     }                                             
276                                                   
277   const G4PenelopeCrossSection* theXS =           
278     fCrossSectionHandler->GetCrossSectionTable    
279                 material,                         
280                 cutEnergy);                       
281   if (!theXS)                                     
282     {                                             
283       //If we are here, it means that Initiali    
284       //not filled up. This can happen in a Un    
285       if (fVerboseLevel > 0)                      
286   {                                               
287     //Issue a G4Exception (warning) only in ve    
288     G4ExceptionDescription ed;                    
289     ed << "Unable to retrieve the cross sectio    
290       theParticle->GetParticleName() <<           
291       " in " << material->GetName() << ", cut     
292     ed << "This can happen only in Unit Tests     
293     G4Exception("G4PenelopeIonisationModel::Cr    
294           "em2038",JustWarning,ed);               
295   }                                               
296       //protect file reading via autolock         
297       G4AutoLock lock(&PenelopeIonisationModel    
298       fCrossSectionHandler->BuildXSTable(mater    
299       lock.unlock();                              
300       //now it should be ok                       
301       theXS =                                     
302   fCrossSectionHandler->GetCrossSectionTableFo    
303                 material,                         
304                 cutEnergy);                       
305     }                                             
306                                                   
307   if (theXS)                                      
308     crossPerMolecule = theXS->GetHardCrossSect    
309                                                   
310   G4double atomDensity = material->GetTotNbOfA    
311   G4double atPerMol =  fOscManager->GetAtomsPe    
312                                                   
313   if (fVerboseLevel > 3)                          
314     G4cout << "Material " << material->GetName    
315       "atoms per molecule" << G4endl;             
316                                                   
317   G4double moleculeDensity = 0.;                  
318   if (atPerMol)                                   
319     moleculeDensity = atomDensity/atPerMol;       
320   G4double crossPerVolume = crossPerMolecule*m    
321                                                   
322   if (fVerboseLevel > 2)                          
323   {                                               
324     G4cout << "G4PenelopeIonisationModel " <<     
325     G4cout << "Mean free path for delta emissi    
326       energy/keV << " keV = " << (1./crossPerV    
327     if (theXS)                                    
328       totalCross = (theXS->GetTotalCrossSectio    
329     G4cout << "Total free path for ionisation     
330       energy/keV << " keV = " << (1./totalCros    
331   }                                               
332   return crossPerVolume;                          
333 }                                                 
334                                                   
335 //....oooOO0OOooo........oooOO0OOooo........oo    
336                                                   
337 //This is a dummy method. Never inkoved by the    
338 //a warning if one tries to get Cross Sections    
339 //G4EmCalculator.                                 
340 G4double G4PenelopeIonisationModel::ComputeCro    
341                      G4double,                    
342                      G4double,                    
343                      G4double,                    
344                      G4double,                    
345                      G4double)                    
346 {                                                 
347   G4cout << "*** G4PenelopeIonisationModel --     
348   G4cout << "Penelope Ionisation model v2008 d    
349   G4cout << "so the result is always zero. For    
350   G4cout << "GetCrossSectionPerVolume() or Get    
351   return 0;                                       
352 }                                                 
353                                                   
354 //....oooOO0OOooo........oooOO0OOooo........oo    
355                                                   
356 G4double G4PenelopeIonisationModel::ComputeDED    
357                const G4ParticleDefinition* the    
358                G4double kineticEnergy,            
359                G4double cutEnergy)                
360 {                                                 
361   // Penelope model v2008 to calculate the sto    
362   // below the threshold. It makes use of the     
363   // model from                                   
364   //  D. Liljequist, J. Phys. D: Appl. Phys. 1    
365   //                                              
366   // The stopping power is calculated analytic    
367   // section from the GOS models, which includ    
368   // distant longitudinal collisions, distant     
369   // close collisions. Only the atomic oscilla    
370   // (according to the threshold) are consider    
371   // Differential cross sections have a differ    
372   //                                              
373   // Fermi density correction is calculated an    
374   //  U. Fano, Ann. Rev. Nucl. Sci. 13 (1963),    
375                                                   
376   if (fVerboseLevel > 3)                          
377     G4cout << "Calling ComputeDEDX() of G4Pene    
378                                                   
379   //Either Initialize() was not called, or we     
380   //not invoked                                   
381   if (!fCrossSectionHandler)                      
382     {                                             
383       //create a **thread-local** version of t    
384       //Unit Tests                                
385       fLocalTable = true;                         
386       fCrossSectionHandler = new G4PenelopeIon    
387     }                                             
388                                                   
389   const G4PenelopeCrossSection* theXS =           
390     fCrossSectionHandler->GetCrossSectionTable    
391                 cutEnergy);                       
392   if (!theXS)                                     
393     {                                             
394       //If we are here, it means that Initiali    
395       //not filled up. This can happen in a Un    
396       if (fVerboseLevel > 0)                      
397   {                                               
398     //Issue a G4Exception (warning) only in ve    
399     G4ExceptionDescription ed;                    
400     ed << "Unable to retrieve the cross sectio    
401       theParticle->GetParticleName() <<           
402       " in " << material->GetName() << ", cut     
403     ed << "This can happen only in Unit Tests     
404     G4Exception("G4PenelopeIonisationModel::Co    
405           "em2038",JustWarning,ed);               
406   }                                               
407       //protect file reading via autolock         
408       G4AutoLock lock(&PenelopeIonisationModel    
409       fCrossSectionHandler->BuildXSTable(mater    
410       lock.unlock();                              
411       //now it should be ok                       
412       theXS =                                     
413   fCrossSectionHandler->GetCrossSectionTableFo    
414                 material,                         
415                 cutEnergy);                       
416     }                                             
417                                                   
418   G4double sPowerPerMolecule = 0.0;               
419   if (theXS)                                      
420     sPowerPerMolecule = theXS->GetSoftStopping    
421                                                   
422   G4double atomDensity = material->GetTotNbOfA    
423   G4double atPerMol =  fOscManager->GetAtomsPe    
424                                                   
425   G4double moleculeDensity = 0.;                  
426   if (atPerMol)                                   
427     moleculeDensity = atomDensity/atPerMol;       
428   G4double sPowerPerVolume = sPowerPerMolecule    
429                                                   
430   if (fVerboseLevel > 2)                          
431     {                                             
432       G4cout << "G4PenelopeIonisationModel " <    
433       G4cout << "Stopping power < " << cutEner    
434         kineticEnergy/keV << " keV = " <<         
435   sPowerPerVolume/(keV/mm) << " keV/mm" << G4e    
436     }                                             
437   return sPowerPerVolume;                         
438 }                                                 
439                                                   
440 //....oooOO0OOooo........oooOO0OOooo........oo    
441                                                   
442 G4double G4PenelopeIonisationModel::MinEnergyC    
443              const G4MaterialCutsCouple*)         
444 {                                                 
445   return fIntrinsicLowEnergyLimit;                
446 }                                                 
447                                                   
448 //....oooOO0OOooo........oooOO0OOooo........oo    
449                                                   
450 void G4PenelopeIonisationModel::SampleSecondar    
451               const G4MaterialCutsCouple* coup    
452               const G4DynamicParticle* aDynami    
453               G4double cutE, G4double)            
454 {                                                 
455   // Penelope model v2008 to sample the final     
456   // It makes use of the Generalised Oscillato    
457   //  D. Liljequist, J. Phys. D: Appl. Phys. 1    
458   //                                              
459   // The GOS model is used to calculate the in    
460   // the atomic oscillators coming in the play    
461   // contributions (distant longitudinal colli    
462   // close collisions). Then the target shell     
463   // sampled. Final state of the delta-ray (en    
464   // to the analytical distributions (dSigma/d    
465   // channels.                                    
466   // For e-, the maximum energy for the delta-    
467   // particles are indistinghusbable), while i    
468   // e+.                                          
469   // The efficiency of the random sampling alg    
470   // decreases when initial and cutoff energy     
471   // and 1 keV threshold, 99% for 10-MeV prima    
472   // Differential cross sections have a differ    
473   //                                              
474   // WARNING: The model provides an _average_     
475   // Anyway, the energy spectrum associated to    
476   // atomic shell is approximated as a single     
477   // show _unphysical_ narrow peaks at energie    
478   // resonance energies. The spurious speaks a    
479   // multiple inelastic collisions.               
480   //                                              
481   // The model determines also the original sh    
482   // in order to produce fluorescence de-excit    
483   //                                              
484   // Fermi density correction is calculated an    
485   //  U. Fano, Ann. Rev. Nucl. Sci. 13 (1963),    
486                                                   
487   if (fVerboseLevel > 3)                          
488     G4cout << "Calling SamplingSecondaries() o    
489                                                   
490   G4double kineticEnergy0 = aDynamicParticle->    
491   const G4ParticleDefinition* theParticle = aD    
492                                                   
493   if (kineticEnergy0 <= fIntrinsicLowEnergyLim    
494   {                                               
495     fParticleChange->SetProposedKineticEnergy(    
496     fParticleChange->ProposeLocalEnergyDeposit    
497     return ;                                      
498   }                                               
499                                                   
500   const G4Material* material = couple->GetMate    
501   const G4PenelopeOscillatorTable* theTable =     
502                                                   
503   G4ParticleMomentum particleDirection0 = aDyn    
504                                                   
505   //Initialise final-state variables. The prop    
506   // SampleFinalStateElectron() and SampleFina    
507   fKineticEnergy1=kineticEnergy0;                 
508   fCosThetaPrimary=1.0;                           
509   fEnergySecondary=0.0;                           
510   fCosThetaSecondary=1.0;                         
511   fTargetOscillator = -1;                         
512                                                   
513   if (theParticle == G4Electron::Electron())      
514     SampleFinalStateElectron(material,cutE,kin    
515   else if (theParticle == G4Positron::Positron    
516     SampleFinalStatePositron(material,cutE,kin    
517   else                                            
518     {                                             
519       G4ExceptionDescription ed;                  
520       ed << "Invalid particle " << theParticle    
521       G4Exception("G4PenelopeIonisationModel::    
522       "em0001",FatalException,ed);                
523                                                   
524     }                                             
525   if (fEnergySecondary == 0) return;              
526                                                   
527   if (fVerboseLevel > 3)                          
528   {                                               
529      G4cout << "G4PenelopeIonisationModel::Sam    
530   theParticle->GetParticleName() << G4endl;       
531       G4cout << "Final eKin = " << fKineticEne    
532       G4cout << "Final cosTheta = " << fCosThe    
533       G4cout << "Delta-ray eKin = " << fEnergy    
534       G4cout << "Delta-ray cosTheta = " << fCo    
535       G4cout << "Oscillator: " << fTargetOscil    
536    }                                              
537                                                   
538   //Update the primary particle                   
539   G4double sint = std::sqrt(1. - fCosThetaPrim    
540   G4double phiPrimary  = twopi * G4UniformRand    
541   G4double dirx = sint * std::cos(phiPrimary);    
542   G4double diry = sint * std::sin(phiPrimary);    
543   G4double dirz = fCosThetaPrimary;               
544                                                   
545   G4ThreeVector electronDirection1(dirx,diry,d    
546   electronDirection1.rotateUz(particleDirectio    
547                                                   
548   if (fKineticEnergy1 > 0)                        
549     {                                             
550       fParticleChange->ProposeMomentumDirectio    
551       fParticleChange->SetProposedKineticEnerg    
552     }                                             
553   else                                            
554     fParticleChange->SetProposedKineticEnergy(    
555                                                   
556   //Generate the delta ray                        
557   G4double ionEnergyInPenelopeDatabase =          
558     (*theTable)[fTargetOscillator]->GetIonisat    
559                                                   
560   //Now, try to handle fluorescence               
561   //Notice: merged levels are indicated with Z    
562   G4int shFlag = (*theTable)[fTargetOscillator    
563   G4int Z = (G4int) (*theTable)[fTargetOscilla    
564                                                   
565   //initialize here, then check photons create    
566   const G4AtomicTransitionManager* transitionM    
567   G4double bindingEnergy = 0.*eV;                 
568                                                   
569   const G4AtomicShell* shell = nullptr;           
570   //Real level                                    
571   if (Z > 0 && shFlag<30)                         
572     {                                             
573       shell = transitionManager->Shell(Z,shFla    
574       bindingEnergy = shell->BindingEnergy();     
575       //shellId = shell->ShellId();               
576     }                                             
577                                                   
578   //correct the fEnergySecondary to account fo    
579   //database of ionisation energies is in gene    
580   //from the fluorescence database used in Gea    
581   fEnergySecondary += ionEnergyInPenelopeDatab    
582                                                   
583   G4double localEnergyDeposit = bindingEnergy;    
584   //testing purposes only                         
585   G4double energyInFluorescence = 0;              
586   G4double energyInAuger = 0;                     
587                                                   
588   if (fEnergySecondary < 0)                       
589     {                                             
590       //It means that there was some problem/m    
591       //In this case, the available energy is     
592       //to the Penelope database, but not acco    
593       //Full residual energy is deposited loca    
594       localEnergyDeposit += fEnergySecondary;     
595       fEnergySecondary = 0.0;                     
596     }                                             
597                                                   
598   //Notice: shell might be nullptr (invalid!)     
599   //Disable the built-in de-excitation of the     
600   //case, the PIXE interface takes care (stati    
601   //de-excitation.                                
602   //Now, take care of fluorescence, if require    
603   if (fAtomDeexcitation && !fPIXEflag && shell    
604     {                                             
605       G4int index = couple->GetIndex();           
606       if (fAtomDeexcitation->CheckDeexcitation    
607   {                                               
608     std::size_t nBefore = fvect->size();          
609     fAtomDeexcitation->GenerateParticles(fvect    
610     std::size_t nAfter = fvect->size();           
611                                                   
612     if (nAfter>nBefore) //actual production of    
613       {                                           
614         for (std::size_t j=nBefore;j<nAfter;++    
615     {                                             
616       G4double itsEnergy = ((*fvect)[j])->GetK    
617                   if (itsEnergy < localEnergyD    
618                     {                             
619           localEnergyDeposit -= itsEnergy;        
620           if (((*fvect)[j])->GetParticleDefini    
621             energyInFluorescence += itsEnergy;    
622           else if (((*fvect)[j])->GetParticleD    
623             energyInAuger += itsEnergy;           
624                     }                             
625                   else //invalid secondary: ta    
626         {                                         
627           delete (*fvect)[j];                     
628           (*fvect)[j] = nullptr;                  
629         }                                         
630     }                                             
631       }                                           
632   }                                               
633     }                                             
634                                                   
635   // Generate the delta ray --> to be done onl    
636   if (fEnergySecondary > cutE)                    
637     {                                             
638       G4DynamicParticle* electron = nullptr;      
639       G4double sinThetaE = std::sqrt(1.-fCosTh    
640       G4double phiEl = phiPrimary+pi; //pi wit    
641       G4double xEl = sinThetaE * std::cos(phiE    
642       G4double yEl = sinThetaE * std::sin(phiE    
643       G4double zEl = fCosThetaSecondary;          
644       G4ThreeVector eDirection(xEl,yEl,zEl); /    
645       eDirection.rotateUz(particleDirection0);    
646       electron = new G4DynamicParticle (G4Elec    
647           eDirection,fEnergySecondary) ;          
648       fvect->push_back(electron);                 
649     }                                             
650   else                                            
651     {                                             
652       localEnergyDeposit += fEnergySecondary;     
653       fEnergySecondary = 0;                       
654     }                                             
655                                                   
656   if (localEnergyDeposit < 0) //Should not be:    
657     {                                             
658       G4Exception("G4PenelopeIonisationModel::    
659       "em2099",JustWarning,"WARNING: Negative     
660       localEnergyDeposit=0.;                      
661     }                                             
662   fParticleChange->ProposeLocalEnergyDeposit(l    
663                                                   
664   if (fVerboseLevel > 1)                          
665     {                                             
666       G4cout << "-----------------------------    
667       G4cout << "Energy balance from G4Penelop    
668       G4cout << "Incoming primary energy: " <<    
669       G4cout << "-----------------------------    
670       G4cout << "Outgoing primary energy: " <<    
671       G4cout << "Delta ray " << fEnergySeconda    
672       if (energyInFluorescence)                   
673   G4cout << "Fluorescence x-rays: " << energyI    
674       if (energyInAuger)                          
675   G4cout << "Auger electrons: " << energyInAug    
676       G4cout << "Local energy deposit " << loc    
677       G4cout << "Total final state: " << (fEne    
678             localEnergyDeposit+energyInAuger)/    
679   " keV" << G4endl;                               
680       G4cout << "-----------------------------    
681     }                                             
682                                                   
683   if (fVerboseLevel > 0)                          
684     {                                             
685       G4double energyDiff = std::fabs(fEnergyS    
686               localEnergyDeposit+energyInAuger    
687       if (energyDiff > 0.05*keV)                  
688   G4cout << "Warning from G4PenelopeIonisation    
689     (fEnergySecondary+energyInFluorescence+fKi    
690     " keV (final) vs. " <<                        
691     kineticEnergy0/keV << " keV (initial)" <<     
692     }                                             
693                                                   
694 }                                                 
695                                                   
696 //....oooOO0OOooo........oooOO0OOooo........oo    
697 void G4PenelopeIonisationModel::SampleFinalSta    
698                G4double cutEnergy,                
699                G4double kineticEnergy)            
700 {                                                 
701   // This method sets the final ionisation par    
702   // fKineticEnergy1, fCosThetaPrimary (= upda    
703   // fEnergySecondary, fCosThetaSecondary (= i    
704   // fTargetOscillator (= ionised oscillator)     
705   //                                              
706   // The method implements SUBROUTINE EINa of     
707   //                                              
708                                                   
709   G4PenelopeOscillatorTable* theTable = fOscMa    
710   std::size_t numberOfOscillators = theTable->    
711   const G4PenelopeCrossSection* theXS =           
712     fCrossSectionHandler->GetCrossSectionTable    
713                 cutEnergy);                       
714   G4double delta = fCrossSectionHandler->GetDe    
715                                                   
716   // Selection of the active oscillator           
717   G4double TST = G4UniformRand();                 
718   fTargetOscillator = G4int(numberOfOscillator    
719   G4double XSsum = 0.;                            
720                                                   
721   for (std::size_t i=0;i<numberOfOscillators-1    
722     {                                             
723       XSsum += theXS->GetNormalizedShellCrossS    
724                                                   
725       if (XSsum > TST)                            
726   {                                               
727     fTargetOscillator = (G4int) i;                
728     break;                                        
729   }                                               
730     }                                             
731                                                   
732   if (fVerboseLevel > 3)                          
733     {                                             
734       G4cout << "SampleFinalStateElectron: sam    
735   fTargetOscillator << "." << G4endl;             
736       G4cout << "Ionisation energy: " <<          
737   (*theTable)[fTargetOscillator]->GetIonisatio    
738   " eV " << G4endl;                               
739       G4cout << "Resonance energy: : " <<         
740   (*theTable)[fTargetOscillator]->GetResonance    
741        << G4endl;                                 
742     }                                             
743   //Constants                                     
744   G4double rb = kineticEnergy + 2.0*electron_m    
745   G4double gam = 1.0+kineticEnergy/electron_ma    
746   G4double gam2 = gam*gam;                        
747   G4double beta2 = (gam2-1.0)/gam2;               
748   G4double amol = ((gam-1.0)/gam)*((gam-1.0)/g    
749                                                   
750   //Partial cross section of the active oscill    
751   G4double resEne = (*theTable)[fTargetOscilla    
752   G4double invResEne = 1.0/resEne;                
753   G4double ionEne = (*theTable)[fTargetOscilla    
754   G4double cutoffEne = (*theTable)[fTargetOsci    
755   G4double XHDL = 0.;                             
756   G4double XHDT = 0.;                             
757   G4double QM = 0.;                               
758   G4double cps = 0.;                              
759   G4double cp = 0.;                               
760                                                   
761   //Distant excitations                           
762   if (resEne > cutEnergy && resEne < kineticEn    
763     {                                             
764       cps = kineticEnergy*rb;                     
765       cp = std::sqrt(cps);                        
766       G4double XHDT0 = std::max(G4Log(gam2)-be    
767       if (resEne > 1.0e-6*kineticEnergy)          
768   {                                               
769     G4double cpp = std::sqrt((kineticEnergy-re    
770     QM = std::sqrt((cp-cpp)*(cp-cpp)+electron_    
771   }                                               
772       else                                        
773   {                                               
774     QM = resEne*resEne/(beta2*2.0*electron_mas    
775     QM *= (1.0-QM*0.5/electron_mass_c2);          
776   }                                               
777       if (QM < cutoffEne)                         
778   {                                               
779     XHDL = G4Log(cutoffEne*(QM+2.0*electron_ma    
780       *invResEne;                                 
781     XHDT = XHDT0*invResEne;                       
782   }                                               
783       else                                        
784   {                                               
785     QM = cutoffEne;                               
786     XHDL = 0.;                                    
787     XHDT = 0.;                                    
788   }                                               
789     }                                             
790   else                                            
791     {                                             
792       QM = cutoffEne;                             
793       cps = 0.;                                   
794       cp = 0.;                                    
795       XHDL = 0.;                                  
796       XHDT = 0.;                                  
797     }                                             
798                                                   
799   //Close collisions                              
800   G4double EE = kineticEnergy + ionEne;           
801   G4double wmaxc = 0.5*EE;                        
802   G4double wcl = std::max(cutEnergy,cutoffEne)    
803   G4double rcl = wcl/EE;                          
804   G4double XHC = 0.;                              
805   if (wcl < wmaxc)                                
806     {                                             
807       G4double rl1 = 1.0-rcl;                     
808       G4double rrl1 = 1.0/rl1;                    
809       XHC = (amol*(0.5-rcl)+1.0/rcl-rrl1+         
810        (1.0-amol)*G4Log(rcl*rrl1))/EE;            
811     }                                             
812                                                   
813   //Total cross section per molecule for the a    
814   G4double XHTOT = XHC + XHDL + XHDT;             
815                                                   
816   //very small cross section, do nothing          
817   if (XHTOT < 1.e-14*barn)                        
818     {                                             
819       fKineticEnergy1=kineticEnergy;              
820       fCosThetaPrimary=1.0;                       
821       fEnergySecondary=0.0;                       
822       fCosThetaSecondary=1.0;                     
823       fTargetOscillator = G4int(numberOfOscill    
824       return;                                     
825     }                                             
826                                                   
827   //decide which kind of interaction we'll hav    
828   TST = XHTOT*G4UniformRand();                    
829                                                   
830   // Hard close collision                         
831   G4double TS1 = XHC;                             
832                                                   
833   if (TST < TS1)                                  
834     {                                             
835       G4double A = 5.0*amol;                      
836       G4double ARCL = A*0.5*rcl;                  
837       G4double rk=0.;                             
838       G4bool loopAgain = false;                   
839       do                                          
840   {                                               
841     loopAgain = false;                            
842     G4double fb = (1.0+ARCL)*G4UniformRand();     
843     if (fb < 1)                                   
844       rk = rcl/(1.0-fb*(1.0-(rcl+rcl)));          
845     else                                          
846       rk = rcl + (fb-1.0)*(0.5-rcl)/ARCL;         
847     G4double rk2 = rk*rk;                         
848     G4double rkf = rk/(1.0-rk);                   
849     G4double phi = 1.0+rkf*rkf-rkf+amol*(rk2+r    
850     if (G4UniformRand()*(1.0+A*rk2) > phi)        
851       loopAgain = true;                           
852   }while(loopAgain);                              
853       //energy and scattering angle (primary e    
854       G4double deltaE = rk*EE;                    
855                                                   
856       fKineticEnergy1 = kineticEnergy - deltaE    
857       fCosThetaPrimary = std::sqrt(fKineticEne    
858       //energy and scattering angle of the del    
859       fEnergySecondary = deltaE - ionEne; //su    
860       fCosThetaSecondary= std::sqrt(deltaE*rb/    
861       if (fVerboseLevel > 3)                      
862   G4cout << "SampleFinalStateElectron: sampled    
863       return;                                     
864     }                                             
865                                                   
866   //Hard distant longitudinal collisions          
867   TS1 += XHDL;                                    
868   G4double deltaE = resEne;                       
869   fKineticEnergy1 = kineticEnergy - deltaE;       
870                                                   
871   if (TST < TS1)                                  
872     {                                             
873       G4double QS = QM/(1.0+QM*0.5/electron_ma    
874       G4double Q = QS/(std::pow((QS/cutoffEne)    
875            - (QS*0.5/electron_mass_c2));          
876       G4double QTREV = Q*(Q+2.0*electron_mass_    
877       G4double cpps = fKineticEnergy1*(fKineti    
878       fCosThetaPrimary = (cpps+cps-QTREV)/(2.0    
879       if (fCosThetaPrimary > 1.)                  
880   fCosThetaPrimary = 1.0;                         
881       //energy and emission angle of the delta    
882       fEnergySecondary = deltaE - ionEne;         
883       fCosThetaSecondary = 0.5*(deltaE*(kineti    
884       if (fCosThetaSecondary > 1.0)               
885   fCosThetaSecondary = 1.0;                       
886       if (fVerboseLevel > 3)                      
887   G4cout << "SampleFinalStateElectron: sampled    
888       return;                                     
889     }                                             
890                                                   
891   //Hard distant transverse collisions            
892   fCosThetaPrimary = 1.0;                         
893   //energy and emission angle of the delta ray    
894   fEnergySecondary = deltaE - ionEne;             
895   fCosThetaSecondary = 0.5;                       
896   if (fVerboseLevel > 3)                          
897     G4cout << "SampleFinalStateElectron: sampl    
898                                                   
899   return;                                         
900 }                                                 
901                                                   
902 //....oooOO0OOooo........oooOO0OOooo........oo    
903                                                   
904 void G4PenelopeIonisationModel::SampleFinalSta    
905                G4double cutEnergy,                
906                G4double kineticEnergy)            
907 {                                                 
908   // This method sets the final ionisation par    
909   // fKineticEnergy1, fCosThetaPrimary (= upda    
910   // fEnergySecondary, fCosThetaSecondary (= i    
911   // fTargetOscillator (= ionised oscillator)     
912   //                                              
913   // The method implements SUBROUTINE PINa of     
914   //                                              
915                                                   
916   G4PenelopeOscillatorTable* theTable = fOscMa    
917   std::size_t numberOfOscillators = theTable->    
918   const G4PenelopeCrossSection* theXS =           
919     fCrossSectionHandler->GetCrossSectionTable    
920               cutEnergy);                         
921   G4double delta = fCrossSectionHandler->GetDe    
922                                                   
923   // Selection of the active oscillator           
924   G4double TST = G4UniformRand();                 
925   fTargetOscillator = G4int(numberOfOscillator    
926   G4double XSsum = 0.;                            
927   for (std::size_t i=0;i<numberOfOscillators-1    
928     {                                             
929       XSsum += theXS->GetNormalizedShellCrossS    
930       if (XSsum > TST)                            
931   {                                               
932     fTargetOscillator = (G4int) i;                
933     break;                                        
934   }                                               
935     }                                             
936                                                   
937   if (fVerboseLevel > 3)                          
938     {                                             
939       G4cout << "SampleFinalStatePositron: sam    
940   fTargetOscillator << "." << G4endl;             
941       G4cout << "Ionisation energy: " << (*the    
942        << " eV " << G4endl;                       
943       G4cout << "Resonance energy: : " << (*th    
944        << " eV " << G4endl;                       
945     }                                             
946                                                   
947   //Constants                                     
948   G4double rb = kineticEnergy + 2.0*electron_m    
949   G4double gam = 1.0+kineticEnergy/electron_ma    
950   G4double gam2 = gam*gam;                        
951   G4double beta2 = (gam2-1.0)/gam2;               
952   G4double g12 = (gam+1.0)*(gam+1.0);             
953   G4double amol = ((gam-1.0)/gam)*((gam-1.0)/g    
954   //Bhabha coefficients                           
955   G4double bha1 = amol*(2.0*g12-1.0)/(gam2-1.0    
956   G4double bha2 = amol*(3.0+1.0/g12);             
957   G4double bha3 = amol*2.0*gam*(gam-1.0)/g12;     
958   G4double bha4 = amol*(gam-1.0)*(gam-1.0)/g12    
959                                                   
960   //                                              
961   //Partial cross section of the active oscill    
962   //                                              
963   G4double resEne = (*theTable)[fTargetOscilla    
964   G4double invResEne = 1.0/resEne;                
965   G4double ionEne = (*theTable)[fTargetOscilla    
966   G4double cutoffEne = (*theTable)[fTargetOsci    
967                                                   
968   G4double XHDL = 0.;                             
969   G4double XHDT = 0.;                             
970   G4double QM = 0.;                               
971   G4double cps = 0.;                              
972   G4double cp = 0.;                               
973                                                   
974   //Distant excitations XS (same as for electr    
975   if (resEne > cutEnergy && resEne < kineticEn    
976     {                                             
977       cps = kineticEnergy*rb;                     
978       cp = std::sqrt(cps);                        
979       G4double XHDT0 = std::max(G4Log(gam2)-be    
980       if (resEne > 1.0e-6*kineticEnergy)          
981   {                                               
982     G4double cpp = std::sqrt((kineticEnergy-re    
983     QM = std::sqrt((cp-cpp)*(cp-cpp)+electron_    
984   }                                               
985       else                                        
986   {                                               
987     QM = resEne*resEne/(beta2*2.0*electron_mas    
988     QM *= (1.0-QM*0.5/electron_mass_c2);          
989   }                                               
990       if (QM < cutoffEne)                         
991   {                                               
992     XHDL = G4Log(cutoffEne*(QM+2.0*electron_ma    
993       *invResEne;                                 
994     XHDT = XHDT0*invResEne;                       
995   }                                               
996       else                                        
997   {                                               
998     QM = cutoffEne;                               
999     XHDL = 0.;                                    
1000     XHDT = 0.;                                   
1001   }                                              
1002     }                                            
1003   else                                           
1004     {                                            
1005       QM = cutoffEne;                            
1006       cps = 0.;                                  
1007       cp = 0.;                                   
1008       XHDL = 0.;                                 
1009       XHDT = 0.;                                 
1010     }                                            
1011   //Close collisions (Bhabha)                    
1012   G4double wmaxc = kineticEnergy;                
1013   G4double wcl = std::max(cutEnergy,cutoffEne    
1014   G4double rcl = wcl/kineticEnergy;              
1015   G4double XHC = 0.;                             
1016   if (wcl < wmaxc)                               
1017     {                                            
1018       G4double rl1 = 1.0-rcl;                    
1019       XHC = ((1.0/rcl-1.0)+bha1*G4Log(rcl)+bh    
1020        + (bha3/2.0)*(rcl*rcl-1.0)                
1021        + (bha4/3.0)*(1.0-rcl*rcl*rcl))/kineti    
1022     }                                            
1023                                                  
1024   //Total cross section per molecule for the     
1025   G4double XHTOT = XHC + XHDL + XHDT;            
1026                                                  
1027   //very small cross section, do nothing         
1028   if (XHTOT < 1.e-14*barn)                       
1029     {                                            
1030       fKineticEnergy1=kineticEnergy;             
1031       fCosThetaPrimary=1.0;                      
1032       fEnergySecondary=0.0;                      
1033       fCosThetaSecondary=1.0;                    
1034       fTargetOscillator = G4int(numberOfOscil    
1035       return;                                    
1036     }                                            
1037                                                  
1038   //decide which kind of interaction we'll ha    
1039   TST = XHTOT*G4UniformRand();                   
1040                                                  
1041   // Hard close collision                        
1042   G4double TS1 = XHC;                            
1043   if (TST < TS1)                                 
1044     {                                            
1045       G4double rl1 = 1.0-rcl;                    
1046       G4double rk=0.;                            
1047       G4bool loopAgain = false;                  
1048       do                                         
1049   {                                              
1050     loopAgain = false;                           
1051     rk = rcl/(1.0-G4UniformRand()*rl1);          
1052     G4double phi = 1.0-rk*(bha1-rk*(bha2-rk*(    
1053     if (G4UniformRand() > phi)                   
1054       loopAgain = true;                          
1055   }while(loopAgain);                             
1056       //energy and scattering angle (primary     
1057       G4double deltaE = rk*kineticEnergy;        
1058       fKineticEnergy1 = kineticEnergy - delta    
1059       fCosThetaPrimary = std::sqrt(fKineticEn    
1060       //energy and scattering angle of the de    
1061       fEnergySecondary = deltaE - ionEne; //s    
1062       fCosThetaSecondary= std::sqrt(deltaE*rb    
1063       if (fVerboseLevel > 3)                     
1064   G4cout << "SampleFinalStatePositron: sample    
1065       return;                                    
1066     }                                            
1067                                                  
1068   //Hard distant longitudinal collisions         
1069   TS1 += XHDL;                                   
1070   G4double deltaE = resEne;                      
1071   fKineticEnergy1 = kineticEnergy - deltaE;      
1072   if (TST < TS1)                                 
1073     {                                            
1074       G4double QS = QM/(1.0+QM*0.5/electron_m    
1075       G4double Q = QS/(std::pow((QS/cutoffEne    
1076            - (QS*0.5/electron_mass_c2));         
1077       G4double QTREV = Q*(Q+2.0*electron_mass    
1078       G4double cpps = fKineticEnergy1*(fKinet    
1079       fCosThetaPrimary = (cpps+cps-QTREV)/(2.    
1080       if (fCosThetaPrimary > 1.)                 
1081   fCosThetaPrimary = 1.0;                        
1082       //energy and emission angle of the delt    
1083       fEnergySecondary = deltaE - ionEne;        
1084       fCosThetaSecondary = 0.5*(deltaE*(kinet    
1085       if (fCosThetaSecondary > 1.0)              
1086   fCosThetaSecondary = 1.0;                      
1087       if (fVerboseLevel > 3)                     
1088   G4cout << "SampleFinalStatePositron: sample    
1089       return;                                    
1090     }                                            
1091                                                  
1092   //Hard distant transverse collisions           
1093   fCosThetaPrimary = 1.0;                        
1094   //energy and emission angle of the delta ra    
1095   fEnergySecondary = deltaE - ionEne;            
1096   fCosThetaSecondary = 0.5;                      
1097                                                  
1098   if (fVerboseLevel > 3)                         
1099     G4cout << "SampleFinalStatePositron: samp    
1100                                                  
1101   return;                                        
1102 }                                                
1103                                                  
1104 //....oooOO0OOooo........oooOO0OOooo........o    
1105                                                  
1106 void G4PenelopeIonisationModel::SetParticle(c    
1107 {                                                
1108   if(!fParticle) {                               
1109     fParticle = p;                               
1110   }                                              
1111 }                                                
1112