Geant4 9.6.0
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
G4eBremsstrahlungModel.cc
Go to the documentation of this file.
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$
27//
28// -------------------------------------------------------------------
29//
30// GEANT4 Class file
31//
32//
33// File name: G4eBremsstrahlungModel
34//
35// Author: Vladimir Ivanchenko on base of Laszlo Urban code
36//
37// Creation date: 03.01.2002
38//
39// Modifications:
40//
41// 11-11-02 Fix division by 0 (V.Ivanchenko)
42// 04-12-02 Change G4DynamicParticle constructor in PostStep (V.Ivanchenko)
43// 23-12-02 Change interface in order to move to cut per region (V.Ivanchenko)
44// 24-01-03 Fix for compounds (V.Ivanchenko)
45// 27-01-03 Make models region aware (V.Ivanchenko)
46// 13-02-03 Add name (V.Ivanchenko)
47// 09-05-03 Fix problem of supression function + optimise sampling (V.Ivanchenko)
48// 20-05-04 Correction to ensure unit independence (L.Urban)
49// 08-04-05 Major optimisation of internal interfaces (V.Ivantchenko)
50// 03-08-05 Add extra protection at initialisation (V.Ivantchenko)
51// 07-02-06 public function ComputeCrossSectionPerAtom() (mma)
52// 21-03-06 Fix problem of initialisation in case when cuts are not defined (VI)
53// 27-03-06 Fix calculation of fl parameter at low energy (energy loss) (VI)
54// 15-02-07 correct LPMconstant by a factor 2, thanks to G. Depaola (mma)
55// 09-09-08 MigdalConstant increased in (2pi)^2 times (A.Schaelicke)
56// 13-10-10 Add angular distributon interface (VI)
57//
58// Class Description:
59//
60//
61// -------------------------------------------------------------------
62//
63//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
64//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
65
68#include "G4SystemOfUnits.hh"
69#include "G4Electron.hh"
70#include "G4Positron.hh"
71#include "G4Gamma.hh"
72#include "Randomize.hh"
73#include "G4Material.hh"
74#include "G4Element.hh"
75#include "G4ElementVector.hh"
77#include "G4DataVector.hh"
79#include "G4ModifiedTsai.hh"
80
81//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
82
83using namespace std;
84
86 const G4String& nam)
87 : G4VEmModel(nam),
88 particle(0),
89 isElectron(true),
90 probsup(1.0),
91 MigdalConstant(classic_electr_radius*electron_Compton_length*electron_Compton_length*4.0*pi),
92 LPMconstant(fine_structure_const*electron_mass_c2*electron_mass_c2/(4.*pi*hbarc)),
93 isInitialised(false)
94{
95 if(p) { SetParticle(p); }
98 highKinEnergy = HighEnergyLimit();
99 lowKinEnergy = LowEnergyLimit();
100 fParticleChange = 0;
101}
102
103//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
104
106{
107 size_t n = partialSumSigma.size();
108 if(n > 0) {
109 for(size_t i=0; i<n; i++) {
110 delete partialSumSigma[i];
111 }
112 }
113}
114
115//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
116
117void G4eBremsstrahlungModel::SetParticle(const G4ParticleDefinition* p)
118{
119 particle = p;
120 if(p == G4Electron::Electron()) { isElectron = true; }
121 else { isElectron = false;}
122}
123
124//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
125
127 const G4DataVector& cuts)
128{
129 if(p) { SetParticle(p); }
130 highKinEnergy = HighEnergyLimit();
131 lowKinEnergy = LowEnergyLimit();
132 const G4ProductionCutsTable* theCoupleTable=
134
135 if(theCoupleTable) {
136 G4int numOfCouples = theCoupleTable->GetTableSize();
137
138 G4int nn = partialSumSigma.size();
139 G4int nc = cuts.size();
140 if(nn > 0) {
141 for (G4int ii=0; ii<nn; ii++){
142 G4DataVector* a=partialSumSigma[ii];
143 if ( a ) delete a;
144 }
145 partialSumSigma.clear();
146 }
147 if(numOfCouples>0) {
148 for (G4int i=0; i<numOfCouples; i++) {
149 G4double cute = DBL_MAX;
150 if(i < nc) cute = cuts[i];
151 const G4MaterialCutsCouple* couple = theCoupleTable->GetMaterialCutsCouple(i);
152 const G4Material* material = couple->GetMaterial();
153 G4DataVector* dv = ComputePartialSumSigma(material, 0.5*highKinEnergy,
154 std::min(cute, 0.25*highKinEnergy));
155 partialSumSigma.push_back(dv);
156 }
157 }
158 }
159 if(isInitialised) return;
161 isInitialised = true;
162}
163
164//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
165
167 const G4Material* material,
168 const G4ParticleDefinition* p,
169 G4double kineticEnergy,
170 G4double cutEnergy)
171{
172 if(!particle) { SetParticle(p); }
173 if(kineticEnergy < lowKinEnergy) { return 0.0; }
174
175 const G4double thigh = 100.*GeV;
176
177 G4double cut = std::min(cutEnergy, kineticEnergy);
178
179 G4double rate, loss;
180 const G4double factorHigh = 36./(1450.*GeV);
181 const G4double coef1 = -0.5;
182 const G4double coef2 = 2./9.;
183
184 const G4ElementVector* theElementVector = material->GetElementVector();
185 const G4double* theAtomicNumDensityVector = material->GetAtomicNumDensityVector();
186
187 G4double totalEnergy = kineticEnergy + electron_mass_c2;
188 G4double dedx = 0.0;
189
190 // loop for elements in the material
191 for (size_t i=0; i<material->GetNumberOfElements(); i++) {
192
193 G4double Z = (*theElementVector)[i]->GetZ();
194 G4double natom = theAtomicNumDensityVector[i];
195
196 // loss for MinKinEnergy<KineticEnergy<=100 GeV
197 if (kineticEnergy <= thigh) {
198
199 // x = log(totalEnergy/electron_mass_c2);
200 loss = ComputeBremLoss(Z, kineticEnergy, cut) ;
201 if (!isElectron) loss *= PositronCorrFactorLoss(Z, kineticEnergy, cut);
202
203 // extrapolation for KineticEnergy>100 GeV
204 } else {
205
206 // G4double xhigh = log(thigh/electron_mass_c2);
207 G4double cuthigh = thigh*0.5;
208
209 if (cut < thigh) {
210
211 loss = ComputeBremLoss(Z, thigh, cut) ;
212 if (!isElectron) loss *= PositronCorrFactorLoss(Z, thigh, cut) ;
213 rate = cut/totalEnergy;
214 loss *= (1. + coef1*rate + coef2*rate*rate);
215 rate = cut/thigh;
216 loss /= (1.+coef1*rate+coef2*rate*rate);
217
218 } else {
219
220 loss = ComputeBremLoss(Z, thigh, cuthigh) ;
221 if (!isElectron) loss *= PositronCorrFactorLoss(Z, thigh, cuthigh) ;
222 rate = cut/totalEnergy;
223 loss *= (1. + coef1*rate + coef2*rate*rate);
224 loss *= cut*factorHigh;
225 }
226 }
227 loss *= natom;
228
229 G4double kp2 = MigdalConstant*totalEnergy*totalEnergy
230 * (material->GetElectronDensity()) ;
231
232 // now compute the correction due to the supression(s)
233 G4double kmin = 1.*eV;
234 G4double kmax = cut;
235
236 if (kmax > kmin) {
237
238 G4double floss = 0.;
239 G4int nmax = 100;
240
241 G4double vmin=log(kmin);
242 G4double vmax=log(kmax) ;
243 G4int nn = (G4int)(nmax*(vmax-vmin)/(log(highKinEnergy)-vmin)) ;
244 G4double u,fac,c,v,dv ;
245 if(nn > 0) {
246
247 dv = (vmax-vmin)/nn ;
248 v = vmin-dv ;
249
250 for(G4int n=0; n<=nn; n++) {
251
252 v += dv;
253 u = exp(v);
254 fac = u*SupressionFunction(material,kineticEnergy,u);
255 fac *= probsup*(u*u/(u*u+kp2))+1.-probsup;
256 if ((n==0)||(n==nn)) c=0.5;
257 else c=1. ;
258 fac *= c ;
259 floss += fac ;
260 }
261 floss *=dv/(kmax-kmin);
262
263 } else {
264 floss = 1.;
265 }
266 if(floss > 1.) floss = 1.;
267 // correct the loss
268 loss *= floss;
269 }
270 dedx += loss;
271 }
272 if(dedx < 0.) { dedx = 0.; }
273 return dedx;
274}
275
276//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
277
278G4double G4eBremsstrahlungModel::ComputeBremLoss(G4double Z, G4double T,
279 G4double Cut)
280
281// compute loss due to soft brems
282{
283 static const G4double beta=1.0, ksi=2.0;
284 static const G4double clossh = 0.254 , closslow = 1./3. , alosslow = 1. ;
285 static const G4double Tlim= 10.*MeV ;
286
287 static const G4double xlim = 1.2 ;
288 static const G4int NZ = 8 ;
289 static const G4int Nloss = 11 ;
290 static const G4double ZZ[NZ] =
291 {2.,4.,6.,14.,26.,50.,82.,92.};
292 static const G4double coefloss[NZ][Nloss] = {
293 // Z=2
294 { 0.98916, 0.47564, -0.2505, -0.45186, 0.14462,
295 0.21307, -0.013738, -0.045689, -0.0042914, 0.0034429,
296 0.00064189},
297
298 // Z=4
299 { 1.0626, 0.37662, -0.23646, -0.45188, 0.14295,
300 0.22906, -0.011041, -0.051398, -0.0055123, 0.0039919,
301 0.00078003},
302 // Z=6
303 { 1.0954, 0.315, -0.24011, -0.43849, 0.15017,
304 0.23001, -0.012846, -0.052555, -0.0055114, 0.0041283,
305 0.00080318},
306
307 // Z=14
308 { 1.1649, 0.18976, -0.24972, -0.30124, 0.1555,
309 0.13565, -0.024765, -0.027047, -0.00059821, 0.0019373,
310 0.00027647},
311
312 // Z=26
313 { 1.2261, 0.14272, -0.25672, -0.28407, 0.13874,
314 0.13586, -0.020562, -0.026722, -0.00089557, 0.0018665,
315 0.00026981},
316
317 // Z=50
318 { 1.3147, 0.020049, -0.35543, -0.13927, 0.17666,
319 0.073746, -0.036076, -0.013407, 0.0025727, 0.00084005,
320 -1.4082e-05},
321
322 // Z=82
323 { 1.3986, -0.10586, -0.49187, -0.0048846, 0.23621,
324 0.031652, -0.052938, -0.0076639, 0.0048181, 0.00056486,
325 -0.00011995},
326
327 // Z=92
328 { 1.4217, -0.116, -0.55497, -0.044075, 0.27506,
329 0.081364, -0.058143, -0.023402, 0.0031322, 0.0020201,
330 0.00017519}
331
332 } ;
333 static G4double aaa = 0.414;
334 static G4double bbb = 0.345;
335 static G4double ccc = 0.460;
336
337 G4int iz = 0;
338 G4double delz = 1.e6;
339 for (G4int ii=0; ii<NZ; ii++)
340 {
341 G4double dz = std::abs(Z-ZZ[ii]);
342 if(dz < delz) {
343 iz = ii;
344 delz = dz;
345 }
346 }
347
348 G4double xx = log10(T/MeV);
349 G4double fl = 1.;
350
351 if (xx <= xlim)
352 {
353 xx /= xlim;
354 G4double yy = 1.0;
355 fl = 0.0;
356 for (G4int j=0; j<Nloss; j++) {
357 fl += yy+coefloss[iz][j];
358 yy *= xx;
359 }
360 if (fl < 0.00001) fl = 0.00001;
361 else if (fl > 1.0) fl = 1.0;
362 }
363
364 G4double loss;
365 G4double E = T+electron_mass_c2 ;
366
367 loss = Z*(Z+ksi)*E*E/(T+E)*exp(beta*log(Cut/T))*(2.-clossh*exp(log(Z)/4.));
368 if (T <= Tlim) loss /= exp(closslow*log(Tlim/T));
369 if( T <= Cut) loss *= exp(alosslow*log(T/Cut));
370 // correction
371 loss *= (aaa+bbb*T/Tlim)/(1.+ccc*T/Tlim);
372 loss *= fl;
373 loss /= Avogadro;
374
375 return loss;
376}
377
378//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
379
380G4double G4eBremsstrahlungModel::PositronCorrFactorLoss(G4double Z,
381 G4double kineticEnergy, G4double cut)
382
383//calculates the correction factor for the energy loss due to bremsstrahlung for positrons
384//the same correction is in the (discrete) bremsstrahlung
385
386{
387 static const G4double K = 132.9416*eV ;
388 static const G4double a1=4.15e-1, a3=2.10e-3, a5=54.0e-5 ;
389
390 G4double x = log(kineticEnergy/(K*Z*Z)), x2 = x*x, x3 = x2*x;
391 G4double eta = 0.5+atan(a1*x+a3*x3+a5*x3*x2)/pi;
392 G4double e0 = cut/kineticEnergy;
393
394 G4double factor = 0.0;
395 if (e0 < 1.0) {
396 factor=log(1.-e0)/eta;
397 factor=exp(factor);
398 }
399 factor = eta*(1.-factor)/e0;
400
401 return factor;
402}
403
404//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
405
407 const G4Material* material,
408 const G4ParticleDefinition* p,
409 G4double kineticEnergy,
410 G4double cutEnergy,
411 G4double maxEnergy)
412{
413 if(!particle) { SetParticle(p); }
414 G4double cross = 0.0;
415 G4double tmax = min(maxEnergy, kineticEnergy);
416 G4double cut = min(cutEnergy, kineticEnergy);
417 if(cut >= tmax) { return cross; }
418
419 const G4ElementVector* theElementVector = material->GetElementVector();
420 const G4double* theAtomNumDensityVector = material->GetAtomicNumDensityVector();
421 G4double dum=0.;
422
423 for (size_t i=0; i<material->GetNumberOfElements(); i++) {
424
425 cross += theAtomNumDensityVector[i] * ComputeCrossSectionPerAtom(p,
426 kineticEnergy, (*theElementVector)[i]->GetZ(), dum, cut);
427 if (tmax < kineticEnergy) {
428 cross -= theAtomNumDensityVector[i] * ComputeCrossSectionPerAtom(p,
429 kineticEnergy, (*theElementVector)[i]->GetZ(), dum, tmax);
430 }
431 }
432
433 // now compute the correction due to the supression(s)
434
435 G4double kmax = tmax;
436 G4double kmin = cut;
437
438 G4double totalEnergy = kineticEnergy+electron_mass_c2 ;
439 G4double kp2 = MigdalConstant*totalEnergy*totalEnergy
440 *(material->GetElectronDensity());
441
442 G4double fsig = 0.;
443 G4int nmax = 100;
444 G4double vmin=log(kmin);
445 G4double vmax=log(kmax) ;
446 G4int nn = (G4int)(nmax*(vmax-vmin)/(log(highKinEnergy)-vmin));
447 G4double u,fac,c,v,dv,y ;
448 if(nn > 0) {
449
450 dv = (vmax-vmin)/nn ;
451 v = vmin-dv ;
452 for(G4int n=0; n<=nn; n++) {
453
454 v += dv;
455 u = exp(v);
456 fac = SupressionFunction(material, kineticEnergy, u);
457 y = u/kmax;
458 fac *= (4.-4.*y+3.*y*y)/3.;
459 fac *= probsup*(u*u/(u*u+kp2))+1.-probsup;
460
461 if ((n==0)||(n==nn)) c=0.5;
462 else c=1. ;
463
464 fac *= c;
465 fsig += fac;
466 }
467 y = kmin/kmax ;
468 fsig *=dv/(-4.*log(y)/3.-4.*(1.-y)/3.+0.5*(1.-y*y));
469
470 } else {
471
472 fsig = 1.;
473 }
474 if (fsig > 1.) fsig = 1.;
475
476 // correct the cross section
477 cross *= fsig;
478
479 return cross;
480}
481
482//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
483
486 G4double kineticEnergy,
488 G4double cut, G4double)
489
490// Calculates the cross section per atom in GEANT4 internal units.
491//
492
493{
494 G4double cross = 0.0 ;
495 if ( kineticEnergy < keV || kineticEnergy < cut) { return cross; }
496
497 static const G4double ksi=2.0, alfa=1.00;
498 static const G4double csigh = 0.127, csiglow = 0.25, asiglow = 0.020*MeV ;
499 static const G4double Tlim = 10.*MeV ;
500
501 static const G4double xlim = 1.2 ;
502 static const G4int NZ = 8 ;
503 static const G4int Nsig = 11 ;
504 static const G4double ZZ[NZ] =
505 {2.,4.,6.,14.,26.,50.,82.,92.} ;
506 static const G4double coefsig[NZ][Nsig] = {
507 // Z=2
508 { 0.4638, 0.37748, 0.32249, -0.060362, -0.065004,
509 -0.033457, -0.004583, 0.011954, 0.0030404, -0.0010077,
510 -0.00028131},
511
512 // Z=4
513 { 0.50008, 0.33483, 0.34364, -0.086262, -0.055361,
514 -0.028168, -0.0056172, 0.011129, 0.0027528, -0.00092265,
515 -0.00024348},
516
517 // Z=6
518 { 0.51587, 0.31095, 0.34996, -0.11623, -0.056167,
519 -0.0087154, 0.00053943, 0.0054092, 0.00077685, -0.00039635,
520 -6.7818e-05},
521
522 // Z=14
523 { 0.55058, 0.25629, 0.35854, -0.080656, -0.054308,
524 -0.049933, -0.00064246, 0.016597, 0.0021789, -0.001327,
525 -0.00025983},
526
527 // Z=26
528 { 0.5791, 0.26152, 0.38953, -0.17104, -0.099172,
529 0.024596, 0.023718, -0.0039205, -0.0036658, 0.00041749,
530 0.00023408},
531
532 // Z=50
533 { 0.62085, 0.27045, 0.39073, -0.37916, -0.18878,
534 0.23905, 0.095028, -0.068744, -0.023809, 0.0062408,
535 0.0020407},
536
537 // Z=82
538 { 0.66053, 0.24513, 0.35404, -0.47275, -0.22837,
539 0.35647, 0.13203, -0.1049, -0.034851, 0.0095046,
540 0.0030535},
541
542 // Z=92
543 { 0.67143, 0.23079, 0.32256, -0.46248, -0.20013,
544 0.3506, 0.11779, -0.1024, -0.032013, 0.0092279,
545 0.0028592}
546
547 } ;
548
549 G4int iz = 0 ;
550 G4double delz = 1.e6 ;
551 for (G4int ii=0; ii<NZ; ii++)
552 {
553 G4double absdelz = std::abs(Z-ZZ[ii]);
554 if(absdelz < delz)
555 {
556 iz = ii ;
557 delz = absdelz;
558 }
559 }
560
561 G4double xx = log10(kineticEnergy/MeV);
562 G4double fs = 1. ;
563
564 if (xx <= xlim) {
565
566 fs = coefsig[iz][Nsig-1] ;
567 for (G4int j=Nsig-2; j>=0; j--) {
568
569 fs = fs*xx+coefsig[iz][j] ;
570 }
571 if(fs < 0.) { fs = 0.; }
572 }
573
574 cross = Z*(Z+ksi)*(1.-csigh*exp(log(Z)/4.))*pow(log(kineticEnergy/cut),alfa);
575
576 if (kineticEnergy <= Tlim)
577 cross *= exp(csiglow*log(Tlim/kineticEnergy))
578 *(1.+asiglow/(sqrt(Z)*kineticEnergy));
579
580 if (!isElectron)
581 cross *= PositronCorrFactorSigma(Z, kineticEnergy, cut);
582
583 cross *= fs/Avogadro ;
584
585 if (cross < 0.) { cross = 0.; }
586 return cross;
587}
588
589//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
590
591G4double G4eBremsstrahlungModel::PositronCorrFactorSigma( G4double Z,
592 G4double kineticEnergy, G4double cut)
593
594//Calculates the correction factor for the total cross section of the positron
595// bremsstrahl.
596// Eta is the ratio of positron to electron energy loss by bremstrahlung.
597// A parametrized formula from L. Urban is used to estimate eta. It is a fit to
598// the results of L. Kim & al: Phys Rev. A33,3002 (1986)
599
600{
601 static const G4double K = 132.9416*eV;
602 static const G4double a1 = 4.15e-1, a3 = 2.10e-3, a5 = 54.0e-5;
603
604 G4double x = log(kineticEnergy/(K*Z*Z));
605 G4double x2 = x*x;
606 G4double x3 = x2*x;
607 G4double eta = 0.5 + atan(a1*x + a3*x3 + a5*x3*x2)/pi ;
608 G4double alfa = (1. - eta)/eta;
609 return eta*pow((1. - cut/kineticEnergy), alfa);
610}
611
612//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
613
614G4DataVector* G4eBremsstrahlungModel::ComputePartialSumSigma(
615 const G4Material* material,
616 G4double kineticEnergy,
617 G4double cut)
618
619// Build the table of cross section per element.
620//The table is built for MATERIALS.
621// This table is used by DoIt to select randomly an element in the material.
622{
623 G4int nElements = material->GetNumberOfElements();
624 const G4ElementVector* theElementVector = material->GetElementVector();
625 const G4double* theAtomNumDensityVector = material->GetAtomicNumDensityVector();
626 G4double dum = 0.;
627
628 G4DataVector* dv = new G4DataVector();
629
630 G4double cross = 0.0;
631
632 for (G4int i=0; i<nElements; i++ ) {
633
634 cross += theAtomNumDensityVector[i] * ComputeCrossSectionPerAtom( particle,
635 kineticEnergy, (*theElementVector)[i]->GetZ(), dum, cut);
636 dv->push_back(cross);
637 }
638 return dv;
639}
640
641//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
642
643void G4eBremsstrahlungModel::SampleSecondaries(std::vector<G4DynamicParticle*>* vdp,
644 const G4MaterialCutsCouple* couple,
645 const G4DynamicParticle* dp,
646 G4double tmin,
647 G4double maxEnergy)
648// The emitted gamma energy is sampled using a parametrized formula
649// from L. Urban.
650// This parametrization is derived from :
651// cross-section values of Seltzer and Berger for electron energies
652// 1 keV - 10 GeV,
653// screened Bethe Heilter differential cross section above 10 GeV,
654// Migdal corrections in both case.
655// Seltzer & Berger: Nim B 12:95 (1985)
656// Nelson, Hirayama & Rogers: Technical report 265 SLAC (1985)
657// Migdal: Phys Rev 103:1811 (1956); Messel & Crawford: Pergamon Press (1970)
658//
659// A modified version of the random number techniques of Butcher&Messel is used
660// (Nuc Phys 20(1960),15).
661{
662 G4double kineticEnergy = dp->GetKineticEnergy();
663 G4double tmax = min(maxEnergy, kineticEnergy);
664 if(tmin >= tmax) { return; }
665
666//
667// GEANT4 internal units.
668//
669 static const G4double
670 ah10 = 4.67733E+00, ah11 =-6.19012E-01, ah12 = 2.02225E-02,
671 ah20 =-7.34101E+00, ah21 = 1.00462E+00, ah22 =-3.20985E-02,
672 ah30 = 2.93119E+00, ah31 =-4.03761E-01, ah32 = 1.25153E-02;
673
674 static const G4double
675 bh10 = 4.23071E+00, bh11 =-6.10995E-01, bh12 = 1.95531E-02,
676 bh20 =-7.12527E+00, bh21 = 9.69160E-01, bh22 =-2.74255E-02,
677 bh30 = 2.69925E+00, bh31 =-3.63283E-01, bh32 = 9.55316E-03;
678
679 static const G4double
680 al00 =-2.05398E+00, al01 = 2.38815E-02, al02 = 5.25483E-04,
681 al10 =-7.69748E-02, al11 =-6.91499E-02, al12 = 2.22453E-03,
682 al20 = 4.06463E-02, al21 =-1.01281E-02, al22 = 3.40919E-04;
683
684 static const G4double
685 bl00 = 1.04133E+00, bl01 =-9.43291E-03, bl02 =-4.54758E-04,
686 bl10 = 1.19253E-01, bl11 = 4.07467E-02, bl12 =-1.30718E-03,
687 bl20 =-1.59391E-02, bl21 = 7.27752E-03, bl22 =-1.94405E-04;
688
689 static const G4double tlow = 1.*MeV;
690
691 G4double gammaEnergy;
692 G4bool LPMOK = false;
693 const G4Material* material = couple->GetMaterial();
694
695 // select randomly one element constituing the material
696 const G4Element* anElement = SelectRandomAtom(couple);
697
698 // Extract Z factors for this Element
699 G4double lnZ = 3.*(anElement->GetIonisation()->GetlogZ3());
700 G4double FZ = lnZ* (4.- 0.55*lnZ);
701 G4double ZZ = anElement->GetIonisation()->GetZZ3();
702
703 // limits of the energy sampling
704 G4double totalEnergy = kineticEnergy + electron_mass_c2;
705
706 G4double xmin = tmin/kineticEnergy;
707 G4double xmax = tmax/kineticEnergy;
708 G4double kappa = 0.0;
709 if(xmax >= 1.) { xmax = 1.; }
710 else { kappa = log(xmax)/log(xmin); }
711 G4double epsilmin = tmin/totalEnergy;
712 G4double epsilmax = tmax/totalEnergy;
713
714 // Migdal factor
715 G4double MigdalFactor = (material->GetElectronDensity())*MigdalConstant
716 / (epsilmax*epsilmax);
717
718 G4double x, epsil, greject, migdal, grejmax, q;
719 G4double U = log(kineticEnergy/electron_mass_c2);
720 G4double U2 = U*U;
721
722 // precalculated parameters
723 G4double ah, bh;
724 G4double screenfac = 0.0;
725
726 if (kineticEnergy > tlow) {
727
728 G4double ah1 = ah10 + ZZ* (ah11 + ZZ* ah12);
729 G4double ah2 = ah20 + ZZ* (ah21 + ZZ* ah22);
730 G4double ah3 = ah30 + ZZ* (ah31 + ZZ* ah32);
731
732 G4double bh1 = bh10 + ZZ* (bh11 + ZZ* bh12);
733 G4double bh2 = bh20 + ZZ* (bh21 + ZZ* bh22);
734 G4double bh3 = bh30 + ZZ* (bh31 + ZZ* bh32);
735
736 ah = 1. + (ah1*U2 + ah2*U + ah3) / (U2*U);
737 bh = 0.75 + (bh1*U2 + bh2*U + bh3) / (U2*U);
738
739 // limit of the screening variable
740 screenfac =
741 136.*electron_mass_c2/((anElement->GetIonisation()->GetZ3())*totalEnergy);
742 G4double screenmin = screenfac*epsilmin/(1.-epsilmin);
743
744 // Compute the maximum of the rejection function
745 G4double F1 = max(ScreenFunction1(screenmin) - FZ ,0.);
746 G4double F2 = max(ScreenFunction2(screenmin) - FZ ,0.);
747 grejmax = (F1 - epsilmin* (F1*ah - bh*epsilmin*F2))/(42.392 - FZ);
748
749 } else {
750
751 G4double al0 = al00 + ZZ* (al01 + ZZ* al02);
752 G4double al1 = al10 + ZZ* (al11 + ZZ* al12);
753 G4double al2 = al20 + ZZ* (al21 + ZZ* al22);
754
755 G4double bl0 = bl00 + ZZ* (bl01 + ZZ* bl02);
756 G4double bl1 = bl10 + ZZ* (bl11 + ZZ* bl12);
757 G4double bl2 = bl20 + ZZ* (bl21 + ZZ* bl22);
758
759 ah = al0 + al1*U + al2*U2;
760 bh = bl0 + bl1*U + bl2*U2;
761
762 // Compute the maximum of the rejection function
763 grejmax = max(1. + xmin* (ah + bh*xmin), 1.+ah+bh);
764 G4double xm = -ah/(2.*bh);
765 if ( xmin < xm && xm < xmax) grejmax = max(grejmax, 1.+ xm* (ah + bh*xm));
766 }
767
768 //
769 // sample the energy rate of the emitted gamma for e- kin energy > 1 MeV
770 //
771
772 do {
773 if (kineticEnergy > tlow) {
774 do {
775 q = G4UniformRand();
776 x = pow(xmin, q + kappa*(1.0 - q));
777 epsil = x*kineticEnergy/totalEnergy;
778 G4double screenvar = screenfac*epsil/(1.0-epsil);
779 G4double F1 = max(ScreenFunction1(screenvar) - FZ ,0.);
780 G4double F2 = max(ScreenFunction2(screenvar) - FZ ,0.);
781 migdal = (1. + MigdalFactor)/(1. + MigdalFactor/(x*x));
782 greject = migdal*(F1 - epsil* (ah*F1 - bh*epsil*F2))/(42.392 - FZ);
783 /*
784 if ( greject > grejmax ) {
785 G4cout << "### G4eBremsstrahlungModel Warning: Majoranta exceeded! "
786 << greject << " > " << grejmax
787 << " x= " << x
788 << " e= " << kineticEnergy
789 << G4endl;
790 }
791 */
792 } while( greject < G4UniformRand()*grejmax );
793
794 } else {
795
796 do {
797 q = G4UniformRand();
798 x = pow(xmin, q + kappa*(1.0 - q));
799 migdal = (1. + MigdalFactor)/(1. + MigdalFactor/(x*x));
800 greject = migdal*(1. + x* (ah + bh*x));
801 /*
802 if ( greject > grejmax ) {
803 G4cout << "### G4eBremsstrahlungModel Warning: Majoranta exceeded! "
804 << greject << " > " << grejmax
805 << " x= " << x
806 << " e= " << kineticEnergy
807 << G4endl;
808 }
809 */
810 } while( greject < G4UniformRand()*grejmax );
811 }
812 gammaEnergy = x*kineticEnergy;
813
814 if (LPMFlag()) {
815 // take into account the supression due to the LPM effect
816 if (G4UniformRand() <= SupressionFunction(material,kineticEnergy,
817 gammaEnergy))
818 LPMOK = true;
819 }
820 else LPMOK = true;
821
822 } while (!LPMOK);
823
824 //
825 // angles of the emitted gamma. ( Z - axis along the parent particle)
826 // use general interface
827 //
828
829 G4ThreeVector gammaDirection =
830 GetAngularDistribution()->SampleDirection(dp, totalEnergy-gammaEnergy,
831 G4lrint(anElement->GetZ()),
832 couple->GetMaterial());
833
834 // create G4DynamicParticle object for the Gamma
835 G4DynamicParticle* gamma = new G4DynamicParticle(theGamma,gammaDirection,
836 gammaEnergy);
837 vdp->push_back(gamma);
838
839 G4double totMomentum = sqrt(kineticEnergy*(totalEnergy + electron_mass_c2));
840
841 G4ThreeVector direction = (totMomentum*dp->GetMomentumDirection()
842 - gammaEnergy*gammaDirection).unit();
843
844 // energy of primary
845 G4double finalE = kineticEnergy - gammaEnergy;
846
847 // stop tracking and create new secondary instead of primary
848 if(gammaEnergy > SecondaryThreshold()) {
851 G4DynamicParticle* el =
853 direction, finalE);
854 vdp->push_back(el);
855
856 // continue tracking
857 } else {
860 }
861}
862
863//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
864
866 const G4MaterialCutsCouple* couple)
867{
868 // select randomly 1 element within the material
869
870 const G4Material* material = couple->GetMaterial();
871 G4int nElements = material->GetNumberOfElements();
872 const G4ElementVector* theElementVector = material->GetElementVector();
873
874 const G4Element* elm = 0;
875
876 if(1 < nElements) {
877
878 --nElements;
879 G4DataVector* dv = partialSumSigma[couple->GetIndex()];
880 G4double rval = G4UniformRand()*((*dv)[nElements]);
881
882 elm = (*theElementVector)[nElements];
883 for (G4int i=0; i<nElements; ++i) {
884 if (rval <= (*dv)[i]) {
885 elm = (*theElementVector)[i];
886 break;
887 }
888 }
889 } else { elm = (*theElementVector)[0]; }
890
892 return elm;
893}
894
895//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
896
897G4double G4eBremsstrahlungModel::SupressionFunction(const G4Material* material,
898 G4double kineticEnergy, G4double gammaEnergy)
899{
900 // supression due to the LPM effect+polarisation of the medium/
901 // supression due to the polarisation alone
902
903
904 G4double totEnergy = kineticEnergy+electron_mass_c2 ;
905 G4double totEnergySquare = totEnergy*totEnergy ;
906
907 G4double LPMEnergy = LPMconstant*(material->GetRadlen()) ;
908
909 G4double gammaEnergySquare = gammaEnergy*gammaEnergy ;
910
911 G4double electronDensity = material->GetElectronDensity();
912
913 G4double sp = gammaEnergySquare/
914 (gammaEnergySquare+MigdalConstant*totEnergySquare*electronDensity);
915
916 G4double supr = 1.0;
917
918 if (LPMFlag()) {
919
920 G4double s2lpm = LPMEnergy*gammaEnergy/totEnergySquare;
921
922 if (s2lpm < 1.) {
923
924 G4double LPMgEnergyLimit = totEnergySquare/LPMEnergy ;
925 G4double LPMgEnergyLimit2 = LPMgEnergyLimit*LPMgEnergyLimit;
926 G4double splim = LPMgEnergyLimit2/
927 (LPMgEnergyLimit2+MigdalConstant*totEnergySquare*electronDensity);
928 G4double w = 1.+1./splim ;
929
930 if ((1.-sp) < 1.e-6) w = s2lpm*(3.-sp);
931 else w = s2lpm*(1.+1./sp);
932
933 supr = (sqrt(w*w+4.*s2lpm)-w)/(sqrt(w*w+4.)-w) ;
934 supr /= sp;
935 }
936
937 }
938 return supr;
939}
940
941//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
942
943
std::vector< G4Element * > G4ElementVector
@ fStopAndKill
double G4double
Definition: G4Types.hh:64
int G4int
Definition: G4Types.hh:66
bool G4bool
Definition: G4Types.hh:67
#define G4UniformRand()
Definition: Randomize.hh:53
const G4ThreeVector & GetMomentumDirection() const
G4double GetKineticEnergy() const
static G4Electron * Electron()
Definition: G4Electron.cc:94
G4double GetZ() const
Definition: G4Element.hh:131
G4IonisParamElm * GetIonisation() const
Definition: G4Element.hh:209
static G4Gamma * Gamma()
Definition: G4Gamma.cc:86
G4double GetlogZ3() const
G4double GetZ3() const
G4double GetZZ3() const
const G4Material * GetMaterial() const
const G4ElementVector * GetElementVector() const
Definition: G4Material.hh:189
size_t GetNumberOfElements() const
Definition: G4Material.hh:185
const G4double * GetAtomicNumDensityVector() const
Definition: G4Material.hh:215
G4double GetElectronDensity() const
Definition: G4Material.hh:216
G4double GetRadlen() const
Definition: G4Material.hh:219
void SetProposedKineticEnergy(G4double proposedKinEnergy)
void SetProposedMomentumDirection(const G4ThreeVector &dir)
const G4MaterialCutsCouple * GetMaterialCutsCouple(G4int i) const
static G4ProductionCutsTable * GetProductionCutsTable()
virtual G4ThreeVector & SampleDirection(const G4DynamicParticle *dp, G4double finalTotalEnergy, G4int Z, const G4Material *)=0
G4VEmAngularDistribution * GetAngularDistribution()
Definition: G4VEmModel.hh:508
G4double LowEnergyLimit() const
Definition: G4VEmModel.hh:529
G4double HighEnergyLimit() const
Definition: G4VEmModel.hh:522
void SetCurrentElement(const G4Element *)
Definition: G4VEmModel.hh:384
G4bool LPMFlag() const
Definition: G4VEmModel.hh:564
void SetAngularDistribution(G4VEmAngularDistribution *)
Definition: G4VEmModel.hh:515
G4double SecondaryThreshold() const
Definition: G4VEmModel.hh:557
G4ParticleChangeForLoss * GetParticleChangeForLoss()
Definition: G4VEmModel.cc:95
void ProposeTrackStatus(G4TrackStatus status)
G4eBremsstrahlungModel(const G4ParticleDefinition *p=0, const G4String &nam="eBrem")
virtual G4double ComputeCrossSectionPerAtom(const G4ParticleDefinition *, G4double tkin, G4double Z, G4double, G4double cut, G4double maxE=DBL_MAX)
virtual void SampleSecondaries(std::vector< G4DynamicParticle * > *, const G4MaterialCutsCouple *, const G4DynamicParticle *, G4double tmin, G4double maxEnergy)
virtual G4double ComputeDEDXPerVolume(const G4Material *, const G4ParticleDefinition *, G4double kineticEnergy, G4double cutEnergy)
G4ParticleChangeForLoss * fParticleChange
virtual void Initialise(const G4ParticleDefinition *, const G4DataVector &)
virtual G4double CrossSectionPerVolume(const G4Material *, const G4ParticleDefinition *, G4double kineticEnergy, G4double cutEnergy, G4double maxEnergy)
const G4Element * SelectRandomAtom(const G4MaterialCutsCouple *couple)
G4ParticleDefinition * theGamma
const G4ParticleDefinition * particle
const G4double pi
int G4lrint(double ad)
Definition: templates.hh:163
#define DBL_MAX
Definition: templates.hh:83