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

Last change on this file since 1168 was 1055, checked in by garnier, 15 years ago

maj sur la beta de geant 4.9.3

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