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

Last change on this file was 1347, checked in by garnier, 15 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.