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

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

update to geant4.9.2

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