source: trunk/source/processes/electromagnetic/lowenergy/src/G4PenelopeComptonModel.cc@ 1014

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

update to geant4.9.2

File size: 26.7 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: G4PenelopeComptonModel.cc,v 1.2 2008/12/04 14:11:21 pandola Exp $
27// GEANT4 tag $Name: geant4-09-02 $
28//
29// Author: Luciano Pandola
30//
31// History:
32// --------
33// 02 Oct 2008 L Pandola Migration from process to model
34// 28 Oct 2008 L Pandola Treat the database data from Penelope according to the
35// original model, namely merging levels below 15 eV in
36// a single one. Still, it is not fully compliant with the
37// original Penelope model, because plasma excitation is not
38// considered.
39// 22 Nov 2008 L Pandola Make unit of measurements explicit for binding energies
40// that are read from the external files.
41// 24 Nov 2008 L Pandola Find a cleaner way to delete vectors.
42//
43
44#include "G4PenelopeComptonModel.hh"
45#include "G4ParticleDefinition.hh"
46#include "G4MaterialCutsCouple.hh"
47#include "G4ProductionCutsTable.hh"
48#include "G4DynamicParticle.hh"
49#include "G4VEMDataSet.hh"
50#include "G4PhysicsTable.hh"
51#include "G4ElementTable.hh"
52#include "G4Element.hh"
53#include "G4PhysicsLogVector.hh"
54#include "G4PenelopeIntegrator.hh"
55#include "G4AtomicTransitionManager.hh"
56#include "G4AtomicDeexcitation.hh"
57#include "G4AtomicShell.hh"
58#include "G4Gamma.hh"
59#include "G4Electron.hh"
60
61//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
62
63
64G4PenelopeComptonModel::G4PenelopeComptonModel(const G4ParticleDefinition*,
65 const G4String& nam)
66 :G4VEmModel(nam),ionizationEnergy(0),hartreeFunction(0),
67 occupationNumber(0),isInitialised(false)
68{
69 fIntrinsicLowEnergyLimit = 100.0*eV;
70 fIntrinsicHighEnergyLimit = 100.0*GeV;
71 SetLowEnergyLimit(fIntrinsicLowEnergyLimit);
72 SetHighEnergyLimit(fIntrinsicHighEnergyLimit);
73 //
74 energyForIntegration = 0.0;
75 ZForIntegration = 1;
76
77 fUseAtomicDeexcitation = true;
78 verboseLevel= 0;
79 // Verbosity scale:
80 // 0 = nothing
81 // 1 = warning for energy non-conservation
82 // 2 = details of energy budget
83 // 3 = calculation of cross sections, file openings, sampling of atoms
84 // 4 = entering in methods
85
86 //These vectors do not change when materials or cut change.
87 //Therefore I can read it at the constructor
88 ionizationEnergy = new std::map<G4int,G4DataVector*>;
89 hartreeFunction = new std::map<G4int,G4DataVector*>;
90 occupationNumber = new std::map<G4int,G4DataVector*>;
91
92 ReadData(); //Read data from file
93
94}
95
96//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
97
98G4PenelopeComptonModel::~G4PenelopeComptonModel()
99{
100 std::map <G4int,G4DataVector*>::iterator i;
101 for (i=ionizationEnergy->begin();i != ionizationEnergy->end();i++)
102 if (i->second) delete i->second;
103 for (i=hartreeFunction->begin();i != hartreeFunction->end();i++)
104 if (i->second) delete i->second;
105 for (i=occupationNumber->begin();i != occupationNumber->end();i++)
106 if (i->second) delete i->second;
107
108
109 if (ionizationEnergy)
110 delete ionizationEnergy;
111 if (hartreeFunction)
112 delete hartreeFunction;
113 if (occupationNumber)
114 delete occupationNumber;
115}
116
117//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
118
119void G4PenelopeComptonModel::Initialise(const G4ParticleDefinition* particle,
120 const G4DataVector& cuts)
121{
122 if (verboseLevel > 3)
123 G4cout << "Calling G4PenelopeComptonModel::Initialise()" << G4endl;
124
125 InitialiseElementSelectors(particle,cuts);
126 if (LowEnergyLimit() < fIntrinsicLowEnergyLimit)
127 {
128 G4cout << "G4PenelopeComptonModel: low energy limit increased from " <<
129 LowEnergyLimit()/eV << " eV to " << fIntrinsicLowEnergyLimit/eV << " eV" << G4endl;
130 SetLowEnergyLimit(fIntrinsicLowEnergyLimit);
131 }
132 if (HighEnergyLimit() > fIntrinsicHighEnergyLimit)
133 {
134 G4cout << "G4PenelopeComptonModel: high energy limit decreased from " <<
135 HighEnergyLimit()/GeV << " GeV to " << fIntrinsicHighEnergyLimit/GeV << " GeV" << G4endl;
136 SetHighEnergyLimit(fIntrinsicHighEnergyLimit);
137 }
138
139 G4cout << "Penelope Compton model is initialized " << G4endl
140 << "Energy range: "
141 << LowEnergyLimit() / keV << " keV - "
142 << HighEnergyLimit() / GeV << " GeV"
143 << G4endl;
144
145 if(isInitialised) return;
146
147 if(pParticleChange)
148 fParticleChange = reinterpret_cast<G4ParticleChangeForGamma*>(pParticleChange);
149 else
150 fParticleChange = new G4ParticleChangeForGamma();
151 isInitialised = true;
152}
153
154//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
155
156G4double G4PenelopeComptonModel::ComputeCrossSectionPerAtom(
157 const G4ParticleDefinition*,
158 G4double energy,
159 G4double Z, G4double,
160 G4double, G4double)
161{
162 // Penelope model to calculate the Compton scattering cross section:
163 // D. Brusa et al., Nucl. Instrum. Meth. A 379 (1996) 167
164 //
165 // The cross section for Compton scattering is calculated according to the Klein-Nishina
166 // formula for energy > 5 MeV.
167 // For E < 5 MeV it is used a parametrization for the differential cross-section dSigma/dOmega,
168 // which is integrated numerically in cos(theta), G4PenelopeComptonModel::DifferentialCrossSection().
169 // The parametrization includes the J(p)
170 // distribution profiles for the atomic shells, that are tabulated from Hartree-Fock calculations
171 // from F. Biggs et al., At. Data Nucl. Data Tables 16 (1975) 201
172 //
173 if (verboseLevel > 3)
174 G4cout << "Calling ComputeCrossSectionPerAtom() of G4PenelopeComptonModel" << G4endl;
175
176 G4int iZ = (G4int) Z;
177 G4double cs=0.0;
178 energyForIntegration=energy;
179 ZForIntegration = iZ;
180 if (energy< 5*MeV)
181 {
182 // numerically integrate differential cross section dSigma/dOmega
183 G4PenelopeIntegrator<G4PenelopeComptonModel,G4double (G4PenelopeComptonModel::*)(G4double)>
184 theIntegrator;
185 cs = theIntegrator.Calculate(this,&G4PenelopeComptonModel::DifferentialCrossSection,-1.0,1.0,1e-05);
186 }
187 else
188 {
189 // use Klein-Nishina formula
190 G4double ki=energy/electron_mass_c2;
191 G4double ki3=ki*ki;
192 G4double ki2=1.0+2*ki;
193 G4double ki1=ki3-ki2-1.0;
194 G4double t0=1.0/(ki2);
195 G4double csl = 0.5*ki3*t0*t0+ki2*t0+ki1*std::log(t0)-(1.0/t0);
196 G4int nosc = occupationNumber->find(iZ)->second->size();
197 for (G4int i=0;i<nosc;i++)
198 {
199 G4double ionEnergy = (*(ionizationEnergy->find(iZ)->second))[i];
200 G4double tau=(energy-ionEnergy)/energy;
201 if (tau > t0)
202 {
203 G4double csu = 0.5*ki3*tau*tau+ki2*tau+ki1*std::log(tau)-(1.0/tau);
204 G4int f = (G4int) (*(occupationNumber->find(iZ)->second))[i];
205 cs = cs + f*(csu-csl);
206 }
207 }
208 cs=pi*classic_electr_radius*classic_electr_radius*cs/(ki*ki3);
209 }
210
211 if (verboseLevel > 2)
212 G4cout << "Compton cross Section at " << energy/keV << " keV for Z=" << Z <<
213 " = " << cs/barn << " barn" << G4endl;
214 return cs;
215}
216
217//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
218
219void G4PenelopeComptonModel::SampleSecondaries(std::vector<G4DynamicParticle*>* fvect,
220 const G4MaterialCutsCouple* couple,
221 const G4DynamicParticle* aDynamicGamma,
222 G4double,
223 G4double)
224{
225
226 // Penelope model to sample the Compton scattering final state.
227 // D. Brusa et al., Nucl. Instrum. Meth. A 379 (1996) 167
228 // The model determines also the original shell from which the electron is expelled,
229 // in order to produce fluorescence de-excitation (from G4DeexcitationManager)
230 //
231 // The final state for Compton scattering is calculated according to the Klein-Nishina
232 // formula for energy > 5 MeV. In this case, the Doppler broadening is negligible and
233 // one can assume that the target electron is at rest.
234 // For E < 5 MeV it is used the parametrization for the differential cross-section dSigma/dOmega,
235 // to sample the scattering angle and the energy of the emerging electron, which is
236 // G4PenelopeComptonModel::DifferentialCrossSection(). The rejection method is
237 // used to sample cos(theta). The efficiency increases monotonically with photon energy and is
238 // nearly independent on the Z; typical values are 35%, 80% and 95% for 1 keV, 1 MeV and 10 MeV,
239 // respectively.
240 // The parametrization includes the J(p) distribution profiles for the atomic shells, that are
241 // tabulated
242 // from Hartree-Fock calculations from F. Biggs et al., At. Data Nucl. Data Tables 16 (1975) 201.
243 // Doppler broadening is included.
244 //
245
246 if (verboseLevel > 3)
247 G4cout << "Calling SampleSecondaries() of G4PenelopeComptonModel" << G4endl;
248
249 G4double photonEnergy0 = aDynamicGamma->GetKineticEnergy();
250
251 if (photonEnergy0 <= LowEnergyLimit())
252 {
253 fParticleChange->ProposeTrackStatus(fStopAndKill);
254 fParticleChange->SetProposedKineticEnergy(0.);
255 fParticleChange->ProposeLocalEnergyDeposit(photonEnergy0);
256 return ;
257 }
258
259 G4ParticleMomentum photonDirection0 = aDynamicGamma->GetMomentumDirection();
260
261 // Select randomly one element in the current material
262 if (verboseLevel > 2)
263 G4cout << "Going to select element in " << couple->GetMaterial()->GetName() << G4endl;
264 // atom can be selected effitiantly if element selectors are initialised
265 const G4Element* anElement = SelectRandomAtom(couple,G4Gamma::GammaDefinition(),photonEnergy0);
266 G4int Z = (G4int) anElement->GetZ();
267 if (verboseLevel > 2)
268 G4cout << "Selected " << anElement->GetName() << G4endl;
269
270 const G4int nmax = 64;
271 G4double rn[nmax],pac[nmax];
272
273 G4double ki,ki1,ki2,ki3,taumin,a1,a2;
274 G4double tau,TST;
275 G4double S=0.0;
276 G4double epsilon,cosTheta;
277 G4double harFunc = 0.0;
278 G4int occupNb= 0;
279 G4double ionEnergy=0.0;
280 G4int nosc = occupationNumber->find(Z)->second->size();
281 G4int iosc = nosc;
282 ki = photonEnergy0/electron_mass_c2;
283 ki2 = 2*ki+1.0;
284 ki3 = ki*ki;
285 ki1 = ki3-ki2-1.0;
286 taumin = 1.0/ki2;
287 a1 = std::log(ki2);
288 a2 = a1+2.0*ki*(1.0+ki)/(ki2*ki2);
289 //If the incoming photon is above 5 MeV, the quicker approach based on the
290 //pure Klein-Nishina formula is used
291 if (photonEnergy0 > 5*MeV)
292 {
293 do{
294 do{
295 if ((a2*G4UniformRand()) < a1)
296 {
297 tau = std::pow(taumin,G4UniformRand());
298 }
299 else
300 {
301 tau = std::sqrt(1.0+G4UniformRand()*(taumin*taumin-1.0));
302 }
303 //rejection function
304 TST = (1+tau*(ki1+tau*(ki2+tau*ki3)))/(ki3*tau*(1.0+tau*tau));
305 }while (G4UniformRand()> TST);
306 epsilon=tau;
307 cosTheta = 1.0 - (1.0-tau)/(ki*tau);
308 //Target shell electrons
309 TST = Z*G4UniformRand();
310 iosc = nosc;
311 S=0.0;
312 for (G4int j=0;j<nosc;j++)
313 {
314 occupNb = (G4int) (*(occupationNumber->find(Z)->second))[j];
315 S = S + occupNb;
316 if (S > TST) iosc = j;
317 if (S > TST) break;
318 }
319 ionEnergy = (*(ionizationEnergy->find(Z)->second))[iosc];
320 }while((epsilon*photonEnergy0-photonEnergy0+ionEnergy) >0);
321 }
322 else //photonEnergy0<5 MeV
323 {
324 //Incoherent scattering function for theta=PI
325 G4double s0=0.0;
326 G4double pzomc=0.0,rni=0.0;
327 G4double aux=0.0;
328 for (G4int i=0;i<nosc;i++){
329 ionEnergy = (*(ionizationEnergy->find(Z)->second))[i];
330 if (photonEnergy0 > ionEnergy)
331 {
332 G4double aux = photonEnergy0*(photonEnergy0-ionEnergy)*2.0;
333 harFunc = (*(hartreeFunction->find(Z)->second))[i]/fine_structure_const;
334 occupNb = (G4int) (*(occupationNumber->find(Z)->second))[i];
335 pzomc = harFunc*(aux-electron_mass_c2*ionEnergy)/
336 (electron_mass_c2*std::sqrt(2.0*aux+ionEnergy*ionEnergy));
337 if (pzomc > 0)
338 {
339 rni = 1.0-0.5*std::exp(0.5-(std::sqrt(0.5)+std::sqrt(2.0)*pzomc)*
340 (std::sqrt(0.5)+std::sqrt(2.0)*pzomc));
341 }
342 else
343 {
344 rni = 0.5*std::exp(0.5-(std::sqrt(0.5)-std::sqrt(2.0)*pzomc)*
345 (std::sqrt(0.5)-std::sqrt(2.0)*pzomc));
346 }
347 s0 = s0 + occupNb*rni;
348 }
349 }
350
351 //Sampling tau
352 G4double cdt1;
353 do
354 {
355 if ((G4UniformRand()*a2) < a1)
356 {
357 tau = std::pow(taumin,G4UniformRand());
358 }
359 else
360 {
361 tau = std::sqrt(1.0+G4UniformRand()*(taumin*taumin-1.0));
362 }
363 cdt1 = (1.0-tau)/(ki*tau);
364 S=0.0;
365 //Incoherent scattering function
366 for (G4int i=0;i<nosc;i++){
367 ionEnergy = (*(ionizationEnergy->find(Z)->second))[i];
368 if (photonEnergy0 > ionEnergy) //sum only on excitable levels
369 {
370 aux = photonEnergy0*(photonEnergy0-ionEnergy)*cdt1;
371 harFunc = (*(hartreeFunction->find(Z)->second))[i]/fine_structure_const;
372 occupNb = (G4int) (*(occupationNumber->find(Z)->second))[i];
373 pzomc = harFunc*(aux-electron_mass_c2*ionEnergy)/
374 (electron_mass_c2*std::sqrt(2.0*aux+ionEnergy*ionEnergy));
375 if (pzomc > 0)
376 {
377 rn[i] = 1.0-0.5*std::exp(0.5-(std::sqrt(0.5)+std::sqrt(2.0)*pzomc)*
378 (std::sqrt(0.5)+std::sqrt(2.0)*pzomc));
379 }
380 else
381 {
382 rn[i] = 0.5*std::exp(0.5-(std::sqrt(0.5)-std::sqrt(2.0)*pzomc)*
383 (std::sqrt(0.5)-std::sqrt(2.0)*pzomc));
384 }
385 S = S + occupNb*rn[i];
386 pac[i] = S;
387 }
388 else
389 {
390 pac[i] = S-(1e-06);
391 }
392 }
393 //Rejection function
394 TST = S*(1.0+tau*(ki1+tau*(ki2+tau*ki3)))/(ki3*tau*(1.0+tau*tau));
395 }while ((G4UniformRand()*s0) > TST);
396 //Target electron shell
397 cosTheta = 1.0 - cdt1;
398 G4double fpzmax=0.0,fpz=0.0;
399 G4double A=0.0;
400 do
401 {
402 do
403 {
404 TST =S*G4UniformRand();
405 iosc=nosc;
406 for (G4int i=0;i<nosc;i++){
407 if (pac[i]>TST) iosc = i;
408 if (pac[i]>TST) break;
409 }
410 A = G4UniformRand()*rn[iosc];
411 harFunc = (*(hartreeFunction->find(Z)->second))[iosc]/fine_structure_const;
412 occupNb = (G4int) (*(occupationNumber->find(Z)->second))[iosc];
413 if (A < 0.5) {
414 pzomc = (std::sqrt(0.5)-std::sqrt(0.5-std::log(2.0*A)))/
415 (std::sqrt(2.0)*harFunc);
416 }
417 else
418 {
419 pzomc = (std::sqrt(0.5-std::log(2.0-2.0*A))-std::sqrt(0.5))/
420 (std::sqrt(2.0)*harFunc);
421 }
422 } while (pzomc < -1);
423 // F(EP) rejection
424 G4double XQC = 1.0+tau*(tau-2.0*cosTheta);
425 G4double AF = std::sqrt(XQC)*(1.0+tau*(tau-cosTheta)/XQC);
426 if (AF > 0) {
427 fpzmax = 1.0+AF*0.2;
428 }
429 else
430 {
431 fpzmax = 1.0-AF*0.2;
432 }
433 fpz = 1.0+AF*std::max(std::min(pzomc,0.2),-0.2);
434 }while ((fpzmax*G4UniformRand())>fpz);
435
436 //Energy of the scattered photon
437 G4double T = pzomc*pzomc;
438 G4double b1 = 1.0-T*tau*tau;
439 G4double b2 = 1.0-T*tau*cosTheta;
440 if (pzomc > 0.0)
441 {
442 epsilon = (tau/b1)*(b2+std::sqrt(std::abs(b2*b2-b1*(1.0-T))));
443 }
444 else
445 {
446 epsilon = (tau/b1)*(b2-std::sqrt(std::abs(b2*b2-b1*(1.0-T))));
447 }
448 }
449
450
451 //Ok, the kinematics has been calculated.
452 G4double sinTheta = std::sqrt(1-cosTheta*cosTheta);
453 G4double phi = twopi * G4UniformRand() ;
454 G4double dirx = sinTheta * std::cos(phi);
455 G4double diry = sinTheta * std::sin(phi);
456 G4double dirz = cosTheta ;
457
458 // Update G4VParticleChange for the scattered photon
459 G4ThreeVector photonDirection1(dirx,diry,dirz);
460 photonDirection1.rotateUz(photonDirection0);
461 fParticleChange->ProposeMomentumDirection(photonDirection1) ;
462 G4double photonEnergy1 = epsilon * photonEnergy0;
463
464 if (photonEnergy1 > 0.)
465 {
466 fParticleChange->SetProposedKineticEnergy(photonEnergy1) ;
467 }
468 else
469 {
470 fParticleChange->SetProposedKineticEnergy(0.) ;
471 fParticleChange->ProposeTrackStatus(fStopAndKill);
472 }
473
474
475 //Create scattered electron
476 G4double diffEnergy = photonEnergy0*(1-epsilon);
477 ionEnergy = (*(ionizationEnergy->find(Z)->second))[iosc];
478 G4double Q2 = photonEnergy0*photonEnergy0+photonEnergy1*(photonEnergy1-2.0*photonEnergy0*cosTheta);
479 G4double cosThetaE; //scattering angle for the electron
480 if (Q2 > 1.0e-12)
481 {
482 cosThetaE = (photonEnergy0-photonEnergy1*cosTheta)/std::sqrt(Q2);
483 }
484 else
485 {
486 cosThetaE = 1.0;
487 }
488 G4double sinThetaE = std::sqrt(1-cosThetaE*cosThetaE);
489
490 //initialize here, then check photons created by Atomic-Deexcitation, and the final state e-
491 std::vector<G4DynamicParticle*>* photonVector=0;
492
493 const G4AtomicTransitionManager* transitionManager = G4AtomicTransitionManager::Instance();
494 const G4AtomicShell* shell = transitionManager->Shell(Z,iosc);
495 G4double bindingEnergy = shell->BindingEnergy();
496 G4int shellId = shell->ShellId();
497 G4double ionEnergyInPenelopeDatabase = ionEnergy;
498 ionEnergy = std::max(bindingEnergy,ionEnergyInPenelopeDatabase); //protection against energy non-conservation
499
500 G4double eKineticEnergy = diffEnergy - ionEnergy; //subtract the excitation energy. If not emitted by fluorescence,
501 //the ionization energy is deposited as local energy deposition
502 G4double localEnergyDeposit = ionEnergy;
503 G4double energyInFluorescence = 0.; //testing purposes only
504
505 if (eKineticEnergy < 0)
506 {
507 //It means that there was some problem/mismatch between the two databases. Try to make it work
508 //In this case available Energy (diffEnergy) < ionEnergy
509 //Full residual energy is deposited locally
510 localEnergyDeposit = diffEnergy;
511 eKineticEnergy = 0.0;
512 }
513 G4double cutForLowEnergySecondaryPhotons = 250.0*eV;
514
515 //Get the cut for electrons
516 const G4ProductionCutsTable* theCoupleTable=
517 G4ProductionCutsTable::GetProductionCutsTable();
518 size_t indx = couple->GetIndex();
519 G4double cutE = (*(theCoupleTable->GetEnergyCutsVector(1)))[indx];
520 cutE = std::max(cutForLowEnergySecondaryPhotons,cutE);
521
522 //the local energy deposit is what remains: part of this may be spent for fluorescence.
523 if (fUseAtomicDeexcitation)
524 {
525 G4int nPhotons=0;
526
527 G4double cutg = (*(theCoupleTable->GetEnergyCutsVector(0)))[indx];
528 cutg = std::max(cutForLowEnergySecondaryPhotons,cutg);
529
530 G4DynamicParticle* aPhoton;
531 G4AtomicDeexcitation deexcitationManager;
532
533 if (Z>5 && (localEnergyDeposit > cutg || localEnergyDeposit > cutE))
534 {
535 photonVector = deexcitationManager.GenerateParticles(Z,shellId);
536 for (size_t k=0;k<photonVector->size();k++){
537 aPhoton = (*photonVector)[k];
538 if (aPhoton)
539 {
540 G4double itsCut = cutg;
541 if (aPhoton->GetDefinition() == G4Electron::Electron()) itsCut = cutE;
542 G4double itsEnergy = aPhoton->GetKineticEnergy();
543 if (itsEnergy > itsCut && itsEnergy <= localEnergyDeposit)
544 {
545 nPhotons++;
546 localEnergyDeposit -= itsEnergy;
547 energyInFluorescence += itsEnergy;
548 }
549 else
550 {
551 delete aPhoton;
552 (*photonVector)[k]=0;
553 }
554 }
555 }
556 }
557 }
558
559 //Produce explicitely the electron only if its proposed kinetic energy is
560 //above the cut, otherwise add local energy deposition
561 G4DynamicParticle* electron = 0;
562 if (eKineticEnergy > cutE)
563 {
564 G4double xEl = sinThetaE * std::cos(phi+pi);
565 G4double yEl = sinThetaE * std::sin(phi+pi);
566 G4double zEl = cosThetaE;
567 G4ThreeVector eDirection(xEl,yEl,zEl); //electron direction
568 eDirection.rotateUz(photonDirection0);
569 electron = new G4DynamicParticle (G4Electron::Electron(),
570 eDirection,eKineticEnergy) ;
571 fvect->push_back(electron);
572 }
573 else
574 {
575 localEnergyDeposit += eKineticEnergy;
576 }
577
578 //This block below is executed only if there is at least one secondary photon produced by
579 //AtomicDeexcitation
580 if (photonVector)
581 {
582 for (size_t ll=0;ll<photonVector->size();ll++)
583 {
584 if ((*photonVector)[ll])
585 {
586 G4DynamicParticle* aFluorescencePhoton = (*photonVector)[ll];
587 fvect->push_back(aFluorescencePhoton);
588 }
589 }
590 }
591 delete photonVector;
592 if (localEnergyDeposit < 0)
593 {
594 G4cout << "WARNING-"
595 << "G4PenelopeComptonModel::SampleSecondaries - Negative energy deposit"
596 << G4endl;
597 localEnergyDeposit=0.;
598 }
599 fParticleChange->ProposeLocalEnergyDeposit(localEnergyDeposit);
600
601 G4double electronEnergy = 0.;
602 if (verboseLevel > 1)
603 {
604 G4cout << "-----------------------------------------------------------" << G4endl;
605 G4cout << "Energy balance from G4PenelopeCompton" << G4endl;
606 G4cout << "Incoming photon energy: " << photonEnergy0/keV << " keV" << G4endl;
607 G4cout << "-----------------------------------------------------------" << G4endl;
608 G4cout << "Scattered photon: " << photonEnergy1/keV << " keV" << G4endl;
609 if (electron)
610 electronEnergy = eKineticEnergy;
611 G4cout << "Scattered electron " << electronEnergy/keV << " keV" << G4endl;
612 G4cout << "Fluorescence: " << energyInFluorescence/keV << " keV" << G4endl;
613 G4cout << "Local energy deposit " << localEnergyDeposit/keV << " keV" << G4endl;
614 G4cout << "Total final state: " << (photonEnergy1+electronEnergy+energyInFluorescence+
615 localEnergyDeposit)/keV <<
616 " keV" << G4endl;
617 G4cout << "-----------------------------------------------------------" << G4endl;
618 }
619 if (verboseLevel > 0)
620 {
621 G4double energyDiff = std::fabs(photonEnergy1+
622 electronEnergy+energyInFluorescence+
623 localEnergyDeposit-photonEnergy0);
624 if (energyDiff > 0.05*keV)
625 G4cout << "Warning from G4PenelopeCompton: problem with energy conservation: " <<
626 (photonEnergy1+electronEnergy+energyInFluorescence+localEnergyDeposit)/keV <<
627 " keV (final) vs. " <<
628 photonEnergy0/keV << " keV (initial)" << G4endl;
629 }
630}
631
632//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
633
634void G4PenelopeComptonModel::ReadData()
635{
636 char* path = getenv("G4LEDATA");
637 if (!path)
638 {
639 G4String excep = "G4PenelopeComptonModel - G4LEDATA environment variable not set!";
640 G4Exception(excep);
641 }
642 G4String pathString(path);
643 G4String pathFile = pathString + "/penelope/compton-pen.dat";
644 std::ifstream file(pathFile);
645
646 if (!file.is_open())
647 {
648 G4String excep = "G4PenelopeComptonModel - data file " + pathFile + " not found!";
649 G4Exception(excep);
650 }
651
652 G4int k1,test,test1;
653 G4double a1,a2;
654 G4int Z=1,nLevels=0;
655
656 if (!ionizationEnergy || !hartreeFunction || !occupationNumber)
657 {
658 G4String excep = "G4PenelopeComptonModel: problem with reading data from file";
659 G4Exception(excep);
660 }
661
662 do{
663 G4double harOfElectronsBelowThreshold = 0;
664 G4int nbOfElectronsBelowThreshold = 0;
665 G4DataVector* occVector = new G4DataVector;
666 G4DataVector* harVector = new G4DataVector;
667 G4DataVector* bindingEVector = new G4DataVector;
668 file >> Z >> nLevels;
669 for (G4int h=0;h<nLevels;h++)
670 {
671 file >> k1 >> a1 >> a2;
672 //Make explicit unit of measurements for ionisation energy, which is MeV
673 a1 *= MeV;
674 if (a1 > 15*eV)
675 {
676 occVector->push_back((G4double) k1);
677 bindingEVector->push_back(a1);
678 harVector->push_back(a2);
679 }
680 else
681 {
682 nbOfElectronsBelowThreshold += k1;
683 harOfElectronsBelowThreshold += k1*a2;
684 }
685 }
686 //Add the "final" level
687 if (nbOfElectronsBelowThreshold)
688 {
689 occVector->push_back(nbOfElectronsBelowThreshold);
690 bindingEVector->push_back(0*eV);
691 G4double averageHartree =
692 harOfElectronsBelowThreshold/((G4double) nbOfElectronsBelowThreshold);
693 harVector->push_back(averageHartree);
694 }
695 //Ok, done for element Z
696 occupationNumber->insert(std::make_pair(Z,occVector));
697 ionizationEnergy->insert(std::make_pair(Z,bindingEVector));
698 hartreeFunction->insert(std::make_pair(Z,harVector));
699 file >> test >> test1; //-1 -1 close the data for each Z
700 if (test > 0) {
701 G4String excep = "G4PenelopeComptonModel - data file corrupted!";
702 G4Exception(excep);
703 }
704 }while (test != -2); //the very last Z is closed with -2 instead of -1
705 file.close();
706 if (verboseLevel > 2)
707 {
708 G4cout << "Data from G4PenelopeComptonModel read " << G4endl;
709 }
710}
711
712//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
713
714G4double G4PenelopeComptonModel::DifferentialCrossSection(G4double cosTheta)
715{
716 //
717 // Penelope model for the Compton scattering differential cross section
718 // dSigma/dOmega.
719 // D. Brusa et al., Nucl. Instrum. Meth. A 379 (1996) 167
720 // The parametrization includes the J(p) distribution profiles for the atomic shells,
721 // that are tabulated from Hartree-Fock calculations
722 // from F. Biggs et al., At. Data Nucl. Data Tables 16 (1975) 201
723 //
724 const G4double k2 = std::sqrt(2.0);
725 const G4double k1 = std::sqrt(0.5);
726 const G4double k12 = 0.5;
727 G4double cdt1 = 1.0-cosTheta;
728 G4double energy = energyForIntegration;
729 G4int Z = ZForIntegration;
730 //energy of Compton line;
731 G4double EOEC = 1.0+(energy/electron_mass_c2)*cdt1;
732 G4double ECOE = 1.0/EOEC;
733 //Incoherent scattering function (analytical profile)
734 G4double sia = 0.0;
735 G4int nosc = occupationNumber->find(Z)->second->size();
736 for (G4int i=0;i<nosc;i++){
737 G4double ionEnergy = (*(ionizationEnergy->find(Z)->second))[i];
738 //Sum only of those shells for which E>Eion
739 if (energy > ionEnergy)
740 {
741 G4double aux = energy * (energy-ionEnergy)*cdt1;
742 G4double Pzimax =
743 (aux - electron_mass_c2*ionEnergy)/(electron_mass_c2*std::sqrt(2*aux+ionEnergy*ionEnergy));
744 G4double harFunc = (*(hartreeFunction->find(Z)->second))[i]/fine_structure_const;
745 G4int occupNb = (G4int) (*(occupationNumber->find(Z)->second))[i];
746 G4double x = harFunc*Pzimax;
747 G4double siap = 0;
748 if (x > 0)
749 {
750 siap = 1.0-0.5*std::exp(k12-(k1+k2*x)*(k1+k2*x));
751 }
752 else
753 {
754 siap = 0.5*std::exp(k12-(k1-k2*x)*(k1-k2*x));
755 }
756 sia = sia + occupNb*siap; //sum of all contributions;
757 }
758 }
759 G4double XKN = EOEC+ECOE-1+cosTheta*cosTheta;
760 G4double diffCS = pi*classic_electr_radius*classic_electr_radius*ECOE*ECOE*XKN*sia;
761 return diffCS;
762}
763
Note: See TracBrowser for help on using the repository browser.