source: trunk/source/processes/electromagnetic/lowenergy/src/G4PenelopeIonisationModel.cc @ 1315

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

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

File size: 61.7 KB
Line 
1//
2// ********************************************************************
3// * License and Disclaimer                                           *
4// *                                                                  *
5// * The  Geant4 software  is  copyright of the Copyright Holders  of *
6// * the Geant4 Collaboration.  It is provided  under  the terms  and *
7// * conditions of the Geant4 Software License,  included in the file *
8// * LICENSE and available at  http://cern.ch/geant4/license .  These *
9// * include a list of copyright holders.                             *
10// *                                                                  *
11// * Neither the authors of this software system, nor their employing *
12// * institutes,nor the agencies providing financial support for this *
13// * work  make  any representation or  warranty, express or implied, *
14// * regarding  this  software system or assume any liability for its *
15// * use.  Please see the license in the file  LICENSE  and URL above *
16// * for the full disclaimer and the limitation of liability.         *
17// *                                                                  *
18// * This  code  implementation is the result of  the  scientific and *
19// * technical work of the GEANT4 collaboration.                      *
20// * By using,  copying,  modifying or  distributing the software (or *
21// * any work based  on the software)  you  agree  to acknowledge its *
22// * use  in  resulting  scientific  publications,  and indicate your *
23// * acceptance of all terms of the Geant4 Software license.          *
24// ********************************************************************
25//
26// $Id: G4PenelopeIonisationModel.cc,v 1.16 2010/04/29 07:28:50 pandola Exp $
27// GEANT4 tag $Name: geant4-09-04-beta-cand-01 $
28//
29// Author: Luciano Pandola
30//
31// History:
32// --------
33// 26 Nov 2008   L Pandola    Migration from process to model
34// 17 Apr 2009   V Ivanchenko Cleanup initialisation and generation of secondaries:
35//                  - apply internal high-energy limit only in constructor
36//                  - do not apply low-energy limit (default is 0)
37//                  - added MinEnergyCut method
38//                  - do not change track status
39// 19 May 2009   L Pandola    Explicitely set to zero pointers deleted in
40//                            Initialise(), since they might be checked later on
41// 21 Oct 2009   L Pandola    Remove un-necessary fUseAtomicDeexcitation flag - now managed by
42//                            G4VEmModel::DeexcitationFlag()
43//                            Add ActivateAuger() method
44// 15 Mar 2010   L Pandola    Explicitely initialize Auger to false
45// 29 Mar 2010   L Pandola    Added a dummy ComputeCrossSectionPerAtom() method issueing a
46//                            warning if users try to access atomic cross sections via
47//                            G4EmCalculator
48// 15 Apr 2010   L. Pandola   Implemented model's own version of MinEnergyCut()
49// 23 Apr 2010   L. Pandola   Removed InitialiseElementSelectors() call. Useless here and
50//                            triggers fake warning messages
51//
52
53#include "G4PenelopeIonisationModel.hh"
54#include "G4ParticleDefinition.hh"
55#include "G4MaterialCutsCouple.hh"
56#include "G4ProductionCutsTable.hh"
57#include "G4DynamicParticle.hh"
58#include "G4Element.hh"
59#include "G4AtomicTransitionManager.hh"
60#include "G4AtomicDeexcitation.hh"
61#include "G4AtomicShell.hh"
62#include "G4Gamma.hh"
63#include "G4Electron.hh"
64#include "G4Positron.hh"
65#include "G4CrossSectionHandler.hh"
66#include "G4AtomicDeexcitation.hh"
67#include "G4VEMDataSet.hh"
68
69//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
70
71
72G4PenelopeIonisationModel::G4PenelopeIonisationModel(const G4ParticleDefinition*,
73                                             const G4String& nam)
74  :G4VEmModel(nam),isInitialised(false),
75   kineticEnergy1(0.*eV),
76   cosThetaPrimary(1.0),
77   energySecondary(0.*eV),
78   cosThetaSecondary(0.0),
79   iOsc(-1),
80   crossSectionHandler(0),ionizationEnergy(0),
81   resonanceEnergy(0),occupationNumber(0),shellFlag(0),
82   theXSTable(0)
83{
84  fIntrinsicLowEnergyLimit = 100.0*eV;
85  fIntrinsicHighEnergyLimit = 100.0*GeV;
86  //  SetLowEnergyLimit(fIntrinsicLowEnergyLimit);
87  SetHighEnergyLimit(fIntrinsicHighEnergyLimit);
88  //
89  //
90  verboseLevel= 0;
91 
92  // Verbosity scale:
93  // 0 = nothing
94  // 1 = warning for energy non-conservation
95  // 2 = details of energy budget
96  // 3 = calculation of cross sections, file openings, sampling of atoms
97  // 4 = entering in methods
98
99  // Atomic deexcitation model activated by default
100  SetDeexcitationFlag(true);
101  ActivateAuger(false);
102 
103  //These vectors do not change when materials or cut change.
104  //Therefore I can read it at the constructor
105  ionizationEnergy = new std::map<G4int,G4DataVector*>;
106  resonanceEnergy  = new std::map<G4int,G4DataVector*>;
107  occupationNumber = new std::map<G4int,G4DataVector*>;
108  shellFlag = new std::map<G4int,G4DataVector*>;
109
110  ReadData(); //Read data from file
111
112}
113
114//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
115
116G4PenelopeIonisationModel::~G4PenelopeIonisationModel()
117{
118 
119  if (crossSectionHandler) delete crossSectionHandler;
120
121  if (theXSTable)
122    {
123      for (size_t i=0; i<theXSTable->size(); i++)
124        delete (*theXSTable)[i];
125      delete theXSTable;
126     }
127
128 
129  std::map <G4int,G4DataVector*>::iterator i;
130  for (i=ionizationEnergy->begin();i != ionizationEnergy->end();i++)
131    if (i->second) delete i->second;
132  for (i=resonanceEnergy->begin();i != resonanceEnergy->end();i++)
133    if (i->second) delete i->second;
134  for (i=occupationNumber->begin();i != occupationNumber->end();i++)
135    if (i->second) delete i->second;
136  for (i=shellFlag->begin();i != shellFlag->end();i++)
137    if (i->second) delete i->second;
138
139  if (ionizationEnergy)
140    delete ionizationEnergy;
141  if (resonanceEnergy)
142    delete resonanceEnergy;
143  if (occupationNumber)
144    delete occupationNumber;
145  if (shellFlag)
146    delete shellFlag;
147}
148
149//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
150
151void G4PenelopeIonisationModel::Initialise(const G4ParticleDefinition* particle,
152                                       const G4DataVector& )
153{
154  if (verboseLevel > 3)
155    G4cout << "Calling G4PenelopeIonisationModel::Initialise()" << G4endl;
156
157  //Delete and re-initialize the cross section handler
158  if (crossSectionHandler)
159    {
160      crossSectionHandler->Clear();
161      delete crossSectionHandler;
162      crossSectionHandler = 0;
163    }
164
165   if (theXSTable)
166    {
167      for (size_t i=0; i<theXSTable->size(); i++)
168        {
169          delete (*theXSTable)[i];
170          (*theXSTable)[i] = 0;
171        }
172      delete theXSTable;
173      theXSTable = 0;
174     }
175
176  crossSectionHandler = new G4CrossSectionHandler();
177  crossSectionHandler->Clear();
178  G4String crossSectionFile = "NULL";
179 
180  if (particle == G4Electron::Electron())
181     crossSectionFile = "penelope/ion-cs-el-";
182  else if (particle == G4Positron::Positron())
183     crossSectionFile = "penelope/ion-cs-po-"; 
184  crossSectionHandler->LoadData(crossSectionFile);
185  //This is used to retrieve cross section values later on
186  crossSectionHandler->BuildMeanFreePathForMaterials();
187 
188  if (verboseLevel > 2) 
189    G4cout << "Loaded cross section files for PenelopeIonisationModel" << G4endl;
190
191  if (verboseLevel > 2) {
192    G4cout << "Penelope Ionisation model is initialized " << G4endl
193           << "Energy range: "
194           << LowEnergyLimit() / keV << " keV - "
195           << HighEnergyLimit() / GeV << " GeV"
196           << G4endl;
197  }
198
199  if(isInitialised) return;
200  fParticleChange = GetParticleChangeForLoss();
201  isInitialised = true; 
202}
203
204//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
205
206G4double G4PenelopeIonisationModel::CrossSectionPerVolume(const G4Material* material,
207                                           const G4ParticleDefinition* theParticle,
208                                           G4double energy,
209                                           G4double cutEnergy,
210                                           G4double)           
211{ 
212  // Penelope model to calculate the cross section for inelastic collisions above the
213  // threshold. It makes use of the Generalised Oscillator Strength (GOS) model from
214  //  D. Liljequist, J. Phys. D: Appl. Phys. 16 (1983) 1567
215  //
216  // The total cross section (hard+soft) is read from a database file (element per
217  // element), while the ratio hard-to-total is calculated analytically by taking
218  // into account the atomic oscillators coming into the play for a given threshold.
219  // This is done by the method CalculateCrossSectionsRatio().
220  // For incident e- the maximum energy allowed for the delta-rays is energy/2.
221  // because particles are undistinghishable.
222  //
223  // The contribution is splitted in three parts: distant longitudinal collisions,
224  // distant transverse collisions and close collisions. Each term is described by
225  // its own analytical function.
226  // Fermi density correction is calculated analytically according to
227  //  U. Fano, Ann. Rev. Nucl. Sci. 13 (1963),1
228  //
229  if (verboseLevel > 3)
230    G4cout << "Calling CrossSectionPerVolume() of G4PenelopeIonisationModel" << G4endl;
231
232  SetupForMaterial(theParticle, material, energy);
233
234  // VI - should be check at initialisation not in run time
235  /*
236  if (!crossSectionHandler)
237    {
238      G4cout << "G4PenelopeIonisationModel::CrossSectionPerVolume" << G4endl;
239      G4cout << "The cross section handler is not correctly initialized" << G4endl;
240      G4Exception();
241    }
242  */ 
243  if (!theXSTable)
244    {
245      if (verboseLevel > 2)
246        {
247          G4cout << "G4PenelopeIonisationModel::CrossSectionPerVolume" << G4endl;
248          G4cout << "Going to build Cross Section table " << G4endl;
249        }
250      theXSTable = new std::vector<G4VEMDataSet*>;
251      theXSTable = BuildCrossSectionTable(theParticle); 
252    }
253 
254  G4double totalCross = 0.0; 
255  G4double cross = 0.0;
256  const G4ElementVector* theElementVector = material->GetElementVector();
257  const G4double* theAtomNumDensityVector = material->GetVecNbOfAtomsPerVolume();
258  G4double electronVolumeDensity =
259    material->GetTotNbOfElectPerVolume();  //electron density
260
261  if (verboseLevel > 4)
262    G4cout << "Electron volume density of " << material->GetName() << ": " << 
263      electronVolumeDensity*cm3 << " electrons/cm3" << G4endl;
264
265  G4int nelm = material->GetNumberOfElements();
266  for (G4int i=0; i<nelm; i++) 
267    {
268      G4int iZ = (G4int) (*theElementVector)[i]->GetZ();
269      G4double ratio = CalculateCrossSectionsRatio(energy,cutEnergy,iZ,electronVolumeDensity,
270                                                   theParticle);
271      cross += theAtomNumDensityVector[i]*
272        crossSectionHandler->FindValue(iZ,energy)*ratio;
273      totalCross += theAtomNumDensityVector[i]*
274        crossSectionHandler->FindValue(iZ,energy);
275    }
276
277  if (verboseLevel > 2)
278  {
279    G4cout << "G4PenelopeIonisationModel " << G4endl;
280    G4cout << "Mean free path for delta emission > " << cutEnergy/keV << " keV at " << 
281      energy/keV << " keV = " << (1./cross)/mm << " mm" << G4endl;
282    G4cout << "Total free path for ionisation (no threshold) at " << 
283      energy/keV << " keV = " << (1./totalCross)/mm << " mm" << G4endl;
284  }
285  return cross;
286}
287
288//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
289
290//This is a dummy method. Never inkoved by the tracking, it just issues
291//a warning if one tries to get Cross Sections per Atom via the
292//G4EmCalculator.
293G4double G4PenelopeIonisationModel::ComputeCrossSectionPerAtom(const G4ParticleDefinition*,
294                                                             G4double,
295                                                             G4double,
296                                                             G4double,
297                                                             G4double,
298                                                             G4double)
299{
300  G4cout << "*** G4PenelopeIonisationModel -- WARNING ***" << G4endl;
301  G4cout << "Penelope Ionisation model does not calculate cross section _per atom_ " << G4endl;
302  G4cout << "so the result is always zero. For physics values, please invoke " << G4endl;
303  G4cout << "GetCrossSectionPerVolume() or GetMeanFreePath() via the G4EmCalculator" << G4endl;
304  return 0;
305}
306
307//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
308
309G4double G4PenelopeIonisationModel::ComputeDEDXPerVolume(const G4Material* material,
310                                           const G4ParticleDefinition* theParticle,
311                                           G4double kineticEnergy,
312                                           G4double cutEnergy)
313{
314  // Penelope model to calculate the stopping power for soft inelastic collisions
315  // below the threshold. It makes use of the Generalised Oscillator Strength (GOS)
316  // model from
317  //  D. Liljequist, J. Phys. D: Appl. Phys. 16 (1983) 1567
318  //
319  // The stopping power is calculated analytically using the dsigma/dW cross
320  // section from the GOS models, which includes separate contributions from
321  // distant longitudinal collisions, distant transverse collisions and
322  // close collisions. Only the atomic oscillators that come in the play
323  // (according to the threshold) are considered for the calculation.
324  // Differential cross sections have a different form for e+ and e-.
325  //
326  // Fermi density correction is calculated analytically according to
327  //  U. Fano, Ann. Rev. Nucl. Sci. 13 (1963),1
328
329  if (verboseLevel > 3)
330    G4cout << "Calling ComputeDEDX() of G4PenelopeIonisationModel" << G4endl;
331
332  G4double sPower = 0.0;
333  const G4ElementVector* theElementVector = material->GetElementVector();
334  const G4double* theAtomNumDensityVector = material->GetVecNbOfAtomsPerVolume();
335  G4double electronVolumeDensity =
336    material->GetTotNbOfElectPerVolume();  //electron density
337
338  //Loop on the elements in the material
339  G4int nelm = material->GetNumberOfElements();
340  for (G4int i=0; i<nelm; i++) 
341    {
342      G4int iZ = (G4int) (*theElementVector)[i]->GetZ();
343   
344      //Calculate stopping power contribution from each element
345      //Constants
346      G4double gamma = 1.0+kineticEnergy/electron_mass_c2;
347      G4double gamma2 = gamma*gamma;
348      G4double beta2 = (gamma2-1.0)/gamma2;
349      G4double constant = pi*classic_electr_radius*classic_electr_radius
350        *2.0*electron_mass_c2/beta2;
351 
352      G4double delta = CalculateDeltaFermi(kineticEnergy,iZ,electronVolumeDensity);
353      G4int nbOsc = (G4int) resonanceEnergy->find(iZ)->second->size();
354      G4double stoppingPowerForElement = 0.0;
355      //Loop on oscillators of element Z
356      for (G4int iosc=0;iosc<nbOsc;iosc++)
357        {
358          G4double S1 = 0.0;
359          G4double resEnergy = (*(resonanceEnergy->find(iZ)->second))[iosc];
360          if (theParticle == G4Electron::Electron())
361            S1 = ComputeStoppingPowerForElectrons(kineticEnergy,cutEnergy,delta,resEnergy);
362          else if (theParticle == G4Positron::Positron())
363            S1 = ComputeStoppingPowerForPositrons(kineticEnergy,cutEnergy,delta,resEnergy);
364          G4double occupNb = (*(occupationNumber->find(iZ)->second))[iosc];
365          stoppingPowerForElement += occupNb*constant*S1;
366        }
367
368      sPower += stoppingPowerForElement*theAtomNumDensityVector[i];
369    }
370  if (verboseLevel > 2)
371    {
372      G4cout << "G4PenelopeIonisationModel " << G4endl;
373      G4cout << "Stopping power < " << cutEnergy/keV << " keV at " << 
374        kineticEnergy/keV << " keV = " << sPower/(keV/mm) << " keV/mm" << G4endl;
375    } 
376  return sPower;
377}
378
379//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
380
381G4double G4PenelopeIonisationModel::MinEnergyCut(const G4ParticleDefinition*,
382                                                 const G4MaterialCutsCouple*)
383{
384  return fIntrinsicLowEnergyLimit;
385}
386
387//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
388
389void G4PenelopeIonisationModel::SampleSecondaries(std::vector<G4DynamicParticle*>* fvect,
390                                              const G4MaterialCutsCouple* couple,
391                                              const G4DynamicParticle* aDynamicParticle,
392                                              G4double cutE, G4double)
393{
394  // Penelope model to sample the final state following an hard inelastic interaction.
395  // It makes use of the Generalised Oscillator Strength (GOS) model from
396  //  D. Liljequist, J. Phys. D: Appl. Phys. 16 (1983) 1567
397  //
398  // The GOS model is used to calculate the individual cross sections for all
399  // the atomic oscillators coming in the play, taking into account the three
400  // contributions (distant longitudinal collisions, distant transverse collisions and
401  // close collisions). Then the target shell and the interaction channel are
402  // sampled. Final state of the delta-ray (energy, angle) are generated according
403  // to the analytical distributions (dSigma/dW) for the selected interaction
404  // channels.
405  // For e-, the maximum energy for the delta-ray is initialEnergy/2. (because
406  // particles are indistinghusbable), while it is the full initialEnergy for
407  // e+.
408  // The efficiency of the random sampling algorithm (e.g. for close collisions)
409  // decreases when initial and cutoff energy increase (e.g. 87% for 10-keV primary
410  // and 1 keV threshold, 99% for 10-MeV primary and 10-keV threshold).
411  // Differential cross sections have a different form for e+ and e-.
412  //
413  // WARNING: The model provides an _average_ description of inelastic collisions.
414  // Anyway, the energy spectrum associated to distant excitations of a given
415  // atomic shell is approximated as a single resonance. The simulated energy spectra
416  // show _unphysical_ narrow peaks at energies that are multiple of the shell
417  // resonance energies. The spurious speaks are automatically smoothed out after
418  // multiple inelastic collisions.
419  //
420  // The model determines also the original shell from which the delta-ray is expelled,
421  // in order to produce fluorescence de-excitation (from G4DeexcitationManager)
422  //
423  // Fermi density correction is calculated analytically according to
424  //  U. Fano, Ann. Rev. Nucl. Sci. 13 (1963),1
425
426  if (verboseLevel > 3)
427    G4cout << "Calling SamplingSecondaries() of G4PenelopeIonisationModel" << G4endl;
428
429  G4double kineticEnergy0 = aDynamicParticle->GetKineticEnergy();
430  const G4ParticleDefinition* theParticle = aDynamicParticle->GetDefinition();
431
432  if (kineticEnergy0 <= fIntrinsicLowEnergyLimit)
433  {
434    fParticleChange->SetProposedKineticEnergy(0.);
435    fParticleChange->ProposeLocalEnergyDeposit(kineticEnergy0);
436    return ;
437  }
438  const G4double electronVolumeDensity = 
439    couple->GetMaterial()->GetTotNbOfElectPerVolume(); 
440  G4ParticleMomentum particleDirection0 = aDynamicParticle->GetMomentumDirection();
441
442  //Initialise final-state variables. The proper values will be set by the methods
443  // CalculateDiscreteForElectrons() and CalculateDiscreteForPositrons()
444  kineticEnergy1=kineticEnergy0;
445  cosThetaPrimary=1.0;
446  energySecondary=0.0;
447  cosThetaSecondary=1.0;
448
449  // Select randomly one element in the current material
450  if (verboseLevel > 2)
451    G4cout << "Going to select element in " << couple->GetMaterial()->GetName() << G4endl;
452
453  //Use sampler of G4CrossSectionHandler for now
454  // atom can be selected effitiantly if element selectors are initialised   
455  //const G4Element* anElement = SelectRandomAtom(couple,theParticle,kineticEnergy0);
456
457  G4int iZ = SampleRandomAtom(couple,kineticEnergy0);
458 
459  const G4ProductionCutsTable* theCoupleTable=
460    G4ProductionCutsTable::GetProductionCutsTable();
461  size_t indx = couple->GetIndex();
462  G4double cutG = (*(theCoupleTable->GetEnergyCutsVector(0)))[indx];
463 
464  if (verboseLevel > 2)
465    G4cout << "Selected Z = " << iZ << G4endl;
466 
467  // The method CalculateDiscreteForXXXX() set the private variables:
468  // kineticEnergy1 = energy of the primary electron/positron after the interaction
469  // cosThetaPrimary = std::cos(theta) of the primary after the interaction
470  // energySecondary = energy of the secondary electron
471  // cosThetaSecondary = std::cos(theta) of the secondary
472  if (theParticle == G4Electron::Electron())
473    CalculateDiscreteForElectrons(kineticEnergy0,cutE,iZ,electronVolumeDensity);
474  else if (theParticle == G4Positron::Positron())
475    CalculateDiscreteForPositrons(kineticEnergy0,cutE,iZ,electronVolumeDensity);
476
477  // if (energySecondary == 0) return;
478
479  //Update the primary particle
480  G4double sint = std::sqrt(1. - cosThetaPrimary*cosThetaPrimary);
481  G4double phi  = twopi * G4UniformRand();
482  G4double dirx = sint * std::cos(phi);
483  G4double diry = sint * std::sin(phi);
484  G4double dirz = cosThetaPrimary;
485
486  G4ThreeVector electronDirection1(dirx,diry,dirz);
487  electronDirection1.rotateUz(particleDirection0);
488 
489  if (kineticEnergy1 > 0)
490    {
491      fParticleChange->ProposeMomentumDirection(electronDirection1);
492      fParticleChange->SetProposedKineticEnergy(kineticEnergy1);
493    }
494  else
495    {
496      fParticleChange->SetProposedKineticEnergy(0.);
497    }
498 
499  //Generate the delta ray
500  G4int iosc2 = 0;
501  G4double ioniEnergy = 0.0;
502  if (iOsc > 0) {
503    ioniEnergy=(*(ionizationEnergy->find(iZ)->second))[iOsc];
504    iosc2 = (ionizationEnergy->find(iZ)->second->size()) - iOsc; //they are in reversed order
505  }
506
507  const G4AtomicTransitionManager* transitionManager = G4AtomicTransitionManager::Instance();
508  G4double bindingEnergy = 0.0;
509  G4int shellId = 0;
510  if (iOsc > 0)
511    {
512      const G4AtomicShell* shell = transitionManager->Shell(iZ,iosc2-1); // Modified by Alf
513      bindingEnergy = shell->BindingEnergy();
514      shellId = shell->ShellId();
515    }
516
517  G4double ionEnergy = bindingEnergy; //energy spent to ionise the atom according to G4dabatase
518  G4double eKineticEnergy = energySecondary;
519
520  //This is an awful thing: Penelope generates the fluorescence only for L and K shells
521  //(i.e. Osc = 1 --> 4). For high-Z, the other shells can be quite relevant. In this case
522  //one MUST ensure ''by hand'' the energy conservation. Then there is the other problem that
523  //the fluorescence database of Penelope doesn not match that of Geant4.
524
525  G4double energyBalance = kineticEnergy0 - kineticEnergy1 - energySecondary; //Penelope Balance
526
527  if (std::abs(energyBalance) < 1*eV)
528    //in this case Penelope didn't subtract the fluorescence energy: do here by hand
529    eKineticEnergy = energySecondary - bindingEnergy;   
530  else 
531    //Penelope subtracted the fluorescence, but one has to match the databases
532    eKineticEnergy = energySecondary+ioniEnergy-bindingEnergy;
533 
534  G4double localEnergyDeposit = ionEnergy; 
535  G4double energyInFluorescence = 0.0*eV;
536
537  if(DeexcitationFlag() && iZ > 5) 
538    {
539      if (ionEnergy > cutG || ionEnergy > cutE)
540        {
541          deexcitationManager.SetCutForSecondaryPhotons(cutG);
542          deexcitationManager.SetCutForAugerElectrons(cutE);
543          std::vector<G4DynamicParticle*> *photonVector =
544            deexcitationManager.GenerateParticles(iZ,shellId);
545          //Check for secondaries
546          if(photonVector) 
547            {
548              for (size_t k=0;k<photonVector->size();k++)
549                {
550                  G4DynamicParticle* aPhoton = (*photonVector)[k];
551                  if (aPhoton)
552                    {
553                      G4double itsEnergy = aPhoton->GetKineticEnergy();
554                      if (itsEnergy <= localEnergyDeposit)
555                        {
556                          if(aPhoton->GetDefinition() == G4Gamma::Gamma())
557                            energyInFluorescence += itsEnergy;
558                          localEnergyDeposit -= itsEnergy;
559                          fvect->push_back(aPhoton);
560                        }
561                      else
562                        {
563                          delete aPhoton;
564                          (*photonVector)[k] = 0;
565                        }
566                    }
567                }
568              delete photonVector;
569            }
570        }
571    }
572
573  // Generate the delta ray
574  G4double sin2 = std::sqrt(1. - cosThetaSecondary*cosThetaSecondary);
575  G4double phi2  = twopi * G4UniformRand();
576 
577  G4double xEl = sin2 * std::cos(phi2); 
578  G4double yEl = sin2 * std::sin(phi2);
579  G4double zEl = cosThetaSecondary;
580  G4ThreeVector eDirection(xEl,yEl,zEl); //electron direction
581  eDirection.rotateUz(particleDirection0);
582
583  G4DynamicParticle* deltaElectron = new G4DynamicParticle (G4Electron::Electron(),
584                                                            eDirection,eKineticEnergy) ;
585  fvect->push_back(deltaElectron);
586 
587  if (localEnergyDeposit < 0)
588    {
589      G4cout << "WARNING-" 
590             << "G4PenelopeIonisationModel::SampleSecondaries - Negative energy deposit"
591             << G4endl;
592      localEnergyDeposit=0.;
593    }
594  fParticleChange->ProposeLocalEnergyDeposit(localEnergyDeposit);
595 
596  if (verboseLevel > 1)
597    {
598      G4cout << "-----------------------------------------------------------" << G4endl;
599      G4cout << "Energy balance from G4PenelopeIonisation" << G4endl;
600      G4cout << "Incoming primary energy: " << kineticEnergy0/keV << " keV" << G4endl;
601      G4cout << "-----------------------------------------------------------" << G4endl;
602      G4cout << "Outgoing primary energy: " << kineticEnergy1/keV << " keV" << G4endl;
603      G4cout << "Delta ray " << eKineticEnergy/keV << " keV" << G4endl;
604      G4cout << "Fluorescence: " << energyInFluorescence/keV << " keV" << G4endl;
605      G4cout << "Local energy deposit " << localEnergyDeposit/keV << " keV" << G4endl;
606      G4cout << "Total final state: " << (eKineticEnergy+energyInFluorescence+kineticEnergy1+
607                                          localEnergyDeposit)/keV << 
608        " keV" << G4endl;
609      G4cout << "-----------------------------------------------------------" << G4endl;
610    }
611  if (verboseLevel > 0)
612    {
613      G4double energyDiff = std::fabs(eKineticEnergy+energyInFluorescence+kineticEnergy1+
614                                      localEnergyDeposit-kineticEnergy0);
615      if (energyDiff > 0.05*keV)
616        G4cout << "Warning from G4PenelopeIonisation: problem with energy conservation: " << 
617          (eKineticEnergy+energyInFluorescence+kineticEnergy1+localEnergyDeposit)/keV << 
618          " keV (final) vs. " << 
619          kineticEnergy0/keV << " keV (initial)" << G4endl;
620    }
621}
622
623//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
624
625void G4PenelopeIonisationModel::ReadData()
626{
627  if (verboseLevel > 2)
628    {
629      G4cout << "Data from G4PenelopeIonisationModel read " << G4endl;
630    }
631  char* path = getenv("G4LEDATA");
632  if (!path)
633    {
634      G4String excep = "G4PenelopeIonisationModel - G4LEDATA environment variable not set!";
635      G4Exception(excep);
636    }
637  G4String pathString(path);
638  G4String pathFile = pathString + "/penelope/ion-pen.dat";
639  std::ifstream file(pathFile);
640 
641  if (!file.is_open())
642    {
643      G4String excep = "G4PenelopeIonisationModel - data file " + pathFile + " not found!";
644      G4Exception(excep);
645    }
646
647 if (!ionizationEnergy || !resonanceEnergy || !occupationNumber || !shellFlag)
648    {
649      G4String excep = "G4PenelopeIonisationModel: problem with reading data from file";
650      G4Exception(excep);
651    }
652
653 G4int Z=1,nLevels=0;
654 G4int test,test1;
655
656 do{
657   G4DataVector* occVector = new G4DataVector;
658   G4DataVector* ionEVector = new G4DataVector;
659   G4DataVector* resEVector = new G4DataVector;
660   G4DataVector* shellIndVector = new G4DataVector;
661   file >> Z >> nLevels;
662   G4double a1,a2,a3,a4;
663   G4int k1,k2,k3;
664   for (G4int h=0;h<nLevels;h++)
665     {
666       //index,occup number,ion energy,res energy,fj0,kz,shell flag
667       file >> k1 >> a1 >> a2 >> a3 >> a4 >> k2 >> k3;
668       //Make explicit unit of measurements for ionisation and resonance energy,
669       // which is MeV
670       a2 *= MeV;
671       a3 *= MeV;
672       //
673       occVector->push_back(a1);
674       ionEVector->push_back(a2);
675       resEVector->push_back(a3);
676       shellIndVector->push_back((G4double) k3);
677     }
678   //Ok, done for element Z
679   occupationNumber->insert(std::make_pair(Z,occVector));
680   ionizationEnergy->insert(std::make_pair(Z,ionEVector));
681   resonanceEnergy->insert(std::make_pair(Z,resEVector));
682   shellFlag->insert(std::make_pair(Z,shellIndVector));
683   file >> test >> test1; //-1 -1 close the data for each Z
684   if (test > 0) {
685     G4String excep = "G4PenelopeIonisationModel - data file corrupted!";
686     G4Exception(excep);
687   }
688 }while (test != -2); //the very last Z is closed with -2 instead of -1
689}
690                                   
691                                           
692//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
693
694G4double G4PenelopeIonisationModel::CalculateDeltaFermi(G4double kinEnergy ,G4int Z,
695                                                        G4double electronVolumeDensity)
696{
697  G4double plasmaEnergyCoefficient = 1.377e-39*(MeV*MeV*m3); //(e*hbar)^2/(epsilon0*electron_mass)
698  G4double plasmaEnergySquared = plasmaEnergyCoefficient*electronVolumeDensity;
699  // std::sqrt(plasmaEnergySquared) is the plasma energy of the solid (MeV)
700  G4double gam = 1.0+kinEnergy/electron_mass_c2;
701  G4double gam2=gam*gam;
702  G4double delta = 0.0;
703
704  //Density effect
705  G4double TST = ((G4double) Z)/(gam2*plasmaEnergySquared); 
706 
707  G4double wl2 = 0.0;
708  G4double fdel=0.0;
709  G4double wr=0;
710  size_t nbOsc = resonanceEnergy->find(Z)->second->size();
711  for(size_t i=0;i<nbOsc;i++)
712    {
713      G4int occupNb = (G4int) (*(occupationNumber->find(Z)->second))[i];
714      wr = (*(resonanceEnergy->find(Z)->second))[i];
715      fdel += occupNb/(wr*wr+wl2);
716    }
717  if (fdel < TST) return delta;
718  G4double help1 = (*(resonanceEnergy->find(Z)->second))[nbOsc-1];
719  wl2 = help1*help1;
720  do{
721    wl2=wl2*2.0;
722    fdel = 0.0;
723    for (size_t ii=0;ii<nbOsc;ii++){
724      G4int occupNb = (G4int) (*(occupationNumber->find(Z)->second))[ii];
725      wr = (*(resonanceEnergy->find(Z)->second))[ii];
726      fdel += occupNb/(wr*wr+wl2);
727    }
728  }while (fdel > TST);
729  G4double wl2l=0.0;
730  G4double wl2u = wl2;
731  G4double control = 0.0;
732  do{
733    wl2=0.5*(wl2l+wl2u);
734    fdel = 0.0;
735    for (size_t jj=0;jj<nbOsc;jj++){
736      G4int occupNb = (G4int) (*(occupationNumber->find(Z)->second))[jj];
737      wr = (*(resonanceEnergy->find(Z)->second))[jj];
738      fdel += occupNb/(wr*wr+wl2);
739    }
740    if (fdel > TST)
741      wl2l = wl2;
742    else
743      wl2u = wl2;
744    control = wl2u-wl2l-wl2*1e-12; 
745  }while(control>0);
746
747  //Density correction effect
748   for (size_t kk=0;kk<nbOsc;kk++){
749      G4int occupNb = (G4int) (*(occupationNumber->find(Z)->second))[kk];
750      wr = (*(resonanceEnergy->find(Z)->second))[kk];
751      delta += occupNb*std::log(1.0+wl2/(wr*wr));
752    }
753   delta = (delta/((G4double) Z))-wl2/(gam2*plasmaEnergySquared); 
754   return delta;
755}
756
757//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
758
759void 
760G4PenelopeIonisationModel::CalculateDiscreteForElectrons(G4double kinEnergy,
761                                                         G4double cutoffEnergy,
762                                                         G4int Z,
763                                                         G4double electronVolumeDensity)
764{
765  if (verboseLevel > 2)
766    G4cout << "Entering in CalculateDiscreteForElectrons() for energy " << 
767      kinEnergy/keV << " keV " << G4endl;
768
769  //Initialization of variables to be calculated in this routine
770  kineticEnergy1=kinEnergy;
771  cosThetaPrimary=1.0;
772  energySecondary=0.0;
773  cosThetaSecondary=1.0;
774  iOsc=-1;
775
776  //constants
777  G4double rb=kinEnergy+2.0*electron_mass_c2;
778  G4double gamma = 1.0+kinEnergy/electron_mass_c2;
779  G4double gamma2 = gamma*gamma;
780  G4double beta2 = (gamma2-1.0)/gamma2;
781  G4double amol = (gamma-1.0)*(gamma-1.0)/gamma2;
782  G4double cps = kinEnergy*rb;
783  G4double cp = std::sqrt(cps);
784 
785  G4double delta = CalculateDeltaFermi(kinEnergy,Z,electronVolumeDensity);
786  G4double distantTransvCS0 = std::max(std::log(gamma2)-beta2-delta,0.0);
787
788  G4double rl,rl1;
789
790  if (cutoffEnergy > kinEnergy) return; //delta rays are not generated
791
792  G4DataVector* qm = new G4DataVector();
793  G4DataVector* cumulHardCS = new G4DataVector();
794  std::vector<G4int> *typeOfInteraction = new std::vector<G4int>;
795  G4DataVector* nbOfLevel = new G4DataVector();
796 
797  //Hard close collisions with outer shells
798  G4double wmaxc = 0.5*kinEnergy;
799  G4double closeCS0 = 0.0;
800  G4double closeCS = 0.0;
801  if (cutoffEnergy>0.1*eV) 
802    {
803      rl=cutoffEnergy/kinEnergy;
804      rl1=1.0-rl;
805      if (rl < 0.5)
806        closeCS0 = (amol*(0.5-rl)+(1.0/rl)-(1.0/rl1)+(1.0-amol)*std::log(rl/rl1))/kinEnergy;
807    }
808
809  // Cross sections for the different oscillators
810
811  // totalHardCS contains the cumulative hard interaction cross section for the different
812  // excitable levels and the different interaction channels (close, distant, etc.),
813  // i.e.
814  // cumulHardCS[0] = 0.0
815  // cumulHardCS[1] = 1st excitable level (distant longitudinal only)
816  // cumulHardCS[2] = 1st excitable level (distant longitudinal + transverse)
817  // cumulHardCS[3] = 1st excitable level (distant longitudinal + transverse + close)
818  // cumulHardCS[4] = 1st excitable level (all channels) + 2nd excitable level (distant long only)
819  // etc.
820  // This is used for sampling the atomic level which is ionised and the channel of the
821  // interaction.
822  //
823  // For each index iFill of the cumulHardCS vector,
824  // nbOfLevel[iFill] contains the current excitable atomic level and
825  // typeOfInteraction[iFill] contains the current interaction channel, with the legenda:
826  //   1 = distant longitudinal interaction
827  //   2 = distant transverse interaction
828  //   3 = close collision
829  //   4 = close collision with outer shells (in this case nbOfLevel < 0 --> no binding energy)
830
831
832  G4int nOscil = ionizationEnergy->find(Z)->second->size();
833  G4double totalHardCS = 0.0;
834  G4double involvedElectrons = 0.0;
835  for (G4int i=0;i<nOscil;i++){
836    G4double wi = (*(resonanceEnergy->find(Z)->second))[i];
837    G4int occupNb = (G4int) (*(occupationNumber->find(Z)->second))[i];
838 
839    //Distant excitations
840    if (wi>cutoffEnergy && wi<kinEnergy)
841      {
842        if (wi>(1e-6*kinEnergy))
843          {
844            G4double cpp=std::sqrt((kinEnergy-wi)*(kinEnergy-wi+2.0*electron_mass_c2));
845            qm->push_back(std::sqrt((cp-cpp)*(cp-cpp)+electron_mass_c2*electron_mass_c2)-electron_mass_c2);
846          }
847        else
848          {
849            qm->push_back((wi*wi)/(beta2*2.0*electron_mass_c2));
850          }
851        if ((*qm)[i] < wi)
852          {
853           
854            G4double distantLongitCS =  occupNb*std::log(wi*((*qm)[i]+2.0*electron_mass_c2)/
855                                         ((*qm)[i]*(wi+2.0*electron_mass_c2)))/wi;
856            cumulHardCS->push_back(totalHardCS);
857            typeOfInteraction->push_back(1); //distant longitudinal
858            nbOfLevel->push_back((G4double) i); //only excitable level are counted
859            totalHardCS += distantLongitCS;
860           
861            G4double distantTransvCS = occupNb*distantTransvCS0/wi;
862           
863            cumulHardCS->push_back(totalHardCS);
864            typeOfInteraction->push_back(2); //distant tranverse
865            nbOfLevel->push_back((G4double) i);
866            totalHardCS += distantTransvCS;
867          }
868      }
869    else 
870      qm->push_back(wi);
871     
872    //close collisions
873    if(wi < wmaxc)
874      {
875        if (wi < cutoffEnergy) 
876          involvedElectrons += occupNb;
877        else
878          {
879            rl=wi/kinEnergy;
880            rl1=1.0-rl;
881            closeCS = occupNb*(amol*(0.5-rl)+(1.0/rl)-(1.0/rl1)+(1.0-amol)*std::log(rl/rl1))/kinEnergy;
882            cumulHardCS->push_back(totalHardCS);
883            typeOfInteraction->push_back(3); //close
884            nbOfLevel->push_back((G4double) i);
885            totalHardCS += closeCS;
886          }
887      }
888  } // loop on the levels
889 
890  cumulHardCS->push_back(totalHardCS);
891  typeOfInteraction->push_back(4); //close interaction with outer shells
892  nbOfLevel->push_back(-1.0);
893  totalHardCS += involvedElectrons*closeCS0;
894  cumulHardCS->push_back(totalHardCS); //this is the final value of the totalHardCS
895
896  if (totalHardCS < 1e-30) {
897    kineticEnergy1=kinEnergy;
898    cosThetaPrimary=1.0;
899    energySecondary=0.0;
900    cosThetaSecondary=0.0;
901    iOsc=-1;
902    delete qm;
903    delete cumulHardCS;
904    delete typeOfInteraction;
905    delete nbOfLevel;
906    return;
907  }
908
909  //Testing purposes
910  if (verboseLevel > 6)
911    {
912      for (size_t t=0;t<cumulHardCS->size();t++)
913        G4cout << (*cumulHardCS)[t] << " " << (*typeOfInteraction)[t] << 
914          " " << (*nbOfLevel)[t] << G4endl;
915    }
916
917  //Selection of the active oscillator on the basis of the cumulative cross sections
918  G4double TST = totalHardCS*G4UniformRand();
919  G4int is=0;
920  G4int js= nbOfLevel->size();
921  do{
922    G4int it=(is+js)/2;
923    if (TST > (*cumulHardCS)[it]) is=it;
924    if (TST <= (*cumulHardCS)[it]) js=it;
925  }while((js-is) > 1);
926
927  G4double UII=0.0;
928  G4double rkc=cutoffEnergy/kinEnergy;
929  G4double dde;
930  G4int kks;
931
932  G4int sampledInteraction = (*typeOfInteraction)[is];
933  iOsc = (G4int) (*nbOfLevel)[is];
934
935  if (verboseLevel > 4) 
936    G4cout << "Chosen interaction #:" << sampledInteraction << " on level " << iOsc << G4endl;
937
938  //Generates the final state according to the sampled level and
939  //interaction channel
940 
941  if (sampledInteraction == 1)  //Hard distant longitudinal collisions
942    {
943      dde= (*(resonanceEnergy->find(Z)->second))[iOsc];
944      kineticEnergy1=kinEnergy-dde;
945      G4double qs=(*qm)[iOsc]/(1.0+((*qm)[iOsc]/(2.0*electron_mass_c2)));
946      G4double q=qs/(std::pow((qs/dde)*(1.0+(0.5*dde/electron_mass_c2)),G4UniformRand())-(0.5*qs/electron_mass_c2));
947      G4double qtrev = q*(q+2.0*electron_mass_c2);
948      G4double cpps = kineticEnergy1*(kineticEnergy1+2.0*electron_mass_c2);
949      cosThetaPrimary = (cpps+cps-qtrev)/(2.0*cp*std::sqrt(cpps));
950      if (cosThetaPrimary>1.0) cosThetaPrimary=1.0;
951      //Energy and emission angle of the delta ray
952      kks = (G4int) (*(shellFlag->find(Z)->second))[iOsc];
953      //kks > 4 means that we are in an outer shell
954      if (kks>4) 
955        energySecondary=dde;
956      else
957        energySecondary=dde-(*(ionizationEnergy->find(Z)->second))[iOsc];
958       
959      cosThetaSecondary = 0.5*(dde*(kinEnergy+rb-dde)+qtrev)/std::sqrt(cps*qtrev);
960      if (cosThetaSecondary>1.0) cosThetaSecondary=1.0;
961    }
962  else if (sampledInteraction == 2)  //Hard distant transverse collisions
963    {
964      dde=(*(resonanceEnergy->find(Z)->second))[iOsc];
965      kineticEnergy1=kinEnergy-dde;
966      cosThetaPrimary=1.0;
967      //Energy and emission angle of the delta ray
968      kks = (G4int) (*(shellFlag->find(Z)->second))[iOsc];
969      if (kks>4)
970        {
971          energySecondary=dde;
972        }
973      else
974        {
975          energySecondary=dde-(*(ionizationEnergy->find(Z)->second))[iOsc];
976        }
977      cosThetaSecondary = 1.0;
978    }
979  else if (sampledInteraction == 3 || sampledInteraction == 4) //Close interaction
980    {
981      if (sampledInteraction == 4) //interaction with inner shells
982        {
983          UII=0.0;
984          rkc = cutoffEnergy/kinEnergy;
985          iOsc = -1;
986        }
987      else
988        {
989          kks = (G4int) (*(shellFlag->find(Z)->second))[iOsc];
990          if (kks > 4) {
991            UII=0.0;
992          }
993          else
994            {
995              UII = (*(ionizationEnergy->find(Z)->second))[iOsc];
996            }
997          rkc = (*(resonanceEnergy->find(Z)->second))[iOsc]/kinEnergy;
998        }
999    G4double A = 0.5*amol;
1000    G4double arkc = A*0.5*rkc;
1001    G4double phi,rk2,rk,rkf;
1002    do{
1003      G4double fb = (1.0+arkc)*G4UniformRand();
1004      if (fb<1.0)
1005        {
1006          rk=rkc/(1.0-fb*(1.0-(rkc*2.0)));
1007        }
1008      else{
1009        rk = rkc+(fb-1.0)*(0.5-rkc)/arkc;
1010      }
1011      rk2 = rk*rk;
1012      rkf = rk/(1.0-rk);
1013      phi = 1.0+(rkf*rkf)-rkf+amol*(rk2+rkf);
1014    }while ((G4UniformRand()*(1.0+A*rk2)) > phi);
1015    //Energy and scattering angle (primary electron);
1016    kineticEnergy1 = kinEnergy*(1.0-rk);
1017    cosThetaPrimary = std::sqrt(kineticEnergy1*rb/(kinEnergy*(rb-(rk*kinEnergy))));
1018    //Energy and scattering angle of the delta ray
1019    energySecondary = kinEnergy-kineticEnergy1-UII;
1020    cosThetaSecondary = std::sqrt(rk*kinEnergy*rb/(kinEnergy*(rk*kinEnergy+2.0*electron_mass_c2)));
1021    }
1022  else
1023    {
1024      G4String excep = "G4PenelopeIonisationModel - Error in the calculation of the final state";
1025      G4Exception(excep);
1026    }
1027
1028  delete qm;
1029  delete cumulHardCS;
1030 
1031  delete typeOfInteraction;
1032  delete nbOfLevel;
1033
1034  return;
1035}
1036
1037//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1038
1039 void 
1040G4PenelopeIonisationModel::CalculateDiscreteForPositrons(G4double kinEnergy,
1041                                                         G4double cutoffEnergy,
1042                                                         G4int Z,
1043                                                         G4double electronVolumeDensity)
1044{
1045  kineticEnergy1=kinEnergy;
1046  cosThetaPrimary=1.0;
1047  energySecondary=0.0;
1048  cosThetaSecondary=1.0;
1049  iOsc=-1;
1050  //constants
1051  G4double rb=kinEnergy+2.0*electron_mass_c2;
1052  G4double gamma = 1.0+kinEnergy/electron_mass_c2;
1053  G4double gamma2 = gamma*gamma;
1054  G4double beta2 = (gamma2-1.0)/gamma2;
1055  G4double amol = (gamma-1.0)*(gamma-1.0)/gamma2;
1056  G4double cps = kinEnergy*rb;
1057  G4double cp = std::sqrt(cps);
1058  G4double help = (gamma+1.0)*(gamma+1.0);
1059  G4double bha1 = amol*(2.0*help-1.0)/(gamma2-1.0);
1060  G4double bha2 = amol*(3.0+1.0/help);
1061  G4double bha3 = amol*2.0*gamma*(gamma-1.0)/help;
1062  G4double bha4 = amol*(gamma-1.0)*(gamma-1.0)/help;
1063 
1064  G4double delta = CalculateDeltaFermi(kinEnergy,Z,electronVolumeDensity);
1065  G4double distantTransvCS0 = std::max(std::log(gamma2)-beta2-delta,0.0);
1066
1067  G4double rl,rl1;
1068
1069  if (cutoffEnergy > kinEnergy) return; //delta rays are not generated
1070
1071  G4DataVector* qm = new G4DataVector();
1072  G4DataVector* cumulHardCS = new G4DataVector();
1073  std::vector<G4int> *typeOfInteraction = new std::vector<G4int>;
1074  G4DataVector* nbOfLevel = new G4DataVector();
1075 
1076
1077  //Hard close collisions with outer shells
1078  G4double wmaxc = kinEnergy;
1079  G4double closeCS0 = 0.0;
1080  G4double closeCS = 0.0;
1081  if (cutoffEnergy>0.1*eV) 
1082    {
1083      rl=cutoffEnergy/kinEnergy;
1084      rl1=1.0-rl;
1085      if (rl < 1.0)
1086        closeCS0 = (((1.0/rl)-1.0) + bha1*std::log(rl) + bha2*rl1
1087                    + (bha3/2.0)*((rl*rl)-1.0)
1088                    + (bha4/3.0)*(1.0-(rl*rl*rl)))/kinEnergy;
1089    }
1090
1091  // Cross sections for the different oscillators
1092
1093  // totalHardCS contains the cumulative hard interaction cross section for the different
1094  // excitable levels and the different interaction channels (close, distant, etc.),
1095  // i.e.
1096  // cumulHardCS[0] = 0.0
1097  // cumulHardCS[1] = 1st excitable level (distant longitudinal only)
1098  // cumulHardCS[2] = 1st excitable level (distant longitudinal + transverse)
1099  // cumulHardCS[3] = 1st excitable level (distant longitudinal + transverse + close)
1100  // cumulHardCS[4] = 1st excitable level (all channels) + 2nd excitable level (distant long only)
1101  // etc.
1102  // This is used for sampling the atomic level which is ionised and the channel of the
1103  // interaction.
1104  //
1105  // For each index iFill of the cumulHardCS vector,
1106  // nbOfLevel[iFill] contains the current excitable atomic level and
1107  // typeOfInteraction[iFill] contains the current interaction channel, with the legenda:
1108  //   1 = distant longitudinal interaction
1109  //   2 = distant transverse interaction
1110  //   3 = close collision
1111  //   4 = close collision with outer shells (in this case nbOfLevel < 0 --> no binding energy)
1112
1113
1114  G4int nOscil = ionizationEnergy->find(Z)->second->size();
1115  G4double totalHardCS = 0.0;
1116  G4double involvedElectrons = 0.0;
1117  for (G4int i=0;i<nOscil;i++){
1118    G4double wi = (*(resonanceEnergy->find(Z)->second))[i];
1119    G4int occupNb = (G4int) (*(occupationNumber->find(Z)->second))[i];
1120    //Distant excitations
1121    if (wi>cutoffEnergy && wi<kinEnergy)
1122      {
1123        if (wi>(1e-6*kinEnergy)){
1124          G4double cpp=std::sqrt((kinEnergy-wi)*(kinEnergy-wi+2.0*electron_mass_c2));
1125          qm->push_back(std::sqrt((cp-cpp)*(cp-cpp)+ electron_mass_c2 * electron_mass_c2)-electron_mass_c2);
1126        }
1127        else
1128          {
1129            qm->push_back(wi*wi/(beta2+2.0*electron_mass_c2));
1130          }
1131        //verificare che quando arriva qui il vettore ha SEMPRE l'i-esimo elemento
1132        if ((*qm)[i] < wi)
1133          {
1134           
1135            G4double distantLongitCS =  occupNb*std::log(wi*((*qm)[i]+2.0*electron_mass_c2)/
1136                                         ((*qm)[i]*(wi+2.0*electron_mass_c2)))/wi;
1137            cumulHardCS->push_back(totalHardCS);
1138            typeOfInteraction->push_back(1); //distant longitudinal
1139            nbOfLevel->push_back((G4double) i); //only excitable level are counted
1140            totalHardCS += distantLongitCS;
1141           
1142            G4double distantTransvCS = occupNb*distantTransvCS0/wi;
1143           
1144            cumulHardCS->push_back(totalHardCS);
1145            typeOfInteraction->push_back(2); //distant tranverse
1146            nbOfLevel->push_back((G4double) i);
1147            totalHardCS += distantTransvCS;
1148          }
1149      }
1150    else 
1151      qm->push_back(wi);
1152     
1153    //close collisions
1154    if(wi < wmaxc)
1155      {
1156        if (wi < cutoffEnergy) {
1157          involvedElectrons += occupNb;
1158        }
1159        else
1160          {
1161            rl=wi/kinEnergy;
1162            rl1=1.0-rl;
1163            closeCS = occupNb*(((1.0/rl)-1.0)+bha1*std::log(rl)+bha2*rl1
1164                               + (bha3/2.0)*((rl*rl)-1.0)
1165                               + (bha4/3.0)*(1.0-(rl*rl*rl)))/kinEnergy;
1166            cumulHardCS->push_back(totalHardCS);
1167            typeOfInteraction->push_back(3); //close
1168            nbOfLevel->push_back((G4double) i);
1169            totalHardCS += closeCS;
1170          }
1171      }
1172  } // loop on the levels
1173 
1174  cumulHardCS->push_back(totalHardCS);
1175  typeOfInteraction->push_back(4); //close interaction with outer shells
1176  nbOfLevel->push_back(-1.0);
1177  totalHardCS += involvedElectrons*closeCS0;
1178  cumulHardCS->push_back(totalHardCS); //this is the final value of the totalHardCS
1179
1180  if (totalHardCS < 1e-30) {
1181    kineticEnergy1=kinEnergy;
1182    cosThetaPrimary=1.0;
1183    energySecondary=0.0;
1184    cosThetaSecondary=0.0;
1185    iOsc=-1;
1186    delete qm;
1187    delete cumulHardCS;
1188    delete typeOfInteraction;
1189    delete nbOfLevel;
1190    return;
1191  }
1192
1193  //Selection of the active oscillator on the basis of the cumulative cross sections
1194  G4double TST = totalHardCS*G4UniformRand();
1195  G4int is=0;
1196  G4int js= nbOfLevel->size();
1197  do{
1198    G4int it=(is+js)/2;
1199    if (TST > (*cumulHardCS)[it]) is=it;
1200    if (TST <= (*cumulHardCS)[it]) js=it;
1201  }while((js-is) > 1);
1202
1203  G4double UII=0.0;
1204  G4double rkc=cutoffEnergy/kinEnergy;
1205  G4double dde;
1206  G4int kks;
1207
1208  G4int sampledInteraction = (*typeOfInteraction)[is];
1209  iOsc = (G4int) (*nbOfLevel)[is];
1210
1211  //Generates the final state according to the sampled level and
1212  //interaction channel
1213 
1214  if (sampledInteraction == 1)  //Hard distant longitudinal collisions
1215    {
1216      dde= (*(resonanceEnergy->find(Z)->second))[iOsc];
1217      kineticEnergy1=kinEnergy-dde;
1218      G4double qs=(*qm)[iOsc]/(1.0+((*qm)[iOsc]/(2.0*electron_mass_c2)));
1219      G4double q=qs/(std::pow((qs/dde)*(1.0+(0.5*dde/electron_mass_c2)),G4UniformRand())-(0.5*qs/electron_mass_c2));
1220      G4double qtrev = q*(q+2.0*electron_mass_c2);
1221      G4double cpps = kineticEnergy1*(kineticEnergy1+2.0*electron_mass_c2);
1222      cosThetaPrimary = (cpps+cps-qtrev)/(2.0*cp*std::sqrt(cpps));
1223      if (cosThetaPrimary>1.0) cosThetaPrimary=1.0;
1224      //Energy and emission angle of the delta ray
1225      kks = (G4int) (*(shellFlag->find(Z)->second))[iOsc];
1226      if (kks>4) 
1227        energySecondary=dde;
1228       
1229      else
1230        energySecondary=dde-(*(ionizationEnergy->find(Z)->second))[iOsc];
1231      cosThetaSecondary = 0.5*(dde*(kinEnergy+rb-dde)+qtrev)/std::sqrt(cps*qtrev);
1232      if (cosThetaSecondary>1.0) cosThetaSecondary=1.0;
1233    }
1234  else if (sampledInteraction == 2)  //Hard distant transverse collisions
1235    {
1236      dde=(*(resonanceEnergy->find(Z)->second))[iOsc];
1237      kineticEnergy1=kinEnergy-dde;
1238      cosThetaPrimary=1.0;
1239      //Energy and emission angle of the delta ray
1240      kks = (G4int) (*(shellFlag->find(Z)->second))[iOsc];
1241      if (kks>4)
1242        {
1243          energySecondary=dde;
1244        }
1245      else
1246        {
1247          energySecondary=dde-(*(ionizationEnergy->find(Z)->second))[iOsc];
1248        }
1249      cosThetaSecondary = 1.0;
1250    }
1251  else if (sampledInteraction == 3 || sampledInteraction == 4) //Close interaction
1252    {
1253      if (sampledInteraction == 4) //interaction with inner shells
1254        {
1255          UII=0.0;
1256          rkc = cutoffEnergy/kinEnergy;
1257          iOsc = -1;
1258        }
1259      else
1260        {
1261          kks = (G4int) (*(shellFlag->find(Z)->second))[iOsc];
1262          if (kks > 4) {
1263            UII=0.0;
1264          }
1265          else
1266            {
1267              UII = (*(ionizationEnergy->find(Z)->second))[iOsc];
1268            }
1269          rkc = (*(resonanceEnergy->find(Z)->second))[iOsc]/kinEnergy;
1270        }
1271      G4double phi,rk;
1272      do{
1273        rk=rkc/(1.0-G4UniformRand()*(1.0-rkc));
1274        phi = 1.0-rk*(bha1-rk*(bha2-rk*(bha3-bha4*rk)));
1275      }while ( G4UniformRand() > phi);
1276      //Energy and scattering angle (primary electron);
1277      kineticEnergy1 = kinEnergy*(1.0-rk);
1278      cosThetaPrimary = std::sqrt(kineticEnergy1*rb/(kinEnergy*(rb-(rk*kinEnergy))));
1279      //Energy and scattering angle of the delta ray
1280      energySecondary = kinEnergy-kineticEnergy1-UII;
1281      cosThetaSecondary = std::sqrt(rk*kinEnergy*rb/(kinEnergy*(rk*kinEnergy+2.0*electron_mass_c2)));
1282    }     
1283  else
1284    {
1285      G4String excep = "G4PenelopeIonisationModel - Error in the calculation of the final state";
1286      G4Exception(excep);
1287    }
1288
1289  delete qm;
1290  delete cumulHardCS;
1291  delete typeOfInteraction;
1292  delete nbOfLevel;
1293
1294  return;
1295}
1296
1297//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1298
1299G4double
1300G4PenelopeIonisationModel::CalculateCrossSectionsRatio(G4double kinEnergy,
1301                                                       G4double cutoffEnergy,
1302                                                       G4int Z, G4double electronVolumeDensity,
1303                                                       const G4ParticleDefinition* theParticle)
1304{
1305  //Constants
1306  G4double gamma = 1.0+kinEnergy/electron_mass_c2;
1307  G4double gamma2 = gamma*gamma;
1308  G4double beta2 = (gamma2-1.0)/gamma2;
1309  G4double constant = pi*classic_electr_radius*classic_electr_radius*2.0*electron_mass_c2/beta2;
1310  G4double delta = CalculateDeltaFermi(kinEnergy,Z,electronVolumeDensity);
1311  G4int nbOsc = (G4int) resonanceEnergy->find(Z)->second->size();
1312  G4double softCS = 0.0;
1313  G4double hardCS = 0.0;
1314  for (G4int i=0;i<nbOsc;i++){
1315    G4double resEnergy = (*(resonanceEnergy->find(Z)->second))[i];
1316    std::pair<G4double,G4double> SoftAndHardXS(0.,0.);
1317    if (theParticle == G4Electron::Electron())
1318      SoftAndHardXS = CrossSectionsRatioForElectrons(kinEnergy,resEnergy,delta,cutoffEnergy);
1319    else if (theParticle == G4Positron::Positron())
1320      SoftAndHardXS = CrossSectionsRatioForPositrons(kinEnergy,resEnergy,delta,cutoffEnergy);     
1321    G4double occupNb = (*(occupationNumber->find(Z)->second))[i];
1322    softCS += occupNb*constant*SoftAndHardXS.first;
1323    hardCS += occupNb*constant*SoftAndHardXS.second;
1324  }
1325  G4double ratio = 0.0;
1326 
1327  if (softCS+hardCS) ratio = (hardCS)/(softCS+hardCS);
1328  return ratio;
1329}
1330
1331//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1332
1333std::pair<G4double,G4double> 
1334G4PenelopeIonisationModel::CrossSectionsRatioForElectrons(G4double kineticEnergy,
1335                                                          G4double resEnergy,
1336                                                          G4double densityCorrection,
1337                                                          G4double cutoffEnergy)
1338{
1339  std::pair<G4double,G4double> theResult(0.,0.);
1340  if (kineticEnergy < resEnergy) return theResult;
1341
1342  //Calculate constants
1343  G4double gamma = 1.0+kineticEnergy/electron_mass_c2;
1344  G4double gamma2 = gamma*gamma;
1345  G4double beta2 = (gamma2-1.0)/gamma2;
1346  G4double cps = kineticEnergy*(kineticEnergy+2.0*electron_mass_c2);
1347  G4double amol = (kineticEnergy/(kineticEnergy+electron_mass_c2)) * (kineticEnergy/(kineticEnergy+electron_mass_c2)) ;
1348  G4double hardCont = 0.0;
1349  G4double softCont = 0.0;
1350   
1351  //Distant interactions
1352  G4double cp1s = (kineticEnergy-resEnergy)*(kineticEnergy-resEnergy+2.0*electron_mass_c2);
1353  G4double cp1 = std::sqrt(cp1s);
1354  G4double cp = std::sqrt(cps);
1355  G4double sdLong=0.0, sdTrans = 0.0, sdDist=0.0;
1356
1357  //Distant longitudinal interactions
1358  G4double qm = 0.0;
1359
1360  if (resEnergy > kineticEnergy*(1e-6))
1361    {
1362      qm = std::sqrt((cp-cp1)*(cp-cp1)+(electron_mass_c2*electron_mass_c2))-electron_mass_c2;
1363    }
1364  else
1365    {
1366      qm = resEnergy*resEnergy/(beta2*2.0*electron_mass_c2);
1367      qm = qm*(1.0-0.5*qm/electron_mass_c2);
1368    }
1369
1370  if (qm < resEnergy)
1371    {
1372      sdLong = std::log(resEnergy*(qm+2.0*electron_mass_c2)/(qm*(resEnergy+2.0*electron_mass_c2)));
1373    }
1374  else
1375    {
1376      sdLong = 0.0;
1377    }
1378 
1379  if (sdLong > 0) {
1380    sdTrans = std::max(std::log(gamma2)-beta2-densityCorrection,0.0);
1381    sdDist = sdTrans + sdLong;
1382    if (cutoffEnergy > resEnergy) 
1383      {
1384        softCont = sdDist/resEnergy;
1385      }
1386    else
1387      {
1388        hardCont = sdDist/resEnergy;
1389      }
1390  }
1391
1392  // Close collisions (Moeller's cross section)
1393  G4double wl = std::max(cutoffEnergy,resEnergy);
1394  G4double wu = 0.5*kineticEnergy;
1395 
1396  if (wl < (wu-1*eV)) 
1397    { 
1398      hardCont += (1.0/(kineticEnergy-wu))-(1.0/(kineticEnergy-wl))
1399        - (1.0/wu)+(1.0/wl)
1400        + (1.0-amol)*std::log(((kineticEnergy-wu)*wl)/((kineticEnergy-wl)*wu))/kineticEnergy
1401        + amol*(wu-wl)/(kineticEnergy*kineticEnergy);
1402      wu=wl;
1403    }
1404
1405  wl = resEnergy;
1406  if (wl > (wu-1*eV)) 
1407    {
1408      theResult.first = softCont;
1409      theResult.second = hardCont;
1410      return theResult;
1411    }
1412  softCont += (1.0/(kineticEnergy-wu))-(1.0/(kineticEnergy-wl))
1413        - (1.0/wu)+(1.0/wl)
1414        + (1.0-amol)*std::log(((kineticEnergy-wu)*wl)/((kineticEnergy-wl)*wu))/kineticEnergy
1415        + amol*(wu-wl)/(kineticEnergy*kineticEnergy);
1416  theResult.first = softCont;
1417  theResult.second = hardCont;
1418  return theResult;
1419}
1420
1421
1422//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1423
1424std::pair<G4double,G4double> 
1425G4PenelopeIonisationModel::CrossSectionsRatioForPositrons(G4double kineticEnergy,
1426                                                          G4double resEnergy,
1427                                                          G4double densityCorrection,
1428                                                          G4double cutoffEnergy)
1429{
1430
1431  std::pair<G4double,G4double> theResult(0.,0.);
1432  if (kineticEnergy < resEnergy) return theResult;
1433
1434  //Calculate constants
1435  G4double gamma = 1.0+kineticEnergy/electron_mass_c2;
1436  G4double gamma2 = gamma*gamma;
1437  G4double beta2 = (gamma2-1.0)/gamma2;
1438  G4double cps = kineticEnergy*(kineticEnergy+2.0*electron_mass_c2);
1439  G4double amol = (kineticEnergy/(kineticEnergy+electron_mass_c2)) * (kineticEnergy/(kineticEnergy+electron_mass_c2)) ;
1440  G4double help = (gamma+1.0)*(gamma+1.0);
1441  G4double bha1 = amol*(2.0*help-1.0)/(gamma2-1.0);
1442  G4double bha2 = amol*(3.0+1.0/help);
1443  G4double bha3 = amol*2.0*gamma*(gamma-1.0)/help;
1444  G4double bha4 = amol*(gamma-1.0)*(gamma-1.0)/help;
1445  G4double hardCont = 0.0;
1446  G4double softCont = 0.0;
1447
1448  //Distant interactions
1449  G4double cp1s = (kineticEnergy-resEnergy)*(kineticEnergy-resEnergy+2.0*electron_mass_c2);
1450  G4double cp1 = std::sqrt(cp1s);
1451  G4double cp = std::sqrt(cps);
1452  G4double sdLong=0.0, sdTrans = 0.0, sdDist=0.0;
1453
1454  //Distant longitudinal interactions
1455  G4double qm = 0.0;
1456
1457  if (resEnergy > kineticEnergy*(1e-6))
1458    {
1459      qm = std::sqrt((cp-cp1)*(cp-cp1)+(electron_mass_c2*electron_mass_c2))-electron_mass_c2;
1460    }
1461  else
1462    {
1463      qm = resEnergy*resEnergy/(beta2*2.0*electron_mass_c2);
1464      qm = qm*(1.0-0.5*qm/electron_mass_c2);
1465    }
1466
1467  if (qm < resEnergy)
1468    {
1469      sdLong = std::log(resEnergy*(qm+2.0*electron_mass_c2)/(qm*(resEnergy+2.0*electron_mass_c2)));
1470    }
1471  else
1472    {
1473      sdLong = 0.0;
1474    }
1475 
1476  if (sdLong > 0) {
1477    sdTrans = std::max(std::log(gamma2)-beta2-densityCorrection,0.0);
1478    sdDist = sdTrans + sdLong;
1479    if (cutoffEnergy > resEnergy) 
1480      {
1481        softCont = sdDist/resEnergy;
1482      }
1483    else
1484      {
1485        hardCont = sdDist/resEnergy;
1486      }
1487  }
1488
1489
1490  // Close collisions (Bhabha's cross section)
1491  G4double wl = std::max(cutoffEnergy,resEnergy);
1492  G4double wu = kineticEnergy;
1493 
1494  if (wl < (wu-1*eV)) {
1495    hardCont += (1.0/wl)-(1.0/wu)-bha1*std::log(wu/wl)/kineticEnergy
1496      + bha2*(wu-wl)/(kineticEnergy*kineticEnergy) 
1497      -bha3*((wu*wu)-(wl*wl))/(2.0*kineticEnergy*kineticEnergy*kineticEnergy)
1498      + bha4*((wu*wu*wu)-(wl*wl*wl))/(3.0*kineticEnergy*kineticEnergy*kineticEnergy*kineticEnergy);
1499    wu=wl;
1500  }
1501  wl = resEnergy;
1502  if (wl > (wu-1*eV)) 
1503    { 
1504      theResult.first = softCont;
1505      theResult.second = hardCont;
1506      return theResult;
1507    }
1508  softCont += (1.0/wl)-(1.0/wu)-bha1*std::log(wu/wl)/kineticEnergy
1509    + bha2*(wu-wl)/(kineticEnergy*kineticEnergy) 
1510    -bha3*((wu*wu)-(wl*wl))/(2.0*kineticEnergy*kineticEnergy*kineticEnergy)
1511    + bha4*((wu*wu*wu)-(wl*wl*wl))/(3.0*kineticEnergy*kineticEnergy*kineticEnergy*kineticEnergy);
1512 
1513
1514  theResult.first = softCont;
1515  theResult.second = hardCont;
1516  return theResult;
1517
1518}
1519
1520G4double G4PenelopeIonisationModel::ComputeStoppingPowerForElectrons(G4double kinEnergy,
1521                                                                     G4double cutEnergy,
1522                                                                     G4double deltaFermi,
1523                                                                     G4double resEnergy)
1524{
1525   //Calculate constants
1526  G4double gamma = 1.0+kinEnergy/electron_mass_c2;
1527  G4double gamma2 = gamma*gamma;
1528  G4double beta2 = (gamma2-1.0)/gamma2;
1529  G4double cps = kinEnergy*(kinEnergy+2.0*electron_mass_c2);
1530  G4double amol = (gamma-1.0)*(gamma-1.0)/gamma2;
1531  G4double sPower = 0.0;
1532  if (kinEnergy < resEnergy) return sPower;
1533
1534  //Distant interactions
1535  G4double cp1s = (kinEnergy-resEnergy)*(kinEnergy-resEnergy+2.0*electron_mass_c2);
1536  G4double cp1 = std::sqrt(cp1s);
1537  G4double cp = std::sqrt(cps);
1538  G4double sdLong=0.0, sdTrans = 0.0, sdDist=0.0;
1539
1540  //Distant longitudinal interactions
1541  G4double qm = 0.0;
1542
1543  if (resEnergy > kinEnergy*(1e-6))
1544    {
1545      qm = std::sqrt((cp-cp1)*(cp-cp1)+(electron_mass_c2*electron_mass_c2))-electron_mass_c2;
1546    }
1547  else
1548    {
1549      qm = resEnergy*resEnergy/(beta2*2.0*electron_mass_c2);
1550      qm = qm*(1.0-0.5*qm/electron_mass_c2);
1551    }
1552
1553  if (qm < resEnergy)
1554    sdLong = std::log(resEnergy*(qm+2.0*electron_mass_c2)/(qm*(resEnergy+2.0*electron_mass_c2)));
1555  else
1556    sdLong = 0.0;
1557 
1558  if (sdLong > 0) {
1559    sdTrans = std::max(std::log(gamma2)-beta2-deltaFermi,0.0);
1560    sdDist = sdTrans + sdLong;
1561    if (cutEnergy > resEnergy) sPower = sdDist;
1562  }
1563
1564
1565  // Close collisions (Moeller's cross section)
1566  G4double wl = std::max(cutEnergy,resEnergy);
1567  G4double wu = 0.5*kinEnergy;
1568 
1569  if (wl < (wu-1*eV)) wu=wl;
1570  wl = resEnergy;
1571  if (wl > (wu-1*eV)) return sPower;
1572  sPower += std::log(wu/wl)+(kinEnergy/(kinEnergy-wu))-(kinEnergy/(kinEnergy-wl))
1573    + (2.0 - amol)*std::log((kinEnergy-wu)/(kinEnergy-wl))
1574    + amol*((wu*wu)-(wl*wl))/(2.0*kinEnergy*kinEnergy);
1575  return sPower;
1576}
1577
1578
1579//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1580
1581G4double G4PenelopeIonisationModel::ComputeStoppingPowerForPositrons(G4double kinEnergy,
1582                                                                     G4double cutEnergy,
1583                                                                     G4double deltaFermi,
1584                                                                     G4double resEnergy)
1585{
1586 //Calculate constants
1587  G4double gamma = 1.0+kinEnergy/electron_mass_c2;
1588  G4double gamma2 = gamma*gamma;
1589  G4double beta2 = (gamma2-1.0)/gamma2;
1590  G4double cps = kinEnergy*(kinEnergy+2.0*electron_mass_c2);
1591  G4double amol = (kinEnergy/(kinEnergy+electron_mass_c2)) * (kinEnergy/(kinEnergy+electron_mass_c2));
1592  G4double help = (gamma+1.0)*(gamma+1.0);
1593  G4double bha1 = amol*(2.0*help-1.0)/(gamma2-1.0);
1594  G4double bha2 = amol*(3.0+1.0/help);
1595  G4double bha3 = amol*2.0*gamma*(gamma-1.0)/help;
1596  G4double bha4 = amol*(gamma-1.0)*(gamma-1.0)/help;
1597
1598  G4double sPower = 0.0;
1599  if (kinEnergy < resEnergy) return sPower;
1600
1601  //Distant interactions
1602  G4double cp1s = (kinEnergy-resEnergy)*(kinEnergy-resEnergy+2.0*electron_mass_c2);
1603  G4double cp1 = std::sqrt(cp1s);
1604  G4double cp = std::sqrt(cps);
1605  G4double sdLong=0.0, sdTrans = 0.0, sdDist=0.0;
1606
1607  //Distant longitudinal interactions
1608  G4double qm = 0.0;
1609
1610  if (resEnergy > kinEnergy*(1e-6))
1611    {
1612      qm = std::sqrt((cp-cp1)*(cp-cp1)+(electron_mass_c2*electron_mass_c2))-electron_mass_c2;
1613    }
1614  else
1615    {
1616      qm = resEnergy*resEnergy/(beta2*2.0*electron_mass_c2);
1617      qm = qm*(1.0-0.5*qm/electron_mass_c2);
1618    }
1619
1620  if (qm < resEnergy)
1621    sdLong = std::log(resEnergy*(qm+2.0*electron_mass_c2)/(qm*(resEnergy+2.0*electron_mass_c2)));
1622  else
1623    sdLong = 0.0;
1624   
1625  if (sdLong > 0) {
1626    sdTrans = std::max(std::log(gamma2)-beta2-deltaFermi,0.0);
1627    sdDist = sdTrans + sdLong;
1628    if (cutEnergy > resEnergy) sPower = sdDist;
1629  }
1630
1631
1632  // Close collisions (Bhabha's cross section)
1633  G4double wl = std::max(cutEnergy,resEnergy);
1634  G4double wu = kinEnergy;
1635 
1636  if (wl < (wu-1*eV)) wu=wl;
1637  wl = resEnergy;
1638  if (wl > (wu-1*eV)) return sPower;
1639  sPower += std::log(wu/wl)-bha1*(wu-wl)/kinEnergy
1640    + bha2*((wu*wu)-(wl*wl))/(2.0*kinEnergy*kinEnergy)
1641    - bha3*((wu*wu*wu)-(wl*wl*wl))/(3.0*kinEnergy*kinEnergy*kinEnergy)
1642    + bha4*((wu*wu*wu*wu)-(wl*wl*wl*wl))/(4.0*kinEnergy*kinEnergy*kinEnergy*kinEnergy);
1643  return sPower;
1644}
1645
1646//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...
1647
1648/* Notice: the methods here above are only temporary. They will become obsolete in a while */
1649
1650#include "G4VDataSetAlgorithm.hh"
1651#include "G4LinLogLogInterpolation.hh"
1652#include "G4CompositeEMDataSet.hh"
1653#include "G4EMDataSet.hh"
1654
1655std::vector<G4VEMDataSet*>* 
1656G4PenelopeIonisationModel::BuildCrossSectionTable(const G4ParticleDefinition* theParticle)
1657{
1658  std::vector<G4VEMDataSet*>* set = new std::vector<G4VEMDataSet*>;
1659
1660  size_t nOfBins = 200;
1661  G4PhysicsLogVector* theLogVector = new G4PhysicsLogVector(LowEnergyLimit(),
1662                                                            HighEnergyLimit(), 
1663                                                            nOfBins);
1664  G4DataVector* energies;
1665  G4DataVector* cs;
1666 
1667  const G4ProductionCutsTable* theCoupleTable=
1668        G4ProductionCutsTable::GetProductionCutsTable();
1669  size_t numOfCouples = theCoupleTable->GetTableSize();
1670
1671
1672  for (size_t m=0; m<numOfCouples; m++) 
1673    {
1674      const G4MaterialCutsCouple* couple = theCoupleTable->GetMaterialCutsCouple(m);
1675      const G4Material* material= couple->GetMaterial();
1676      const G4ElementVector* elementVector = material->GetElementVector();
1677      const G4double* nAtomsPerVolume = material->GetAtomicNumDensityVector();
1678      G4double electronVolumeDensity = 
1679        material->GetTotNbOfElectPerVolume();  //electron density
1680      G4int nElements = material->GetNumberOfElements();
1681 
1682      G4double tcut  = (*(theCoupleTable->GetEnergyCutsVector(1)))[couple->GetIndex()];
1683
1684      G4VDataSetAlgorithm* algo =  new G4LinLogLogInterpolation();
1685
1686      G4VEMDataSet* setForMat = new G4CompositeEMDataSet(algo,1.,1.);
1687
1688      for (G4int i=0; i<nElements; i++) 
1689        {
1690          G4int iZ = (G4int) (*elementVector)[i]->GetZ();
1691          energies = new G4DataVector;
1692          cs = new G4DataVector;
1693          G4double density = nAtomsPerVolume[i];         
1694          for (size_t bin=0; bin<nOfBins; bin++) 
1695            {
1696              G4double e = theLogVector->GetLowEdgeEnergy(bin);
1697              energies->push_back(e);
1698              G4double value = 0.0;           
1699              if(e > tcut) 
1700                {
1701                  G4double ratio = CalculateCrossSectionsRatio(e,tcut,iZ,
1702                                                               electronVolumeDensity,
1703                                                               theParticle);
1704                  value = crossSectionHandler->FindValue(iZ,e)*ratio*density;
1705                }
1706              cs->push_back(value);
1707            }
1708      G4VDataSetAlgorithm* algo1 = algo->Clone();
1709      G4VEMDataSet* elSet = new G4EMDataSet(i,energies,cs,algo1,1.,1.);
1710      setForMat->AddComponent(elSet);
1711    }
1712    set->push_back(setForMat);
1713  }
1714  return set;
1715}
1716
1717//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...
1718
1719G4int G4PenelopeIonisationModel::SampleRandomAtom(const G4MaterialCutsCouple* couple,
1720                                                     G4double e) const
1721{
1722  // Select randomly an element within the material, according to the weight
1723  // determined by the cross sections in the data set
1724
1725  const G4Material* material = couple->GetMaterial();
1726  G4int nElements = material->GetNumberOfElements();
1727
1728  // Special case: the material consists of one element
1729  if (nElements == 1)
1730    {
1731      G4int Z = (G4int) material->GetZ();
1732      return Z;
1733    }
1734
1735  // Composite material
1736  const G4ElementVector* elementVector = material->GetElementVector();
1737  size_t materialIndex = couple->GetIndex();
1738
1739  G4VEMDataSet* materialSet = (*theXSTable)[materialIndex];
1740  G4double materialCrossSection0 = 0.0;
1741  G4DataVector cross;
1742  cross.clear();
1743  for ( G4int i=0; i < nElements; i++ )
1744    {
1745      G4double cr = materialSet->GetComponent(i)->FindValue(e);
1746      materialCrossSection0 += cr;
1747      cross.push_back(materialCrossSection0);
1748    }
1749
1750  G4double random = G4UniformRand() * materialCrossSection0;
1751
1752  for (G4int k=0 ; k < nElements ; k++ )
1753    {
1754      if (random <= cross[k]) return (G4int) (*elementVector)[k]->GetZ();
1755    }
1756  // It should never get here
1757  return 0;
1758}
1759
1760
1761//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1762
1763void G4PenelopeIonisationModel::ActivateAuger(G4bool augerbool)
1764{
1765  if (!DeexcitationFlag() && augerbool)
1766    {
1767      G4cout << "WARNING - G4PenelopeIonisationModel" << G4endl;
1768      G4cout << "The use of the Atomic Deexcitation Manager is set to false " << G4endl;
1769      G4cout << "Therefore, Auger electrons will be not generated anyway" << G4endl;
1770    }
1771  deexcitationManager.ActivateAugerElectronProduction(augerbool);
1772  if (verboseLevel > 1)
1773    G4cout << "Auger production set to " << augerbool << G4endl;
1774}
1775
1776//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
Note: See TracBrowser for help on using the repository browser.