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

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

geant4 tag 9.4

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