File indexing completed on 2025-09-16 08:52:16
0001
0002
0003
0004
0005
0006
0007 #pragma once
0008
0009 #include "corecel/Macros.hh"
0010 #include "corecel/Types.hh"
0011 #include "corecel/math/Algorithms.hh"
0012 #include "corecel/random/distribution/RejectionSampler.hh"
0013 #include "corecel/random/distribution/UniformRealDistribution.hh"
0014 #include "celeritas/Quantities.hh"
0015
0016 namespace celeritas
0017 {
0018
0019
0020
0021
0022
0023
0024 class MollerEnergyDistribution
0025 {
0026 public:
0027
0028
0029 using Mass = units::MevMass;
0030 using Energy = units::MevEnergy;
0031
0032
0033 public:
0034
0035 inline CELER_FUNCTION MollerEnergyDistribution(Mass electron_mass,
0036 Energy min_valid_energy,
0037 Energy inc_energy);
0038
0039
0040 template<class Engine>
0041 inline CELER_FUNCTION real_type operator()(Engine& rng);
0042
0043 private:
0044
0045
0046
0047 real_type min_energy_fraction_;
0048
0049 real_type gamma_;
0050
0051
0052
0053
0054 inline CELER_FUNCTION real_type calc_g_fraction(real_type epsilon);
0055
0056 static CELER_CONSTEXPR_FUNCTION real_type max_energy_fraction()
0057 {
0058 return 0.5;
0059 }
0060 };
0061
0062
0063
0064
0065
0066
0067
0068 CELER_FUNCTION
0069 MollerEnergyDistribution::MollerEnergyDistribution(Mass electron_mass,
0070 Energy min_valid_energy,
0071 Energy inc_energy)
0072 : min_energy_fraction_(value_as<Energy>(min_valid_energy)
0073 / value_as<Energy>(inc_energy))
0074 , gamma_(1 + value_as<Energy>(inc_energy) / value_as<Mass>(electron_mass))
0075 {
0076 CELER_EXPECT(electron_mass > zero_quantity()
0077 && inc_energy > zero_quantity());
0078 }
0079
0080
0081
0082
0083
0084 template<class Engine>
0085 CELER_FUNCTION real_type MollerEnergyDistribution::operator()(Engine& rng)
0086 {
0087 real_type const g_denominator
0088 = this->calc_g_fraction(this->max_energy_fraction());
0089
0090 UniformRealDistribution<> sample_inverse_epsilon(
0091 1 / this->max_energy_fraction(), 1 / min_energy_fraction_);
0092
0093
0094 real_type epsilon;
0095 do
0096 {
0097 epsilon = 1 / sample_inverse_epsilon(rng);
0098 } while (RejectionSampler<>(calc_g_fraction(epsilon), g_denominator)(rng));
0099
0100 return epsilon;
0101 }
0102
0103
0104
0105
0106
0107 CELER_FUNCTION real_type
0108 MollerEnergyDistribution::calc_g_fraction(real_type epsilon)
0109 {
0110 real_type const two_gamma_term = (2 * gamma_ - 1) / ipow<2>(gamma_);
0111 real_type const complement_frac = 1 - epsilon;
0112
0113 return 1 - two_gamma_term * epsilon
0114 + ipow<2>(epsilon)
0115 * (1 - two_gamma_term
0116 + (1 - two_gamma_term * complement_frac)
0117 / ipow<2>(complement_frac));
0118 }
0119
0120
0121 }