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

Last change on this file since 1058 was 1055, checked in by garnier, 17 years ago

maj sur la beta de geant 4.9.3

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