Geant4 11.1.1
Toolkit for the simulation of the passage of particles through matter
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
G4DNAScreenedRutherfordElasticModel.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//
27
30#include "G4SystemOfUnits.hh"
32#include "G4Exp.hh"
33#include "G4Log.hh"
34
35//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
36
37using namespace std;
38
39//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
40
43 const G4String& nam) :
44G4VEmModel(nam), isInitialised(false)
45{
46 fpWaterDensity = 0;
47
48 lowEnergyLimit = 0 * eV;
49 intermediateEnergyLimit = 200 * eV; // Switch between two final state models
50 highEnergyLimit = 1. * MeV;
51
52 SetLowEnergyLimit(lowEnergyLimit);
53 SetHighEnergyLimit(highEnergyLimit);
54
55 verboseLevel = 0;
56 // Verbosity scale:
57 // 0 = nothing
58 // 1 = warning for energy non-conservation
59 // 2 = details of energy budget
60 // 3 = calculation of cross sections, file openings, sampling of atoms
61 // 4 = entering in methods
62
63#ifdef SR_VERBOSE
64 if (verboseLevel > 0)
65 {
66 G4cout << "Screened Rutherford Elastic model is constructed "
67 << G4endl
68 << "Energy range: "
69 << lowEnergyLimit / eV << " eV - "
70 << highEnergyLimit / MeV << " MeV"
71 << G4endl;
72 }
73#endif
75
76 // Selection of computation method
77 // We do not recommend "true" usage with the current cumul. proba. settings
78 fasterCode = false;
79}
80
81//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
82
84{
85}
86
87//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
88
90Initialise(const G4ParticleDefinition* particle,
91 const G4DataVector& /*cuts*/)
92{
93#ifdef SR_VERBOSE
94 if (verboseLevel > 3)
95 {
96 G4cout << "Calling G4DNAScreenedRutherfordElasticModel::Initialise()"
97 << G4endl;
98 }
99#endif
100
101 if(particle->GetParticleName() != "e-")
102 {
103 G4Exception ("*** WARNING: the G4DNAScreenedRutherfordElasticModel is not "
104 "intented to be used with another particle than the electron",
105 "",FatalException,"") ;
106 }
107
108 // Energy limits
109 if (LowEnergyLimit() < 9*eV)
110 {
111 G4Exception("*** WARNING: the G4DNAScreenedRutherfordElasticModel class is "
112 "not validated below 9 eV",
113 "",JustWarning,"") ;
114 }
115
116 if (HighEnergyLimit() > 1*MeV)
117 {
118 G4Exception("*** WARNING: the G4DNAScreenedRutherfordElasticModel class is "
119 "not validated above 1 MeV",
120 "",JustWarning,"") ;
121 }
122
123 //
124#ifdef SR_VERBOSE
125 if( verboseLevel>0 )
126 {
127 G4cout << "Screened Rutherford elastic model is initialized " << G4endl
128 << "Energy range: "
129 << LowEnergyLimit() / eV << " eV - "
130 << HighEnergyLimit() / MeV << " MeV"
131 << G4endl;
132 }
133#endif
134
135 if (isInitialised) { return; } // return here, prevent reinit consts + pointer
136
137 // Initialize water density pointer
138 fpWaterDensity = G4DNAMolecularMaterial::Instance()->
139 GetNumMolPerVolTableFor(G4Material::GetMaterial("G4_WATER"));
140
142 isInitialised = true;
143
144 // Constants for final state by Brenner & Zaider
145 // note: if called after if(isInitialised) no need for clear and resetting
146 // the values at every call
147
148 betaCoeff=
149 {
150 7.51525,
151 -0.41912,
152 7.2017E-3,
153 -4.646E-5,
154 1.02897E-7};
155
156 deltaCoeff=
157 {
158 2.9612,
159 -0.26376,
160 4.307E-3,
161 -2.6895E-5,
162 5.83505E-8};
163
164 gamma035_10Coeff =
165 {
166 -1.7013,
167 -1.48284,
168 0.6331,
169 -0.10911,
170 8.358E-3,
171 -2.388E-4};
172
173 gamma10_100Coeff =
174 {
175 -3.32517,
176 0.10996,
177 -4.5255E-3,
178 5.8372E-5,
179 -2.4659E-7};
180
181 gamma100_200Coeff =
182 {
183 2.4775E-2,
184 -2.96264E-5,
185 -1.20655E-7};
186}
187
188//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
189
191CrossSectionPerVolume(const G4Material* material,
192#ifdef SR_VERBOSE
193 const G4ParticleDefinition* particleDefinition,
194#else
196#endif
197 G4double ekin,
198 G4double,
199 G4double)
200{
201#ifdef SR_VERBOSE
202 if (verboseLevel > 3)
203 {
204 G4cout << "Calling CrossSectionPerVolume() of "
205 "G4DNAScreenedRutherfordElasticModel"
206 << G4endl;
207 }
208#endif
209
210 // Calculate total cross section for model
211
212 G4double sigma=0.;
213 G4double waterDensity = (*fpWaterDensity)[material->GetIndex()];
214
215 if(ekin <= HighEnergyLimit() && ekin >= LowEnergyLimit())
216 {
217 G4double z = 10.;
218 G4double n = ScreeningFactor(ekin,z);
219 G4double crossSection = RutherfordCrossSection(ekin, z);
220 sigma = pi * crossSection / (n * (n + 1.));
221 }
222
223#ifdef SR_VERBOSE
224 if (verboseLevel > 2)
225 {
226 G4cout << "__________________________________" << G4endl;
227 G4cout << "=== G4DNAScreenedRutherfordElasticModel - XS INFO START"
228 << G4endl;
229 G4cout << "=== Kinetic energy(eV)=" << ekin/eV
230 << " particle : " << particleDefinition->GetParticleName()
231 << G4endl;
232 G4cout << "=== Cross section per water molecule (cm^2)=" << sigma/cm/cm
233 << G4endl;
234 G4cout << "=== Cross section per water molecule (cm^-1)="
235 << sigma*waterDensity/(1./cm) << G4endl;
236 G4cout << "=== G4DNAScreenedRutherfordElasticModel - XS INFO END"
237 << G4endl;
238 }
239#endif
240
241 return sigma*waterDensity;
242}
243
244//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
245
246G4double G4DNAScreenedRutherfordElasticModel::RutherfordCrossSection(G4double k,
247 G4double z)
248{
249 //
250 // e^4 / K + m_e c^2 \^2
251 // sigma_Ruth(K) = Z (Z+1) -------------------- | --------------------- |
252 // (4 pi epsilon_0)^2 \ K * (K + 2 m_e c^2) /
253 //
254 // Where K is the electron non-relativistic kinetic energy
255 //
256 // NIM 155, pp. 145-156, 1978
257
258 G4double length = (e_squared * (k + electron_mass_c2))
259 / (4 * pi * epsilon0 * k * (k + 2 * electron_mass_c2));
260 G4double cross = z * (z + 1) * length * length;
261
262 return cross;
263}
264
265//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
266
267G4double G4DNAScreenedRutherfordElasticModel::ScreeningFactor(G4double k,
268 G4double z)
269{
270 //
271 // alpha_1 + beta_1 ln(K/eV) constK Z^(2/3)
272 // n(T) = -------------------------- -----------------
273 // K/(m_e c^2) 2 + K/(m_e c^2)
274 //
275 // Where K is the electron non-relativistic kinetic energy
276 //
277 // n(T) > 0 for T < ~ 400 MeV
278 //
279 // NIM 155, pp. 145-156, 1978
280 // Formulae (2) and (5)
281
282 const G4double alpha_1(1.64);
283 const G4double beta_1(-0.0825);
284 const G4double constK(1.7E-5);
285
286 G4double numerator = (alpha_1 + beta_1 * G4Log(k / eV)) * constK
287 * std::pow(z, 2. / 3.);
288
289 k /= electron_mass_c2;
290
291 G4double denominator = k * (2 + k);
292
293 G4double value = 0.;
294 if (denominator > 0.) value = numerator / denominator;
295
296 return value;
297}
298
299//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
300
302SampleSecondaries(std::vector<G4DynamicParticle*>* /*fvect*/,
303 const G4MaterialCutsCouple* /*couple*/,
304 const G4DynamicParticle* aDynamicElectron,
305 G4double,
306 G4double)
307{
308#ifdef SR_VERBOSE
309 if (verboseLevel > 3)
310 {
311 G4cout << "Calling SampleSecondaries() of "
312 "G4DNAScreenedRutherfordElasticModel"
313 << G4endl;
314 }
315#endif
316
317 G4double electronEnergy0 = aDynamicElectron->GetKineticEnergy();
318 G4double cosTheta = 0.;
319
320 if (electronEnergy0<intermediateEnergyLimit)
321 {
322#ifdef SR_VERBOSE
323 if (verboseLevel > 3)
324 {G4cout << "---> Using Brenner & Zaider model" << G4endl;}
325#endif
326 cosTheta = BrennerZaiderRandomizeCosTheta(electronEnergy0);
327 }
328
329 if (electronEnergy0>=intermediateEnergyLimit)
330 {
331#ifdef SR_VERBOSE
332 if (verboseLevel > 3)
333 {G4cout << "---> Using Screened Rutherford model" << G4endl;}
334#endif
335 G4double z = 10.;
336 cosTheta = ScreenedRutherfordRandomizeCosTheta(electronEnergy0,z);
337 }
338
339 G4double phi = 2. * pi * G4UniformRand();
340
341 G4ThreeVector zVers = aDynamicElectron->GetMomentumDirection();
342 G4ThreeVector xVers = zVers.orthogonal();
343 G4ThreeVector yVers = zVers.cross(xVers);
344
345 G4double xDir = std::sqrt(1. - cosTheta*cosTheta);
346 G4double yDir = xDir;
347 xDir *= std::cos(phi);
348 yDir *= std::sin(phi);
349
350 G4ThreeVector zPrimeVers((xDir*xVers + yDir*yVers + cosTheta*zVers));
351
353
355}
356
357//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
358
359G4double G4DNAScreenedRutherfordElasticModel::
360BrennerZaiderRandomizeCosTheta(G4double k)
361{
362 // d sigma_el 1 beta(K)
363 // ------------ (K) ~ --------------------------------- + ---------------------------------
364 // d Omega (1 + 2 gamma(K) - cos(theta))^2 (1 + 2 delta(K) + cos(theta))^2
365 //
366 // Maximum is < 1/(4 gamma(K)^2) + beta(K)/((2+2delta(K))^2)
367 //
368 // Phys. Med. Biol. 29 N.4 (1983) 443-447
369
370 // gamma(K), beta(K) and delta(K) are polynomials with coefficients for energy measured in eV
371
372 k /= eV;
373
374 G4double beta = G4Exp(CalculatePolynomial(k, betaCoeff));
375 G4double delta = G4Exp(CalculatePolynomial(k, deltaCoeff));
376 G4double gamma;
377
378 if (k > 100.)
379 {
380 gamma = CalculatePolynomial(k, gamma100_200Coeff);
381 // Only in this case it is not the exponent of the polynomial
382 }
383 else
384 {
385 if (k > 10)
386 {
387 gamma = G4Exp(CalculatePolynomial(k, gamma10_100Coeff));
388 }
389 else
390 {
391 gamma = G4Exp(CalculatePolynomial(k, gamma035_10Coeff));
392 }
393 }
394
395 // ***** Original method
396
397 if (!fasterCode)
398 {
399
400 G4double oneOverMax = 1.
401 / (1. / (4. * gamma * gamma) + beta
402 / ((2. + 2. * delta) * (2. + 2. * delta)));
403
404 G4double cosTheta = 0.;
405 G4double leftDenominator = 0.;
406 G4double rightDenominator = 0.;
407 G4double fCosTheta = 0.;
408
409 do
410 {
411 cosTheta = 2. * G4UniformRand()- 1.;
412
413 leftDenominator = (1. + 2.*gamma - cosTheta);
414 rightDenominator = (1. + 2.*delta + cosTheta);
415 if ( (leftDenominator * rightDenominator) != 0. )
416 {
417 fCosTheta = oneOverMax * (1./(leftDenominator*leftDenominator)
418 + beta/(rightDenominator*rightDenominator));
419 }
420 }
421 while (fCosTheta < G4UniformRand());
422
423 return cosTheta;
424 }
425
426 // ***** Alternative method using cumulative probability
427
428 if (fasterCode)
429 {
430
431 //
432 // modified by Shogo OKADA @ KEK, JP, 2016.2.27(Sat.)
433 //
434 // An integral of differential cross-section formula shown above this member function
435 // (integral variable: cos(theta), integral interval: [-1, x]) is as follows:
436 //
437 // 1.0 + x beta * (1 + x)
438 // I = --------------------- + ---------------------- (1)
439 // (a - x) * (a + 1.0) (b + x) * (b - 1.0)
440 //
441 // where a = 1.0 + 2.0 * gamma(K), b = 1.0 + 2.0 * delta(K)
442 //
443 // Then, a cumulative probability (cp) is as follows:
444 //
445 // cp 1.0 + x beta * (1 + x)
446 // ---- = --------------------- + ---------------------- (2)
447 // S (a - x) * (a + 1.0) (b + x) * (b - 1.0)
448 //
449 // where 1/S is the integral of differnetical cross-section (1) on interval [-1, 1]
450 //
451 // 1 2.0 2.0 * beta
452 // --- = ----------------------- + ----------------------- (3)
453 // S (a - 1.0) * (a + 1.0) (b + 1.0) * (b - 1.0)
454 //
455 // x is calculated from the quadratic equation derived from (2) and (3):
456 //
457 // A * x^2 + B * x + C = 0
458 //
459 // where A, B, anc C are coefficients of the equation:
460 // A = S * {(b - 1.0) - beta * (a + 1.0)} + cp * (a + 1.0) * (b - 1.0),
461 // B = S * {(b - 1.0) * (b + 1.0) + beta * (a - 1.0) * (a + 1.0)} - cp * (a + 1.0) * (b - 1.0) * (a - b)
462 // C = S * {b * (b - 1.0) + beta * a * (a + 1.0)} - cp * (a + 1.0) * (b - 1.0) * ab
463 //
464
465 // sampling cumulative probability
466 G4double cp = G4UniformRand();
467
468 G4double a = 1.0 + 2.0 * gamma;
469 G4double b = 1.0 + 2.0 * delta;
470 G4double a1 = a - 1.0;
471 G4double a2 = a + 1.0;
472 G4double b1 = b - 1.0;
473 G4double b2 = b + 1.0;
474 G4double c1 = a - b;
475 G4double c2 = a * b;
476
477 G4double S = 2.0 / (a1 * a2) + 2.0 * beta / (b1 * b2); S = 1.0 / S;
478
479 // coefficients for the quadratic equation
480 G4double A = S * (b1 - beta * a2) + cp * a2 * b1;
481 G4double B = S * (b1 * b2 + beta * a1 * a2) - cp * a2 * b1 * c1;
482 G4double C = S * (b * b1 + beta * a * a2) - cp * a2 * b1 * c2;
483
484 // calculate cos(theta)
485 return (-1.0 * B + std::sqrt(B * B - 4.0 * A * C)) / (2.0 * A);
486
487 /*
488 G4double cosTheta = -1;
489 G4double cumul = 0;
490 G4double value = 0;
491 G4double leftDenominator = 0.;
492 G4double rightDenominator = 0.;
493
494 // Number of integration steps in the -1,1 range
495 G4int iMax=200;
496
497 G4double random = G4UniformRand();
498
499 // Cumulate differential cross section
500 for (G4int i=0; i<iMax; i++)
501 {
502 cosTheta = -1 + i*2./(iMax-1);
503 leftDenominator = (1. + 2.*gamma - cosTheta);
504 rightDenominator = (1. + 2.*delta + cosTheta);
505 if ( (leftDenominator * rightDenominator) != 0. )
506 {
507 cumul = cumul + (1./(leftDenominator*leftDenominator) + beta/(rightDenominator*rightDenominator));
508 }
509 }
510
511 // Select cosTheta
512 for (G4int i=0; i<iMax; i++)
513 {
514 cosTheta = -1 + i*2./(iMax-1);
515 leftDenominator = (1. + 2.*gamma - cosTheta);
516 rightDenominator = (1. + 2.*delta + cosTheta);
517 if (cumul !=0 && (leftDenominator * rightDenominator) != 0.)
518 value = value + (1./(leftDenominator*leftDenominator) + beta/(rightDenominator*rightDenominator)) / cumul;
519 if (random < value) break;
520 }
521
522 return cosTheta;
523 */
524 }
525
526 return 0.;
527}
528
529//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
530
531G4double G4DNAScreenedRutherfordElasticModel::
532CalculatePolynomial(G4double k,
533 std::vector<G4double>& vec)
534{
535 // Sum_{i=0}^{size-1} vector_i k^i
536 //
537 // Phys. Med. Biol. 29 N.4 (1983) 443-447
538
539 G4double result = 0.;
540 size_t size = vec.size();
541
542 while (size > 0)
543 {
544 size--;
545
546 result *= k;
547 result += vec[size];
548 }
549
550 return result;
551}
552
553//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
554
555G4double G4DNAScreenedRutherfordElasticModel::
556ScreenedRutherfordRandomizeCosTheta(G4double k,
557 G4double z)
558{
559
560 // d sigma_el sigma_Ruth(K)
561 // ------------ (K) ~ -----------------------------
562 // d Omega (1 + 2 n(K) - cos(theta))^2
563 //
564 // We extract cos(theta) distributed as (1 + 2 n(K) - cos(theta))^-2
565 //
566 // Maximum is for theta=0: 1/(4 n(K)^2) (When n(K) is positive, that is always satisfied within the validity of the process)
567 //
568 // Phys. Med. Biol. 45 (2000) 3171-3194
569
570 // ***** Original method
571
572 if (!fasterCode)
573 {
574
575 G4double n = ScreeningFactor(k, z);
576
577 G4double oneOverMax = (4. * n * n);
578
579 G4double cosTheta = 0.;
580 G4double fCosTheta;
581
582 do
583 {
584 cosTheta = 2. * G4UniformRand()- 1.;
585 fCosTheta = (1 + 2.*n - cosTheta);
586 if (fCosTheta !=0.) fCosTheta = oneOverMax / (fCosTheta*fCosTheta);
587 }
588 while (fCosTheta < G4UniformRand());
589
590 return cosTheta;
591 }
592
593 // ***** Alternative method using cumulative probability
594 else
595 {
596
597 //
598 // modified by Shogo OKADA @ KEK, JP, 2016.2.27(Sat.)
599 //
600 // The cumulative probability (cp) is calculated by integrating
601 // the differential cross-section fomula with cos(theta):
602 //
603 // n(K) * (1.0 + cos(theta))
604 // cp = ---------------------------------
605 // 1.0 + 2.0 * n(K) - cos(theta)
606 //
607 // Then, cos(theta) is as follows:
608 //
609 // cp * (1.0 + 2.0 * n(K)) - n(K)
610 // cos(theta) = --------------------------------
611 // n(k) + cp
612 //
613 // where, K is kinetic energy, n(K) is screeing factor, and cp is cumulative probability
614 //
615
616 G4double n = ScreeningFactor(k, z);
617 G4double cp = G4UniformRand();
618 G4double numerator = cp * (1.0 + 2.0 * n) - n;
619 G4double denominator = n + cp;
620 return numerator / denominator;
621
622 /*
623 G4double cosTheta = -1;
624 G4double cumul = 0;
625 G4double value = 0;
626 G4double n = ScreeningFactor(k, z);
627 G4double fCosTheta;
628
629 // Number of integration steps in the -1,1 range
630 G4int iMax=200;
631
632 G4double random = G4UniformRand();
633
634 // Cumulate differential cross section
635 for (G4int i=0; i<iMax; i++)
636 {
637 cosTheta = -1 + i*2./(iMax-1);
638 fCosTheta = (1 + 2.*n - cosTheta);
639 if (fCosTheta !=0.) cumul = cumul + 1./(fCosTheta*fCosTheta);
640 }
641
642 // Select cosTheta
643 for (G4int i=0; i<iMax; i++)
644 {
645 cosTheta = -1 + i*2./(iMax-1);
646 fCosTheta = (1 + 2.*n - cosTheta);
647 if (cumul !=0.) value = value + (1./(fCosTheta*fCosTheta)) / cumul;
648 if (random < value) break;
649 }
650 return cosTheta;
651 */
652 }
653
654 //return 0.;
655}
656
657
G4double S(G4double temp)
G4double B(G4double temperature)
@ JustWarning
@ FatalException
void G4Exception(const char *originOfException, const char *exceptionCode, G4ExceptionSeverity severity, const char *description)
Definition: G4Exception.cc:59
G4double G4Exp(G4double initial_x)
Exponential Function double precision.
Definition: G4Exp.hh:180
G4double G4Log(G4double x)
Definition: G4Log.hh:227
double G4double
Definition: G4Types.hh:83
const G4double A[17]
#define G4endl
Definition: G4ios.hh:57
G4GLOB_DLL std::ostream G4cout
#define G4UniformRand()
Definition: Randomize.hh:52
Hep3Vector unit() const
Hep3Vector orthogonal() const
Hep3Vector cross(const Hep3Vector &) const
static G4DNAMolecularMaterial * Instance()
virtual void Initialise(const G4ParticleDefinition *, const G4DataVector &)
G4DNAScreenedRutherfordElasticModel(const G4ParticleDefinition *p=0, const G4String &nam="DNAScreenedRutherfordElasticModel")
virtual void SampleSecondaries(std::vector< G4DynamicParticle * > *, const G4MaterialCutsCouple *, const G4DynamicParticle *, G4double tmin, G4double maxEnergy)
virtual G4double CrossSectionPerVolume(const G4Material *material, const G4ParticleDefinition *p, G4double ekin, G4double emin, G4double emax)
const G4ThreeVector & GetMomentumDirection() const
G4double GetKineticEnergy() const
size_t GetIndex() const
Definition: G4Material.hh:255
static G4Material * GetMaterial(const G4String &name, G4bool warning=true)
Definition: G4Material.cc:691
void SetProposedKineticEnergy(G4double proposedKinEnergy)
void ProposeMomentumDirection(const G4ThreeVector &Pfinal)
const G4String & GetParticleName() const
void SetHighEnergyLimit(G4double)
Definition: G4VEmModel.hh:746
G4ParticleChangeForGamma * GetParticleChangeForGamma()
Definition: G4VEmModel.cc:124
G4double LowEnergyLimit() const
Definition: G4VEmModel.hh:641
G4double HighEnergyLimit() const
Definition: G4VEmModel.hh:634
void SetLowEnergyLimit(G4double)
Definition: G4VEmModel.hh:753