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