source: trunk/source/processes/electromagnetic/lowenergy/src/G4PenelopeIonisation.cc @ 1347

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

geant4 tag 9.4

File size: 48.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: G4PenelopeIonisation.cc,v 1.22 2009/06/11 15:47:08 mantero Exp $
27// GEANT4 tag $Name: geant4-09-04-ref-00 $
28//
29// --------------------------------------------------------------
30//
31// File name:     G4PenelopeIonisation
32//
33// Author:        Luciano Pandola
34//
35// Creation date: March 2003
36//
37// Modifications:
38//
39// 25.03.03 L.Pandola           First implementation
40// 03.06.03 L.Pandola           Added continuous part
41// 30.06.03 L.Pandola           Added positrons 
42// 01.07.03 L.Pandola           Changed cross section files for e- and e+   
43//                              Interface with PenelopeCrossSectionHandler
44// 18.01.04 M.Mendenhall (Vanderbilt University) [bug report 568]
45//                              Changed returns in CalculateDiscreteForElectrons()
46//                              to eliminate leaks
47// 20.01.04 L.Pandola           Changed returns in CalculateDiscreteForPositrons()
48//                              to eliminate the same bug
49// 10.03.04 L.Pandola           Bug fixed with reference system of delta rays
50// 17.03.04 L.Pandola           Removed unnecessary calls to std::pow(a,b)
51// 18.03.04 L.Pandola           Bug fixed in the destructor
52// 01.06.04 L.Pandola           StopButAlive for positrons on PostStepDoIt
53// 10.03.05 L.Pandola           Fix of bug report 729. The solution works but it is
54//                              quite un-elegant. Something better to be found.
55// --------------------------------------------------------------
56
57#include "G4PenelopeIonisation.hh"
58#include "G4PenelopeCrossSectionHandler.hh"
59#include "G4AtomicTransitionManager.hh"
60#include "G4AtomicShell.hh"
61#include "G4eIonisationSpectrum.hh"
62#include "G4VDataSetAlgorithm.hh"
63#include "G4SemiLogInterpolation.hh"
64#include "G4LogLogInterpolation.hh"
65#include "G4EMDataSet.hh"
66#include "G4VEMDataSet.hh"
67#include "G4CompositeEMDataSet.hh"
68#include "G4EnergyLossTables.hh"
69#include "G4UnitsTable.hh"
70#include "G4Electron.hh"
71#include "G4Gamma.hh"
72#include "G4Positron.hh"
73#include "G4ProductionCutsTable.hh"
74#include "G4ProcessManager.hh"
75
76G4PenelopeIonisation::G4PenelopeIonisation(const G4String& nam)
77  : G4eLowEnergyLoss(nam), 
78    crossSectionHandler(0),
79    theMeanFreePath(0),
80    kineticEnergy1(0.0),
81    cosThetaPrimary(1.0),
82    energySecondary(0.0),
83    cosThetaSecondary(0.0),
84    iOsc(-1)
85{
86  cutForPhotons = 250.0*eV;
87  cutForElectrons = 250.0*eV;
88  verboseLevel = 0;
89  ionizationEnergy = new std::map<G4int,G4DataVector*>;
90  resonanceEnergy  = new std::map<G4int,G4DataVector*>;
91  occupationNumber = new std::map<G4int,G4DataVector*>;
92  shellFlag = new std::map<G4int,G4DataVector*>;
93  ReadData(); //Read data from file
94 
95   G4cout << G4endl;
96   G4cout << "*******************************************************************************" << G4endl;
97   G4cout << "*******************************************************************************" << G4endl;
98   G4cout << "   The class G4PenelopeIonisation is NOT SUPPORTED ANYMORE. " << G4endl;
99   G4cout << "   It will be REMOVED with the next major release of Geant4. " << G4endl;
100   G4cout << "   Please consult: https://twiki.cern.ch/twiki/bin/view/Geant4/LoweProcesses" << G4endl;
101   G4cout << "*******************************************************************************" << G4endl;
102   G4cout << "*******************************************************************************" << G4endl;
103   G4cout << G4endl;
104
105}
106
107
108G4PenelopeIonisation::~G4PenelopeIonisation()
109{
110  delete crossSectionHandler;
111  delete theMeanFreePath;
112  for (G4int Z=1;Z<100;Z++)
113    {
114      if (ionizationEnergy->count(Z)) delete (ionizationEnergy->find(Z)->second);
115      if (resonanceEnergy->count(Z)) delete (resonanceEnergy->find(Z)->second);
116      if (occupationNumber->count(Z)) delete (occupationNumber->find(Z)->second);
117      if (shellFlag->count(Z)) delete (shellFlag->find(Z)->second);
118    }
119  delete ionizationEnergy;
120  delete resonanceEnergy;
121  delete occupationNumber;
122  delete shellFlag;
123}
124
125
126void G4PenelopeIonisation::BuildPhysicsTable(const G4ParticleDefinition& aParticleType) 
127{
128  if(verboseLevel > 0) {
129    G4cout << "G4PenelopeIonisation::BuildPhysicsTable start" << G4endl;
130      }
131
132  cutForDelta.clear();
133
134  // Create and fill G4CrossSectionHandler once
135  if ( crossSectionHandler != 0 ) delete crossSectionHandler;
136  G4VDataSetAlgorithm* interpolation = new G4LogLogInterpolation();
137  G4double lowKineticEnergy  = GetLowerBoundEloss();
138  G4double highKineticEnergy = GetUpperBoundEloss();
139  G4int    totBin = GetNbinEloss();
140  crossSectionHandler = new G4PenelopeCrossSectionHandler(this,aParticleType,
141                                                          interpolation,
142                                                          lowKineticEnergy,
143                                                          highKineticEnergy,
144                                                          totBin);
145
146  if (&aParticleType == G4Electron::Electron()) 
147    {
148      crossSectionHandler->LoadData("penelope/ion-cs-el-");
149    }
150  else if (&aParticleType == G4Positron::Positron())
151    {
152      crossSectionHandler->LoadData("penelope/ion-cs-po-");
153    }
154
155  if (verboseLevel > 0) {
156    G4cout << GetProcessName() << " is created." << G4endl;
157  }
158
159  // Build loss table for Ionisation
160
161  BuildLossTable(aParticleType);
162
163  if(verboseLevel > 0) {
164    G4cout << "The loss table is built"
165           << G4endl;
166      }
167
168  if (&aParticleType==G4Electron::Electron()) {
169
170    RecorderOfElectronProcess[CounterOfElectronProcess] = (*this).theLossTable;
171    CounterOfElectronProcess++;
172    PrintInfoDefinition(); 
173
174  } else {
175
176    RecorderOfPositronProcess[CounterOfPositronProcess] = (*this).theLossTable;
177    CounterOfPositronProcess++;
178    PrintInfoDefinition();
179  }
180
181  // Build mean free path data using cut values
182
183  if( theMeanFreePath ) delete theMeanFreePath;
184  theMeanFreePath = crossSectionHandler->
185                    BuildMeanFreePathForMaterials(&cutForDelta);
186
187  if(verboseLevel > 0) {
188    G4cout << "The MeanFreePath table is built"
189           << G4endl;
190    if(verboseLevel > 1) theMeanFreePath->PrintData();
191  }
192
193  // Build common DEDX table for all ionisation processes
194 
195  BuildDEDXTable(aParticleType);
196
197  if (verboseLevel > 0) {
198    G4cout << "G4PenelopeIonisation::BuildPhysicsTable end"
199           << G4endl;
200  }
201}
202
203
204void G4PenelopeIonisation::BuildLossTable(
205                                          const G4ParticleDefinition& aParticleType)
206{
207  // Build table for energy loss due to soft brems
208  // the tables are built for *MATERIALS* binning is taken from LowEnergyLoss
209
210  G4double lowKineticEnergy  = GetLowerBoundEloss();
211  G4double highKineticEnergy = GetUpperBoundEloss();
212  size_t   totBin = GetNbinEloss();
213 
214  //  create table
215
216  if (theLossTable) { 
217      theLossTable->clearAndDestroy();
218      delete theLossTable;
219  }
220  const G4ProductionCutsTable* theCoupleTable=
221        G4ProductionCutsTable::GetProductionCutsTable();
222  size_t numOfCouples = theCoupleTable->GetTableSize();
223  theLossTable = new G4PhysicsTable(numOfCouples);
224
225  // Clean up the vector of cuts
226
227  cutForDelta.clear();
228
229  // Loop for materials
230
231  for (size_t m=0; m<numOfCouples; m++) {
232
233    // create physics vector and fill it
234    G4PhysicsLogVector* aVector = new G4PhysicsLogVector(lowKineticEnergy,
235                                                         highKineticEnergy,
236                                                         totBin);
237
238    // get material parameters needed for the energy loss calculation
239    const G4MaterialCutsCouple* couple = theCoupleTable->GetMaterialCutsCouple(m);
240    const G4Material* material= couple->GetMaterial();
241
242    // the cut cannot be below lowest limit
243    G4double tCut = 0.0;
244    tCut = (*(theCoupleTable->GetEnergyCutsVector(1)))[m];
245    tCut = std::min(tCut,highKineticEnergy);
246
247    cutForDelta.push_back(tCut);
248
249    const G4ElementVector* theElementVector = material->GetElementVector();
250    size_t NumberOfElements = material->GetNumberOfElements() ;
251    const G4double* theAtomicNumDensityVector =
252                    material->GetAtomicNumDensityVector();
253    const G4double electronVolumeDensity = 
254      material->GetTotNbOfElectPerVolume();  //electron density
255    if(verboseLevel > 0) {
256      G4cout << "Energy loss for material # " << m
257             << " tCut(keV)= " << tCut/keV
258             << G4endl;
259      }
260
261    // now comes the loop for the kinetic energy values
262    for (size_t i = 0; i<totBin; i++) {
263
264      G4double lowEdgeEnergy = aVector->GetLowEdgeEnergy(i);
265      G4double ionloss = 0.;
266
267      // loop for elements in the material
268      for (size_t iel=0; iel<NumberOfElements; iel++ ) {
269
270        G4int Z = (G4int)((*theElementVector)[iel]->GetZ());
271        ionloss   += 
272          CalculateContinuous(lowEdgeEnergy,tCut,Z,electronVolumeDensity,
273                              aParticleType) * theAtomicNumDensityVector[iel];
274
275        if(verboseLevel > 1) {
276          G4cout << "Z= " << Z
277                 << " E(keV)= " << lowEdgeEnergy/keV
278                 << " loss= " << ionloss
279                 << " rho= " << theAtomicNumDensityVector[iel]
280                 << G4endl;
281        }
282      }
283      aVector->PutValue(i,ionloss);
284    }
285    theLossTable->insert(aVector);
286  }
287}
288
289
290G4VParticleChange* G4PenelopeIonisation::PostStepDoIt(const G4Track& track,
291                                                       const G4Step&  step)
292{
293  aParticleChange.Initialize(track);
294
295  const G4MaterialCutsCouple* couple = track.GetMaterialCutsCouple();
296  const G4DynamicParticle* incidentElectron = track.GetDynamicParticle();
297  const G4Material* material = couple->GetMaterial();
298  const G4double electronVolumeDensity = 
299    material->GetTotNbOfElectPerVolume();  //electron density
300  const G4ParticleDefinition* aParticleType = track.GetDefinition();
301  G4double kineticEnergy0 = incidentElectron->GetKineticEnergy();
302  G4ParticleMomentum electronDirection0 = incidentElectron->GetMomentumDirection();
303
304  //Inizialisation of variables
305  kineticEnergy1=kineticEnergy0;
306  cosThetaPrimary=1.0;
307  energySecondary=0.0;
308  cosThetaSecondary=1.0;
309
310  G4int Z = crossSectionHandler->SelectRandomAtom(couple, kineticEnergy0);
311  G4int    index  = couple->GetIndex();
312  G4double tCut   = cutForDelta[index];
313
314  if (aParticleType==G4Electron::Electron()){
315    CalculateDiscreteForElectrons(kineticEnergy0,tCut,Z,electronVolumeDensity);
316  }
317  else if (aParticleType==G4Positron::Positron()){
318    CalculateDiscreteForPositrons(kineticEnergy0,tCut,Z,electronVolumeDensity);
319  }
320  // the method CalculateDiscrete() sets the private variables:
321  // kineticEnergy1 = energy of the primary electron after the interaction
322  // cosThetaPrimary = std::cos(theta) of the primary after the interaction
323  // energySecondary = energy of the secondary electron
324  // cosThetaSecondary = std::cos(theta) of the secondary
325 
326  if(energySecondary == 0.0)
327    {   
328      return G4VContinuousDiscreteProcess::PostStepDoIt(track, step);
329    }
330
331  //Update the primary particle
332  G4double sint = std::sqrt(1. - cosThetaPrimary*cosThetaPrimary);
333  G4double phi  = twopi * G4UniformRand();
334  G4double dirx = sint * std::cos(phi);
335  G4double diry = sint * std::sin(phi);
336  G4double dirz = cosThetaPrimary;
337
338  G4ThreeVector electronDirection1(dirx,diry,dirz);
339  electronDirection1.rotateUz(electronDirection0);
340  aParticleChange.ProposeMomentumDirection(electronDirection1) ;
341
342  if (kineticEnergy1 > 0.)
343    {
344      aParticleChange.ProposeEnergy(kineticEnergy1) ;
345    }
346  else
347    {   
348      aParticleChange.ProposeEnergy(0.) ;
349      if (aParticleType->GetProcessManager()->GetAtRestProcessVector()->size()) 
350        //In this case there is at least one AtRest process
351        {
352          aParticleChange.ProposeTrackStatus(fStopButAlive);
353        }
354      else
355        {
356          aParticleChange.ProposeTrackStatus(fStopAndKill);
357        }
358    }
359
360  //Generate the delta day
361  G4int iosc2 = 0;
362  G4double ioniEnergy = 0.0;
363  if (iOsc > 0) {
364    ioniEnergy=(*(ionizationEnergy->find(Z)->second))[iOsc];
365    iosc2 = (ionizationEnergy->find(Z)->second->size()) - iOsc; //they are in reversed order
366  }
367
368  const G4AtomicTransitionManager* transitionManager = G4AtomicTransitionManager::Instance();
369  G4double bindingEnergy = 0.0;
370  G4int shellId = 0;
371  if (iOsc > 0){
372    const G4AtomicShell* shell = transitionManager->Shell(Z,iosc2-1); // Modified by Alf
373    bindingEnergy = shell->BindingEnergy();
374    shellId = shell->ShellId();
375  }
376
377  G4double ionEnergy = bindingEnergy; //energy spent to ionise the atom according to G4dabatase
378  G4double eKineticEnergy = energySecondary;
379
380  //This is an awful thing: Penelope generates the fluorescence only for L and K shells
381  //(i.e. Osc = 1 --> 4). For high-Z, the other shells can be quite relevant. In this case
382  //one MUST ensure ''by hand'' the energy conservation. Then there is the other problem that
383  //the fluorescence database of Penelope doesn not match that of Geant4.
384
385  G4double energyBalance = kineticEnergy0 - kineticEnergy1 - energySecondary; //Penelope Balance
386
387  if (std::abs(energyBalance) < 1*eV)
388    {
389      //in this case Penelope didn't subtract the fluorescence energy: do here by hand
390      eKineticEnergy = energySecondary - bindingEnergy;
391    }
392  else 
393    {
394      //Penelope subtracted the fluorescence, but one has to match the databases
395      eKineticEnergy = energySecondary+ioniEnergy-bindingEnergy;
396    }
397 
398  //Now generates the various secondaries
399  size_t nTotPhotons=0;
400  G4int nPhotons=0;
401
402  const G4ProductionCutsTable* theCoupleTable=
403    G4ProductionCutsTable::GetProductionCutsTable();
404  size_t indx = couple->GetIndex();
405  G4double cutg = (*(theCoupleTable->GetEnergyCutsVector(0)))[indx];
406  cutg = std::min(cutForPhotons,cutg);
407
408  G4double cute = (*(theCoupleTable->GetEnergyCutsVector(1)))[indx];
409  cute = std::min(cutForPhotons,cute);
410 
411  std::vector<G4DynamicParticle*>* photonVector=0;
412  G4DynamicParticle* aPhoton;
413  if (Z>5 && (ionEnergy > cutg || ionEnergy > cute))
414    {
415      photonVector = deexcitationManager.GenerateParticles(Z,shellId);
416      nTotPhotons = photonVector->size();
417      for (size_t k=0;k<nTotPhotons;k++){
418        aPhoton = (*photonVector)[k];
419        if (aPhoton)
420          {
421            G4double itsCut = cutg;
422            if (aPhoton->GetDefinition() == G4Electron::Electron()) itsCut = cute;
423            G4double itsEnergy = aPhoton->GetKineticEnergy();
424            if (itsEnergy > itsCut && itsEnergy <= ionEnergy)
425              {
426                nPhotons++;
427                ionEnergy -= itsEnergy;
428              }
429            else
430              {
431                delete aPhoton;
432                (*photonVector)[k]=0;
433              }
434          }
435      }
436    }
437  G4double energyDeposit=ionEnergy; //il deposito locale e' quello che rimane
438  G4int nbOfSecondaries=nPhotons;
439
440
441  // Generate the delta ray
442  G4double sin2 = std::sqrt(1. - cosThetaSecondary*cosThetaSecondary);
443  G4double phi2  = twopi * G4UniformRand();
444  G4DynamicParticle* electron = 0;
445 
446  G4double xEl = sin2 * std::cos(phi2); 
447  G4double yEl = sin2 * std::sin(phi2);
448  G4double zEl = cosThetaSecondary;
449  G4ThreeVector eDirection(xEl,yEl,zEl); //electron direction
450  eDirection.rotateUz(electronDirection0);
451
452  electron = new G4DynamicParticle (G4Electron::Electron(),
453                                    eDirection,eKineticEnergy) ;
454  nbOfSecondaries++;
455
456  aParticleChange.SetNumberOfSecondaries(nbOfSecondaries);
457  if (electron) aParticleChange.AddSecondary(electron);
458
459  G4double energySumTest = kineticEnergy1 +  eKineticEnergy;
460
461  for (size_t ll=0;ll<nTotPhotons;ll++)
462    {
463      aPhoton = (*photonVector)[ll];
464      if (aPhoton) {
465        aParticleChange.AddSecondary(aPhoton);
466        energySumTest += aPhoton->GetKineticEnergy();
467      }
468    }
469  delete photonVector;
470  if (energyDeposit < 0)
471    {
472      G4cout << "WARNING-" 
473             << "G4PenelopeIonisaition::PostStepDoIt - Negative energy deposit"
474             << G4endl;
475      energyDeposit=0;
476    }
477  energySumTest += energyDeposit; 
478  if (std::abs(energySumTest-kineticEnergy0)>1*eV) 
479    {
480      G4cout << "WARNING-" 
481             << "G4PenelopeIonisaition::PostStepDoIt - Energy non conservation"
482             << G4endl;
483      G4cout << "Final energy - initial energy = " <<
484        (energySumTest-kineticEnergy0)/eV << " eV" << G4endl;
485    }
486  aParticleChange.ProposeLocalEnergyDeposit(energyDeposit);
487  return G4VContinuousDiscreteProcess::PostStepDoIt(track, step);
488}
489
490
491void G4PenelopeIonisation::PrintInfoDefinition()
492{
493  G4String comments = "Total cross sections from EEDL database.";
494  comments += "\n      Delta energy sampled from a parametrised formula.";
495  comments += "\n      Implementation of the continuous dE/dx part.";
496  comments += "\n      At present it can be used for electrons and positrons ";
497  comments += "in the energy range [250eV,100GeV].";
498  comments += "\n      The process must work with G4PenelopeBremsstrahlung.";
499
500  G4cout << G4endl << GetProcessName() << ":  " << comments << G4endl;
501}
502
503G4bool G4PenelopeIonisation::IsApplicable(const G4ParticleDefinition& particle)
504{
505  return (  (&particle == G4Electron::Electron()) || (
506                                                      &particle == G4Positron::Positron()) );
507}
508
509G4double G4PenelopeIonisation::GetMeanFreePath(const G4Track& track,
510                                               G4double, // previousStepSize
511                                               G4ForceCondition* cond)
512{
513   *cond = NotForced;
514   G4int index = (track.GetMaterialCutsCouple())->GetIndex();
515   const G4VEMDataSet* data = theMeanFreePath->GetComponent(index);
516   G4double meanFreePath = data->FindValue(track.GetKineticEnergy());
517   return meanFreePath;
518}
519
520void G4PenelopeIonisation::SetCutForLowEnSecPhotons(G4double cut)
521{
522  cutForPhotons = cut;
523  deexcitationManager.SetCutForSecondaryPhotons(cut);
524}
525
526void G4PenelopeIonisation::SetCutForLowEnSecElectrons(G4double cut)
527{
528  cutForElectrons = cut;
529  deexcitationManager.SetCutForAugerElectrons(cut);
530}
531
532void G4PenelopeIonisation::ActivateAuger(G4bool val)
533{
534  deexcitationManager.ActivateAugerElectronProduction(val);
535}
536
537
538void G4PenelopeIonisation::CalculateDiscreteForElectrons(G4double ene,G4double cutoff,
539                                             G4int Z,G4double electronVolumeDensity)
540{
541  kineticEnergy1=ene;
542  cosThetaPrimary=1.0;
543  energySecondary=0.0;
544  cosThetaSecondary=1.0;
545  iOsc=-1;
546  //constants
547  G4double rb=ene+2.0*electron_mass_c2;
548  G4double gamma = 1.0+ene/electron_mass_c2;
549  G4double gamma2 = gamma*gamma;
550  G4double beta2 = (gamma2-1.0)/gamma2;
551  G4double amol = (gamma-1.0)*(gamma-1.0)/gamma2;
552  G4double cps = ene*rb;
553  G4double cp = std::sqrt(cps);
554 
555  G4double delta = CalculateDeltaFermi(ene,Z,electronVolumeDensity);
556  G4double distantTransvCS0 = std::max(std::log(gamma2)-beta2-delta,0.0);
557
558  G4double rl,rl1;
559
560  if (cutoff > ene) return; //delta rays are not generated
561
562  G4DataVector* qm = new G4DataVector();
563  G4DataVector* cumulHardCS = new G4DataVector();
564  G4DataVector* typeOfInteraction = new G4DataVector();
565  G4DataVector* nbOfLevel = new G4DataVector();
566 
567  //Hard close collisions with outer shells
568  G4double wmaxc = 0.5*ene;
569  G4double closeCS0 = 0.0;
570  G4double closeCS = 0.0;
571  if (cutoff>0.1*eV) 
572    {
573      rl=cutoff/ene;
574      rl1=1.0-rl;
575      if (rl < 0.5)
576        closeCS0 = (amol*(0.5-rl)+(1.0/rl)-(1.0/rl1)+(1.0-amol)*std::log(rl/rl1))/ene;
577    }
578
579  // Cross sections for the different oscillators
580
581  // totalHardCS contains the cumulative hard interaction cross section for the different
582  // excitable levels and the different interaction channels (close, distant, etc.),
583  // i.e.
584  // cumulHardCS[0] = 0.0
585  // cumulHardCS[1] = 1st excitable level (distant longitudinal only)
586  // cumulHardCS[2] = 1st excitable level (distant longitudinal + transverse)
587  // cumulHardCS[3] = 1st excitable level (distant longitudinal + transverse + close)
588  // cumulHardCS[4] = 1st excitable level (all channels) + 2nd excitable level (distant long only)
589  // etc.
590  // This is used for sampling the atomic level which is ionised and the channel of the
591  // interaction.
592  //
593  // For each index iFill of the cumulHardCS vector,
594  // nbOfLevel[iFill] contains the current excitable atomic level and
595  // typeOfInteraction[iFill] contains the current interaction channel, with the legenda:
596  //   1 = distant longitudinal interaction
597  //   2 = distant transverse interaction
598  //   3 = close collision
599  //   4 = close collision with outer shells (in this case nbOfLevel < 0 --> no binding energy)
600
601
602  G4int nOscil = ionizationEnergy->find(Z)->second->size();
603  G4double totalHardCS = 0.0;
604  G4double involvedElectrons = 0.0;
605  for (G4int i=0;i<nOscil;i++){
606    G4double wi = (*(resonanceEnergy->find(Z)->second))[i];
607    G4int occupNb = (G4int) (*(occupationNumber->find(Z)->second))[i];
608    //Distant excitations
609    if (wi>cutoff && wi<ene)
610      {
611        if (wi>(1e-6*ene)){
612          G4double cpp=std::sqrt((ene-wi)*(ene-wi+2.0*electron_mass_c2));
613          qm->push_back(std::sqrt((cp-cpp)*(cp-cpp)+electron_mass_c2*electron_mass_c2)-electron_mass_c2);
614        }
615        else
616          {
617            qm->push_back((wi*wi)/(beta2*2.0*electron_mass_c2));
618          }
619        //verificare che quando arriva qui il vettore ha SEMPRE l'i-esimo elemento
620        if ((*qm)[i] < wi)
621          {
622           
623            G4double distantLongitCS =  occupNb*std::log(wi*((*qm)[i]+2.0*electron_mass_c2)/
624                                         ((*qm)[i]*(wi+2.0*electron_mass_c2)))/wi;
625            cumulHardCS->push_back(totalHardCS);
626            typeOfInteraction->push_back(1.0); //distant longitudinal
627            nbOfLevel->push_back((G4double) i); //only excitable level are counted
628            totalHardCS += distantLongitCS;
629           
630            G4double distantTransvCS = occupNb*distantTransvCS0/wi;
631           
632            cumulHardCS->push_back(totalHardCS);
633            typeOfInteraction->push_back(2.0); //distant tranverse
634            nbOfLevel->push_back((G4double) i);
635            totalHardCS += distantTransvCS;
636          }
637      }
638    else 
639      {
640        qm->push_back(wi);
641      }
642    //close collisions
643    if(wi < wmaxc){
644      if (wi < cutoff) {
645        involvedElectrons += occupNb;
646      }
647      else
648        {
649          rl=wi/ene;
650          rl1=1.0-rl;
651          closeCS = occupNb*(amol*(0.5-rl)+(1.0/rl)-(1.0/rl1)+(1.0-amol)*std::log(rl/rl1))/ene;
652          cumulHardCS->push_back(totalHardCS);
653          typeOfInteraction->push_back(3.0); //close
654          nbOfLevel->push_back((G4double) i);
655          totalHardCS += closeCS;
656        }
657    }
658  } // loop on the levels
659 
660  cumulHardCS->push_back(totalHardCS);
661  typeOfInteraction->push_back(4.0); //close interaction with outer shells
662  nbOfLevel->push_back(-1.0);
663  totalHardCS += involvedElectrons*closeCS0;
664  cumulHardCS->push_back(totalHardCS); //this is the final value of the totalHardCS
665
666  if (totalHardCS < 1e-30) {
667    kineticEnergy1=ene;
668    cosThetaPrimary=1.0;
669    energySecondary=0.0;
670    cosThetaSecondary=0.0;
671    iOsc=-1;
672    delete qm;
673    delete cumulHardCS;
674    delete typeOfInteraction;
675    delete nbOfLevel;
676    return;
677  }
678
679
680  //Selection of the active oscillator on the basis of the cumulative cross sections
681  G4double TST = totalHardCS*G4UniformRand();
682  G4int is=0;
683  G4int js= nbOfLevel->size();
684  do{
685    G4int it=(is+js)/2;
686    if (TST > (*cumulHardCS)[it]) is=it;
687    if (TST <= (*cumulHardCS)[it]) js=it;
688  }while((js-is) > 1);
689
690  G4double UII=0.0;
691  G4double rkc=cutoff/ene;
692  G4double dde;
693  G4int kks;
694
695  G4double sampledInteraction = (*typeOfInteraction)[is];
696  iOsc = (G4int) (*nbOfLevel)[is];
697
698  //Generates the final state according to the sampled level and
699  //interaction channel
700 
701  if (sampledInteraction == 1.0)  //Hard distant longitudinal collisions
702    {
703      dde= (*(resonanceEnergy->find(Z)->second))[iOsc];
704      kineticEnergy1=ene-dde;
705      G4double qs=(*qm)[iOsc]/(1.0+((*qm)[iOsc]/(2.0*electron_mass_c2)));
706      G4double q=qs/(std::pow((qs/dde)*(1.0+(0.5*dde/electron_mass_c2)),G4UniformRand())-(0.5*qs/electron_mass_c2));
707      G4double qtrev = q*(q+2.0*electron_mass_c2);
708      G4double cpps = kineticEnergy1*(kineticEnergy1+2.0*electron_mass_c2);
709      cosThetaPrimary = (cpps+cps-qtrev)/(2.0*cp*std::sqrt(cpps));
710      if (cosThetaPrimary>1.0) cosThetaPrimary=1.0;
711      //Energy and emission angle of the delta ray
712      kks = (G4int) (*(shellFlag->find(Z)->second))[iOsc];
713      if (kks>4) 
714        {
715          energySecondary=dde;
716        }
717      else
718        {
719          energySecondary=dde-(*(ionizationEnergy->find(Z)->second))[iOsc];
720        }
721      cosThetaSecondary = 0.5*(dde*(ene+rb-dde)+qtrev)/std::sqrt(cps*qtrev);
722      if (cosThetaSecondary>1.0) cosThetaSecondary=1.0;
723    }
724
725  else if (sampledInteraction == 2.0)  //Hard distant transverse collisions
726    {
727      dde=(*(resonanceEnergy->find(Z)->second))[iOsc];
728      kineticEnergy1=ene-dde;
729      cosThetaPrimary=1.0;
730      //Energy and emission angle of the delta ray
731      kks = (G4int) (*(shellFlag->find(Z)->second))[iOsc];
732      if (kks>4)
733        {
734          energySecondary=dde;
735        }
736      else
737        {
738          energySecondary=dde-(*(ionizationEnergy->find(Z)->second))[iOsc];
739        }
740      cosThetaSecondary = 1.0;
741    }
742
743  else if (sampledInteraction == 3.0 || sampledInteraction == 4.0) //Close interaction
744    {
745      if (sampledInteraction == 4.0) //interaction with inner shells
746        {
747          UII=0.0;
748          rkc = cutoff/ene;
749          iOsc = -1;
750        }
751      else
752        {
753          kks = (G4int) (*(shellFlag->find(Z)->second))[iOsc];
754          if (kks > 4) {
755            UII=0.0;
756          }
757          else
758            {
759              UII = (*(ionizationEnergy->find(Z)->second))[iOsc];
760            }
761          rkc = (*(resonanceEnergy->find(Z)->second))[iOsc]/ene;
762        }
763    G4double A = 0.5*amol;
764    G4double arkc = A*0.5*rkc;
765    G4double phi,rk2,rk,rkf;
766    do{
767      G4double fb = (1.0+arkc)*G4UniformRand();
768      if (fb<1.0)
769        {
770          rk=rkc/(1.0-fb*(1.0-(rkc*2.0)));
771        }
772      else{
773        rk = rkc+(fb-1.0)*(0.5-rkc)/arkc;
774      }
775      rk2 = rk*rk;
776      rkf = rk/(1.0-rk);
777      phi = 1.0+(rkf*rkf)-rkf+amol*(rk2+rkf);
778    }while ((G4UniformRand()*(1.0+A*rk2)) > phi);
779    //Energy and scattering angle (primary electron);
780    kineticEnergy1 = ene*(1.0-rk);
781    cosThetaPrimary = std::sqrt(kineticEnergy1*rb/(ene*(rb-(rk*ene))));
782    //Energy and scattering angle of the delta ray
783    energySecondary = ene-kineticEnergy1-UII;
784    cosThetaSecondary = std::sqrt(rk*ene*rb/(ene*(rk*ene+2.0*electron_mass_c2)));
785    }
786
787  else
788
789    {
790      G4String excep = "G4PenelopeIonisation - Error in the calculation of the final state";
791      G4Exception(excep);
792    }
793
794  delete qm;
795  delete cumulHardCS;
796  delete typeOfInteraction;
797  delete nbOfLevel;
798
799  return;
800}
801
802void G4PenelopeIonisation::ReadData()
803{
804  char* path = getenv("G4LEDATA");
805  if (!path)
806    {
807      G4String excep = "G4PenelopeIonisation - G4LEDATA environment variable not set!";
808      G4Exception(excep);
809    }
810  G4String pathString(path);
811  G4String pathFile = pathString + "/penelope/ion-pen.dat";
812  std::ifstream file(pathFile);
813  std::filebuf* lsdp = file.rdbuf();
814 
815  if (!(lsdp->is_open()))
816    {
817      G4String excep = "G4PenelopeIonisation - data file " + pathFile + " not found!";
818      G4Exception(excep);
819    }
820
821  G4int k1,test,test1,k2,k3;
822  G4double a1,a2,a3,a4;
823  G4int Z=1,nLevels=0;
824  G4DataVector* x1;
825  G4DataVector* x2;
826  G4DataVector* x3;
827  G4DataVector* x4;
828
829  do{
830    x1 = new G4DataVector;
831    x2 = new G4DataVector;
832    x3 = new G4DataVector;
833    x4 = new G4DataVector;
834    file >> Z >> nLevels;
835    for (G4int h=0;h<nLevels;h++){
836      //index,occup number,ion energy,res energy,fj0,kz,shell flag
837      file >> k1 >> a1 >> a2 >> a3 >> a4 >> k2 >> k3;
838      x1->push_back(a1); 
839      x2->push_back(a2);
840      x3->push_back(a3);
841      x4->push_back((G4double) k3);
842    }
843    occupationNumber->insert(std::make_pair(Z,x1));
844    ionizationEnergy->insert(std::make_pair(Z,x2));
845    resonanceEnergy->insert(std::make_pair(Z,x3));
846    shellFlag->insert(std::make_pair(Z,x4));
847    file >> test >> test1; //-1 -1 close the data for each Z
848    if (test > 0) {
849      G4String excep = "G4PenelopeIonisation - data file corrupted!";
850      G4Exception(excep);
851    }
852  }while (test != -2); //the very last Z is closed with -2 instead of -1
853}
854
855
856G4double G4PenelopeIonisation::CalculateDeltaFermi(G4double ene,G4int Z,
857                                                   G4double electronVolumeDensity)
858{
859  G4double plasmaEnergyCoefficient = 1.377e-39; //(e*hbar)^2/(epsilon0*electron_mass)
860  G4double plasmaEnergySquared = plasmaEnergyCoefficient*(electronVolumeDensity*m3);
861  // std::sqrt(plasmaEnergySquared) is the plasma energy of the solid (MeV)
862  G4double gam = 1.0+ene/electron_mass_c2;
863  G4double gam2=gam*gam;
864  G4double delta = 0.0;
865
866  //Density effect
867  G4double TST = ((G4double) Z)/(gam2*plasmaEnergySquared); 
868 
869  G4double wl2 = 0.0;
870  G4double fdel=0.0;
871  G4double wr=0;
872  G4double help1=0.0;
873  size_t nbOsc = resonanceEnergy->find(Z)->second->size();
874  for(size_t i=0;i<nbOsc;i++)
875    {
876      G4int occupNb = (G4int) (*(occupationNumber->find(Z)->second))[i];
877      wr = (*(resonanceEnergy->find(Z)->second))[i];
878      fdel += occupNb/(wr*wr+wl2);
879    }
880  if (fdel < TST) return delta;
881  help1 = (*(resonanceEnergy->find(Z)->second))[nbOsc-1];
882  wl2 = help1*help1;
883  do{
884    wl2=wl2*2.0;
885    fdel = 0.0;
886    for (size_t ii=0;ii<nbOsc;ii++){
887      G4int occupNb = (G4int) (*(occupationNumber->find(Z)->second))[ii];
888      wr = (*(resonanceEnergy->find(Z)->second))[ii];
889      fdel += occupNb/(wr*wr+wl2);
890    }
891  }while (fdel > TST);
892  G4double wl2l=0.0;
893  G4double wl2u = wl2;
894  G4double control = 0.0;
895  do{
896    wl2=0.5*(wl2l+wl2u);
897    fdel = 0.0;
898    for (size_t jj=0;jj<nbOsc;jj++){
899      G4int occupNb = (G4int) (*(occupationNumber->find(Z)->second))[jj];
900      wr = (*(resonanceEnergy->find(Z)->second))[jj];
901      fdel += occupNb/(wr*wr+wl2);
902    }
903    if (fdel > TST)
904      {
905        wl2l = wl2;
906      }
907    else
908      {
909        wl2u = wl2;
910      }
911    control = wl2u-wl2l-wl2*1e-12; 
912  }while(control>0);
913
914  //Density correction effect
915   for (size_t kk=0;kk<nbOsc;kk++){
916      G4int occupNb = (G4int) (*(occupationNumber->find(Z)->second))[kk];
917      wr = (*(resonanceEnergy->find(Z)->second))[kk];
918      delta += occupNb*std::log(1.0+wl2/(wr*wr));
919    }
920   delta = (delta/((G4double) Z))-wl2/(gam2*plasmaEnergySquared); 
921   return delta;
922}
923
924G4double G4PenelopeIonisation::CalculateContinuous(G4double ene,G4double cutoff,
925                                                   G4int Z,G4double electronVolumeDensity,
926                                                   const G4ParticleDefinition& particle)
927{
928  //Constants
929  G4double gamma = 1.0+ene/electron_mass_c2;
930  G4double gamma2 = gamma*gamma;
931  G4double beta2 = (gamma2-1.0)/gamma2;
932  G4double constant = pi*classic_electr_radius*classic_electr_radius
933    *2.0*electron_mass_c2/beta2;
934 
935 
936  G4double delta = CalculateDeltaFermi(ene,Z,electronVolumeDensity);
937  G4int nbOsc = (G4int) resonanceEnergy->find(Z)->second->size();
938  G4double S1 = 0.0;
939  G4double stoppingPower = 0.0;
940  for (G4int i=0;i<nbOsc;i++){
941    G4double resEnergy = (*(resonanceEnergy->find(Z)->second))[i];
942    if (&particle == G4Electron::Electron())
943      {
944        S1 = CalculateStoppingPowerForElectrons(ene,resEnergy,delta,cutoff);
945      }
946    else if (&particle == G4Positron::Positron())
947      {
948        S1 = CalculateStoppingPowerForPositrons(ene,resEnergy,delta,cutoff);
949      }
950    G4double occupNb = (*(occupationNumber->find(Z)->second))[i];
951    stoppingPower += occupNb*constant*S1;
952  }
953 
954  return stoppingPower;
955}
956
957G4double G4PenelopeIonisation::CalculateStoppingPowerForElectrons(G4double ene,G4double resEne,
958                                             G4double delta,G4double cutoff)
959{
960  //Calculate constants
961  G4double gamma = 1.0+ene/electron_mass_c2;
962  G4double gamma2 = gamma*gamma;
963  G4double beta2 = (gamma2-1.0)/gamma2;
964  G4double cps = ene*(ene+2.0*electron_mass_c2);
965  G4double amol = (gamma-1.0)*(gamma-1.0)/gamma2;
966  G4double sPower = 0.0;
967  if (ene < resEne) return sPower;
968
969  //Distant interactions
970  G4double cp1s = (ene-resEne)*(ene-resEne+2.0*electron_mass_c2);
971  G4double cp1 = std::sqrt(cp1s);
972  G4double cp = std::sqrt(cps);
973  G4double sdLong=0.0, sdTrans = 0.0, sdDist=0.0;
974
975  //Distant longitudinal interactions
976  G4double qm = 0.0;
977
978  if (resEne > ene*(1e-6))
979    {
980      qm = std::sqrt((cp-cp1)*(cp-cp1)+(electron_mass_c2*electron_mass_c2))-electron_mass_c2;
981    }
982  else
983    {
984      qm = resEne*resEne/(beta2*2.0*electron_mass_c2);
985      qm = qm*(1.0-0.5*qm/electron_mass_c2);
986    }
987
988  if (qm < resEne)
989    {
990      sdLong = std::log(resEne*(qm+2.0*electron_mass_c2)/(qm*(resEne+2.0*electron_mass_c2)));
991    }
992  else
993    {
994      sdLong = 0.0;
995    }
996 
997  if (sdLong > 0) {
998    sdTrans = std::max(std::log(gamma2)-beta2-delta,0.0);
999    sdDist = sdTrans + sdLong;
1000    if (cutoff > resEne) sPower = sdDist;
1001  }
1002
1003
1004  // Close collisions (Moeller's cross section)
1005  G4double wl = std::max(cutoff,resEne);
1006  G4double wu = 0.5*ene;
1007 
1008  if (wl < (wu-1*eV)) wu=wl;
1009  wl = resEne;
1010  if (wl > (wu-1*eV)) return sPower;
1011  sPower += std::log(wu/wl)+(ene/(ene-wu))-(ene/(ene-wl))
1012    + (2.0 - amol)*std::log((ene-wu)/(ene-wl))
1013    + amol*((wu*wu)-(wl*wl))/(2.0*ene*ene);
1014
1015  return sPower;
1016}
1017
1018G4double G4PenelopeIonisation::CalculateStoppingPowerForPositrons(G4double ene,G4double resEne,
1019                                             G4double delta,G4double cutoff)
1020{
1021  //Calculate constants
1022  G4double gamma = 1.0+ene/electron_mass_c2;
1023  G4double gamma2 = gamma*gamma;
1024  G4double beta2 = (gamma2-1.0)/gamma2;
1025  G4double cps = ene*(ene+2.0*electron_mass_c2);
1026  G4double amol = (ene/(ene+electron_mass_c2)) * (ene/(ene+electron_mass_c2));
1027  G4double help = (gamma+1.0)*(gamma+1.0);
1028  G4double bha1 = amol*(2.0*help-1.0)/(gamma2-1.0);
1029  G4double bha2 = amol*(3.0+1.0/help);
1030  G4double bha3 = amol*2.0*gamma*(gamma-1.0)/help;
1031  G4double bha4 = amol*(gamma-1.0)*(gamma-1.0)/help;
1032
1033  G4double sPower = 0.0;
1034  if (ene < resEne) return sPower;
1035
1036  //Distant interactions
1037  G4double cp1s = (ene-resEne)*(ene-resEne+2.0*electron_mass_c2);
1038  G4double cp1 = std::sqrt(cp1s);
1039  G4double cp = std::sqrt(cps);
1040  G4double sdLong=0.0, sdTrans = 0.0, sdDist=0.0;
1041
1042  //Distant longitudinal interactions
1043  G4double qm = 0.0;
1044
1045  if (resEne > ene*(1e-6))
1046    {
1047      qm = std::sqrt((cp-cp1)*(cp-cp1)+(electron_mass_c2*electron_mass_c2))-electron_mass_c2;
1048    }
1049  else
1050    {
1051      qm = resEne*resEne/(beta2*2.0*electron_mass_c2);
1052      qm = qm*(1.0-0.5*qm/electron_mass_c2);
1053    }
1054
1055  if (qm < resEne)
1056    {
1057      sdLong = std::log(resEne*(qm+2.0*electron_mass_c2)/(qm*(resEne+2.0*electron_mass_c2)));
1058    }
1059  else
1060    {
1061      sdLong = 0.0;
1062    }
1063 
1064  if (sdLong > 0) {
1065    sdTrans = std::max(std::log(gamma2)-beta2-delta,0.0);
1066    sdDist = sdTrans + sdLong;
1067    if (cutoff > resEne) sPower = sdDist;
1068  }
1069
1070
1071  // Close collisions (Bhabha's cross section)
1072  G4double wl = std::max(cutoff,resEne);
1073  G4double wu = ene;
1074 
1075  if (wl < (wu-1*eV)) wu=wl;
1076  wl = resEne;
1077  if (wl > (wu-1*eV)) return sPower;
1078  sPower += std::log(wu/wl)-bha1*(wu-wl)/ene
1079    + bha2*((wu*wu)-(wl*wl))/(2.0*ene*ene)
1080    - bha3*((wu*wu*wu)-(wl*wl*wl))/(3.0*ene*ene*ene)
1081    + bha4*((wu*wu*wu*wu)-(wl*wl*wl*wl))/(4.0*ene*ene*ene*ene);
1082
1083  return sPower;
1084}
1085
1086void G4PenelopeIonisation::CalculateDiscreteForPositrons(G4double ene,G4double cutoff,
1087                                             G4int Z,G4double electronVolumeDensity)
1088
1089{
1090  kineticEnergy1=ene;
1091  cosThetaPrimary=1.0;
1092  energySecondary=0.0;
1093  cosThetaSecondary=1.0;
1094  iOsc=-1;
1095  //constants
1096  G4double rb=ene+2.0*electron_mass_c2;
1097  G4double gamma = 1.0+ene/electron_mass_c2;
1098  G4double gamma2 = gamma*gamma;
1099  G4double beta2 = (gamma2-1.0)/gamma2;
1100  G4double amol = (gamma-1.0)*(gamma-1.0)/gamma2;
1101  G4double cps = ene*rb;
1102  G4double cp = std::sqrt(cps);
1103  G4double help = (gamma+1.0)*(gamma+1.0);
1104  G4double bha1 = amol*(2.0*help-1.0)/(gamma2-1.0);
1105  G4double bha2 = amol*(3.0+1.0/help);
1106  G4double bha3 = amol*2.0*gamma*(gamma-1.0)/help;
1107  G4double bha4 = amol*(gamma-1.0)*(gamma-1.0)/help;
1108 
1109  G4double delta = CalculateDeltaFermi(ene,Z,electronVolumeDensity);
1110  G4double distantTransvCS0 = std::max(std::log(gamma2)-beta2-delta,0.0);
1111
1112  G4double rl,rl1;
1113
1114  if (cutoff > ene) return; //delta rays are not generated
1115
1116  G4DataVector* qm = new G4DataVector();
1117  G4DataVector* cumulHardCS = new G4DataVector();
1118  G4DataVector* typeOfInteraction = new G4DataVector();
1119  G4DataVector* nbOfLevel = new G4DataVector();
1120 
1121
1122  //Hard close collisions with outer shells
1123  G4double wmaxc = ene;
1124  G4double closeCS0 = 0.0;
1125  G4double closeCS = 0.0;
1126  if (cutoff>0.1*eV) 
1127    {
1128      rl=cutoff/ene;
1129      rl1=1.0-rl;
1130      if (rl < 1.0)
1131        closeCS0 = (((1.0/rl)-1.0) + bha1*std::log(rl) + bha2*rl1
1132                    + (bha3/2.0)*((rl*rl)-1.0)
1133                    + (bha4/3.0)*(1.0-(rl*rl*rl)))/ene;
1134    }
1135
1136  // Cross sections for the different oscillators
1137
1138  // totalHardCS contains the cumulative hard interaction cross section for the different
1139  // excitable levels and the different interaction channels (close, distant, etc.),
1140  // i.e.
1141  // cumulHardCS[0] = 0.0
1142  // cumulHardCS[1] = 1st excitable level (distant longitudinal only)
1143  // cumulHardCS[2] = 1st excitable level (distant longitudinal + transverse)
1144  // cumulHardCS[3] = 1st excitable level (distant longitudinal + transverse + close)
1145  // cumulHardCS[4] = 1st excitable level (all channels) + 2nd excitable level (distant long only)
1146  // etc.
1147  // This is used for sampling the atomic level which is ionised and the channel of the
1148  // interaction.
1149  //
1150  // For each index iFill of the cumulHardCS vector,
1151  // nbOfLevel[iFill] contains the current excitable atomic level and
1152  // typeOfInteraction[iFill] contains the current interaction channel, with the legenda:
1153  //   1 = distant longitudinal interaction
1154  //   2 = distant transverse interaction
1155  //   3 = close collision
1156  //   4 = close collision with outer shells (in this case nbOfLevel < 0 --> no binding energy)
1157
1158
1159  G4int nOscil = ionizationEnergy->find(Z)->second->size();
1160  G4double totalHardCS = 0.0;
1161  G4double involvedElectrons = 0.0;
1162  for (G4int i=0;i<nOscil;i++){
1163    G4double wi = (*(resonanceEnergy->find(Z)->second))[i];
1164    G4int occupNb = (G4int) (*(occupationNumber->find(Z)->second))[i];
1165    //Distant excitations
1166    if (wi>cutoff && wi<ene)
1167      {
1168        if (wi>(1e-6*ene)){
1169          G4double cpp=std::sqrt((ene-wi)*(ene-wi+2.0*electron_mass_c2));
1170          qm->push_back(std::sqrt((cp-cpp)*(cp-cpp)+ electron_mass_c2 * electron_mass_c2)-electron_mass_c2);
1171        }
1172        else
1173          {
1174            qm->push_back(wi*wi/(beta2+2.0*electron_mass_c2));
1175          }
1176        //verificare che quando arriva qui il vettore ha SEMPRE l'i-esimo elemento
1177        if ((*qm)[i] < wi)
1178          {
1179           
1180            G4double distantLongitCS =  occupNb*std::log(wi*((*qm)[i]+2.0*electron_mass_c2)/
1181                                         ((*qm)[i]*(wi+2.0*electron_mass_c2)))/wi;
1182            cumulHardCS->push_back(totalHardCS);
1183            typeOfInteraction->push_back(1.0); //distant longitudinal
1184            nbOfLevel->push_back((G4double) i); //only excitable level are counted
1185            totalHardCS += distantLongitCS;
1186           
1187            G4double distantTransvCS = occupNb*distantTransvCS0/wi;
1188           
1189            cumulHardCS->push_back(totalHardCS);
1190            typeOfInteraction->push_back(2.0); //distant tranverse
1191            nbOfLevel->push_back((G4double) i);
1192            totalHardCS += distantTransvCS;
1193          }
1194      }
1195    else 
1196      {
1197        qm->push_back(wi);
1198      }
1199    //close collisions
1200    if(wi < wmaxc){
1201      if (wi < cutoff) {
1202        involvedElectrons += occupNb;
1203      }
1204      else
1205        {
1206          rl=wi/ene;
1207          rl1=1.0-rl;
1208          closeCS = occupNb*(((1.0/rl)-1.0)+bha1*std::log(rl)+bha2*rl1
1209                             + (bha3/2.0)*((rl*rl)-1.0)
1210                             + (bha4/3.0)*(1.0-(rl*rl*rl)))/ene;
1211          cumulHardCS->push_back(totalHardCS);
1212          typeOfInteraction->push_back(3.0); //close
1213          nbOfLevel->push_back((G4double) i);
1214          totalHardCS += closeCS;
1215        }
1216    }
1217  } // loop on the levels
1218 
1219  cumulHardCS->push_back(totalHardCS);
1220  typeOfInteraction->push_back(4.0); //close interaction with outer shells
1221  nbOfLevel->push_back(-1.0);
1222  totalHardCS += involvedElectrons*closeCS0;
1223  cumulHardCS->push_back(totalHardCS); //this is the final value of the totalHardCS
1224
1225  if (totalHardCS < 1e-30) {
1226    kineticEnergy1=ene;
1227    cosThetaPrimary=1.0;
1228    energySecondary=0.0;
1229    cosThetaSecondary=0.0;
1230    iOsc=-1;
1231    delete qm;
1232    delete cumulHardCS;
1233    delete typeOfInteraction;
1234    delete nbOfLevel;
1235    return;
1236  }
1237
1238
1239  //Selection of the active oscillator on the basis of the cumulative cross sections
1240  G4double TST = totalHardCS*G4UniformRand();
1241  G4int is=0;
1242  G4int js= nbOfLevel->size();
1243  do{
1244    G4int it=(is+js)/2;
1245    if (TST > (*cumulHardCS)[it]) is=it;
1246    if (TST <= (*cumulHardCS)[it]) js=it;
1247  }while((js-is) > 1);
1248
1249  G4double UII=0.0;
1250  G4double rkc=cutoff/ene;
1251  G4double dde;
1252  G4int kks;
1253
1254  G4double sampledInteraction = (*typeOfInteraction)[is];
1255  iOsc = (G4int) (*nbOfLevel)[is];
1256
1257  //Generates the final state according to the sampled level and
1258  //interaction channel
1259 
1260  if (sampledInteraction == 1.0)  //Hard distant longitudinal collisions
1261    {
1262      dde= (*(resonanceEnergy->find(Z)->second))[iOsc];
1263      kineticEnergy1=ene-dde;
1264      G4double qs=(*qm)[iOsc]/(1.0+((*qm)[iOsc]/(2.0*electron_mass_c2)));
1265      G4double q=qs/(std::pow((qs/dde)*(1.0+(0.5*dde/electron_mass_c2)),G4UniformRand())-(0.5*qs/electron_mass_c2));
1266      G4double qtrev = q*(q+2.0*electron_mass_c2);
1267      G4double cpps = kineticEnergy1*(kineticEnergy1+2.0*electron_mass_c2);
1268      cosThetaPrimary = (cpps+cps-qtrev)/(2.0*cp*std::sqrt(cpps));
1269      if (cosThetaPrimary>1.0) cosThetaPrimary=1.0;
1270      //Energy and emission angle of the delta ray
1271      kks = (G4int) (*(shellFlag->find(Z)->second))[iOsc];
1272      if (kks>4) 
1273        {
1274          energySecondary=dde;
1275        }
1276      else
1277        {
1278          energySecondary=dde-(*(ionizationEnergy->find(Z)->second))[iOsc];
1279        }
1280      cosThetaSecondary = 0.5*(dde*(ene+rb-dde)+qtrev)/std::sqrt(cps*qtrev);
1281      if (cosThetaSecondary>1.0) cosThetaSecondary=1.0;
1282    }
1283
1284  else if (sampledInteraction == 2.0)  //Hard distant transverse collisions
1285    {
1286      dde=(*(resonanceEnergy->find(Z)->second))[iOsc];
1287      kineticEnergy1=ene-dde;
1288      cosThetaPrimary=1.0;
1289      //Energy and emission angle of the delta ray
1290      kks = (G4int) (*(shellFlag->find(Z)->second))[iOsc];
1291      if (kks>4)
1292        {
1293          energySecondary=dde;
1294        }
1295      else
1296        {
1297          energySecondary=dde-(*(ionizationEnergy->find(Z)->second))[iOsc];
1298        }
1299      cosThetaSecondary = 1.0;
1300    }
1301
1302  else if (sampledInteraction == 3.0 || sampledInteraction == 4.0) //Close interaction
1303    {
1304      if (sampledInteraction == 4.0) //interaction with inner shells
1305        {
1306          UII=0.0;
1307          rkc = cutoff/ene;
1308          iOsc = -1;
1309        }
1310      else
1311        {
1312          kks = (G4int) (*(shellFlag->find(Z)->second))[iOsc];
1313          if (kks > 4) {
1314            UII=0.0;
1315          }
1316          else
1317            {
1318              UII = (*(ionizationEnergy->find(Z)->second))[iOsc];
1319            }
1320          rkc = (*(resonanceEnergy->find(Z)->second))[iOsc]/ene;
1321        }
1322      G4double phi,rk;
1323      do{
1324        rk=rkc/(1.0-G4UniformRand()*(1.0-rkc));
1325        phi = 1.0-rk*(bha1-rk*(bha2-rk*(bha3-bha4*rk)));
1326      }while ( G4UniformRand() > phi);
1327      //Energy and scattering angle (primary electron);
1328      kineticEnergy1 = ene*(1.0-rk);
1329      cosThetaPrimary = std::sqrt(kineticEnergy1*rb/(ene*(rb-(rk*ene))));
1330      //Energy and scattering angle of the delta ray
1331      energySecondary = ene-kineticEnergy1-UII;
1332      cosThetaSecondary = std::sqrt(rk*ene*rb/(ene*(rk*ene+2.0*electron_mass_c2)));
1333    }     
1334      else
1335    {
1336      G4String excep = "G4PenelopeIonisation - Error in the calculation of the final state";
1337      G4Exception(excep);
1338    }
1339
1340  delete qm;
1341  delete cumulHardCS;
1342  delete typeOfInteraction;
1343  delete nbOfLevel;
1344
1345  return;
1346}
1347
1348// This stuff in needed in order to interface with the Cross Section Handler
1349
1350G4double G4PenelopeIonisation::CalculateCrossSectionsRatio(G4double ene,G4double cutoff,
1351                                                           G4int Z,G4double electronVolumeDensity,
1352                                                           const G4ParticleDefinition& particle)
1353{
1354 //Constants
1355  G4double gamma = 1.0+ene/electron_mass_c2;
1356  G4double gamma2 = gamma*gamma;
1357  G4double beta2 = (gamma2-1.0)/gamma2;
1358  G4double constant = pi*classic_electr_radius*classic_electr_radius*2.0*electron_mass_c2/beta2;
1359  G4double delta = CalculateDeltaFermi(ene,Z,electronVolumeDensity);
1360  G4int nbOsc = (G4int) resonanceEnergy->find(Z)->second->size();
1361  G4double S0 = 0.0, H0=0.0;
1362  G4double softCS = 0.0;
1363  G4double hardCS = 0.0;
1364  for (G4int i=0;i<nbOsc;i++){
1365    G4double resEnergy = (*(resonanceEnergy->find(Z)->second))[i];
1366    if (&particle == G4Electron::Electron())
1367      {
1368        S0 = CrossSectionsRatioForElectrons(ene,resEnergy,delta,cutoff,1);
1369        H0 = CrossSectionsRatioForElectrons(ene,resEnergy,delta,cutoff,2);
1370      }
1371    else if (&particle == G4Positron::Positron())
1372      {
1373        S0 = CrossSectionsRatioForPositrons(ene,resEnergy,delta,cutoff,1);
1374        H0 = CrossSectionsRatioForPositrons(ene,resEnergy,delta,cutoff,2);
1375      }
1376    G4double occupNb = (*(occupationNumber->find(Z)->second))[i];
1377    softCS += occupNb*constant*S0;
1378    hardCS += occupNb*constant*H0;
1379  }
1380  G4double ratio = 0.0;
1381  if (softCS+hardCS) ratio = (hardCS)/(softCS+hardCS);
1382  return ratio;
1383}
1384
1385
1386G4double G4PenelopeIonisation::CrossSectionsRatioForElectrons(G4double ene,G4double resEne,
1387                                                     G4double delta,G4double cutoff,
1388                                                     G4int index)
1389{
1390  //Calculate constants
1391  G4double gamma = 1.0+ene/electron_mass_c2;
1392  G4double gamma2 = gamma*gamma;
1393  G4double beta2 = (gamma2-1.0)/gamma2;
1394  G4double cps = ene*(ene+2.0*electron_mass_c2);
1395  G4double amol = (ene/(ene+electron_mass_c2)) * (ene/(ene+electron_mass_c2)) ;
1396  G4double hardCont = 0.0;
1397  G4double softCont = 0.0;
1398  if (ene < resEne) return 0.0;
1399 
1400  //Distant interactions
1401  G4double cp1s = (ene-resEne)*(ene-resEne+2.0*electron_mass_c2);
1402  G4double cp1 = std::sqrt(cp1s);
1403  G4double cp = std::sqrt(cps);
1404  G4double sdLong=0.0, sdTrans = 0.0, sdDist=0.0;
1405
1406  //Distant longitudinal interactions
1407  G4double qm = 0.0;
1408
1409  if (resEne > ene*(1e-6))
1410    {
1411      qm = std::sqrt((cp-cp1)*(cp-cp1)+(electron_mass_c2*electron_mass_c2))-electron_mass_c2;
1412    }
1413  else
1414    {
1415      qm = resEne*resEne/(beta2*2.0*electron_mass_c2);
1416      qm = qm*(1.0-0.5*qm/electron_mass_c2);
1417    }
1418
1419  if (qm < resEne)
1420    {
1421      sdLong = std::log(resEne*(qm+2.0*electron_mass_c2)/(qm*(resEne+2.0*electron_mass_c2)));
1422    }
1423  else
1424    {
1425      sdLong = 0.0;
1426    }
1427 
1428  if (sdLong > 0) {
1429    sdTrans = std::max(std::log(gamma2)-beta2-delta,0.0);
1430    sdDist = sdTrans + sdLong;
1431    if (cutoff > resEne) 
1432      {
1433        softCont = sdDist/resEne;
1434      }
1435    else
1436      {
1437        hardCont = sdDist/resEne;
1438      }
1439  }
1440
1441
1442  // Close collisions (Moeller's cross section)
1443  G4double wl = std::max(cutoff,resEne);
1444  G4double wu = 0.5*ene;
1445 
1446  if (wl < (wu-1*eV)) 
1447    { 
1448      hardCont += (1.0/(ene-wu))-(1.0/(ene-wl))
1449        - (1.0/wu)+(1.0/wl)
1450        + (1.0-amol)*std::log(((ene-wu)*wl)/((ene-wl)*wu))/ene
1451        + amol*(wu-wl)/(ene*ene);
1452      wu=wl;
1453    }
1454
1455  wl = resEne;
1456  if (wl > (wu-1*eV)) {
1457    if (index == 1) return softCont;
1458    if (index == 2) return hardCont;
1459  }
1460  softCont += (1.0/(ene-wu))-(1.0/(ene-wl))
1461        - (1.0/wu)+(1.0/wl)
1462        + (1.0-amol)*std::log(((ene-wu)*wl)/((ene-wl)*wu))/ene
1463        + amol*(wu-wl)/(ene*ene);
1464  if (index == 1) return softCont;
1465  return hardCont;
1466}
1467
1468G4double G4PenelopeIonisation::CrossSectionsRatioForPositrons(G4double ene,G4double resEne,
1469                                             G4double delta,G4double cutoff,G4int index)
1470{
1471  //Calculate constants
1472  G4double gamma = 1.0+ene/electron_mass_c2;
1473  G4double gamma2 = gamma*gamma;
1474  G4double beta2 = (gamma2-1.0)/gamma2;
1475  G4double cps = ene*(ene+2.0*electron_mass_c2);
1476  G4double amol = (ene/(ene+electron_mass_c2)) * (ene/(ene+electron_mass_c2)) ;
1477  G4double help = (gamma+1.0)*(gamma+1.0);
1478  G4double bha1 = amol*(2.0*help-1.0)/(gamma2-1.0);
1479  G4double bha2 = amol*(3.0+1.0/help);
1480  G4double bha3 = amol*2.0*gamma*(gamma-1.0)/help;
1481  G4double bha4 = amol*(gamma-1.0)*(gamma-1.0)/help;
1482  G4double hardCont = 0.0;
1483  G4double softCont = 0.0;
1484  if (ene < resEne) return 0.0;
1485
1486
1487  //Distant interactions
1488  G4double cp1s = (ene-resEne)*(ene-resEne+2.0*electron_mass_c2);
1489  G4double cp1 = std::sqrt(cp1s);
1490  G4double cp = std::sqrt(cps);
1491  G4double sdLong=0.0, sdTrans = 0.0, sdDist=0.0;
1492
1493  //Distant longitudinal interactions
1494  G4double qm = 0.0;
1495
1496  if (resEne > ene*(1e-6))
1497    {
1498      qm = std::sqrt((cp-cp1)*(cp-cp1)+(electron_mass_c2*electron_mass_c2))-electron_mass_c2;
1499    }
1500  else
1501    {
1502      qm = resEne*resEne/(beta2*2.0*electron_mass_c2);
1503      qm = qm*(1.0-0.5*qm/electron_mass_c2);
1504    }
1505
1506  if (qm < resEne)
1507    {
1508      sdLong = std::log(resEne*(qm+2.0*electron_mass_c2)/(qm*(resEne+2.0*electron_mass_c2)));
1509    }
1510  else
1511    {
1512      sdLong = 0.0;
1513    }
1514 
1515  if (sdLong > 0) {
1516    sdTrans = std::max(std::log(gamma2)-beta2-delta,0.0);
1517    sdDist = sdTrans + sdLong;
1518    if (cutoff > resEne) 
1519      {
1520        softCont = sdDist/resEne;
1521      }
1522    else
1523      {
1524        hardCont = sdDist/resEne;
1525      }
1526  }
1527
1528
1529  // Close collisions (Bhabha's cross section)
1530  G4double wl = std::max(cutoff,resEne);
1531  G4double wu = ene;
1532 
1533  if (wl < (wu-1*eV)) {
1534    hardCont += (1.0/wl)-(1.0/wu)-bha1*std::log(wu/wl)/ene
1535      + bha2*(wu-wl)/(ene*ene) -bha3*((wu*wu)-(wl*wl))/(2.0*ene*ene*ene)
1536      + bha4*((wu*wu*wu)-(wl*wl*wl))/(3.0*ene*ene*ene*ene);
1537    wu=wl;
1538  }
1539  wl = resEne;
1540  if (wl > (wu-1*eV)) 
1541    { 
1542      if (index == 1) return softCont;
1543      if (index == 2) return hardCont;
1544    }
1545  softCont += (1.0/wl)-(1.0/wu)-bha1*std::log(wu/wl)/ene
1546    + bha2*(wu-wl)/(ene*ene) -bha3*((wu*wu)-(wl*wl))/(2.0*ene*ene*ene)
1547    + bha4*((wu*wu*wu)-(wl*wl*wl))/(3.0*ene*ene*ene*ene);
1548 
1549  if (index == 1) return softCont;
1550  return hardCont;
1551}
Note: See TracBrowser for help on using the repository browser.