File indexing completed on 2025-02-22 10:31:16
0001
0002
0003
0004
0005
0006
0007
0008 #pragma once
0009
0010 #include <cmath>
0011
0012 #include "corecel/Macros.hh"
0013 #include "corecel/Types.hh"
0014 #include "corecel/math/Algorithms.hh"
0015 #include "celeritas/Quantities.hh"
0016 #include "celeritas/phys/ParticleTrackView.hh"
0017 #include "celeritas/random/distribution/InverseSquareDistribution.hh"
0018 #include "celeritas/random/distribution/RejectionSampler.hh"
0019
0020 #include "detail/Utils.hh"
0021
0022 namespace celeritas
0023 {
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049 class MuBBEnergyDistribution
0050 {
0051 public:
0052
0053
0054 using Energy = units::MevEnergy;
0055 using Mass = units::MevMass;
0056
0057
0058 public:
0059
0060 inline CELER_FUNCTION
0061 MuBBEnergyDistribution(ParticleTrackView const& particle,
0062 Energy electron_cutoff,
0063 Mass electron_mass);
0064
0065
0066 template<class Engine>
0067 inline CELER_FUNCTION Energy operator()(Engine& rng);
0068
0069
0070 CELER_FUNCTION Energy min_secondary_energy() const { return min_energy_; }
0071
0072
0073 CELER_FUNCTION Energy max_secondary_energy() const { return max_energy_; }
0074
0075 private:
0076
0077
0078
0079 real_type inc_mass_;
0080
0081 real_type total_energy_;
0082
0083 real_type beta_sq_;
0084
0085 real_type electron_mass_;
0086
0087 Energy min_energy_;
0088
0089 Energy max_energy_;
0090
0091 bool use_rad_correction_;
0092
0093 real_type envelope_;
0094
0095
0096
0097
0098 static CELER_CONSTEXPR_FUNCTION Energy rad_correction_limit()
0099 {
0100 return units::MevEnergy{250};
0101 }
0102
0103
0104 static CELER_CONSTEXPR_FUNCTION Energy kin_energy_limit()
0105 {
0106
0107
0108 return units::MevEnergy{0.1};
0109 }
0110
0111
0112 static CELER_CONSTEXPR_FUNCTION real_type alpha_over_twopi()
0113 {
0114 return constants::alpha_fine_structure / (2 * constants::pi);
0115 }
0116
0117
0118
0119 inline CELER_FUNCTION real_type calc_envelope_distribution() const;
0120 };
0121
0122
0123
0124
0125
0126
0127
0128 CELER_FUNCTION
0129 MuBBEnergyDistribution::MuBBEnergyDistribution(ParticleTrackView const& particle,
0130 Energy electron_cutoff,
0131 Mass electron_mass)
0132 : inc_mass_(value_as<Mass>(particle.mass()))
0133 , total_energy_(value_as<Energy>(particle.total_energy()))
0134 , beta_sq_(particle.beta_sq())
0135 , electron_mass_(value_as<Mass>(electron_mass))
0136 , min_energy_(electron_cutoff)
0137 , max_energy_(detail::calc_max_secondary_energy(particle, electron_mass))
0138 , use_rad_correction_(particle.energy() > rad_correction_limit()
0139 && max_energy_ > kin_energy_limit())
0140 , envelope_(this->calc_envelope_distribution())
0141 {
0142 }
0143
0144
0145
0146
0147
0148 template<class Engine>
0149 CELER_FUNCTION auto MuBBEnergyDistribution::operator()(Engine& rng) -> Energy
0150 {
0151 InverseSquareDistribution sample_energy(value_as<Energy>(min_energy_),
0152 value_as<Energy>(max_energy_));
0153 real_type energy;
0154 real_type target;
0155 do
0156 {
0157 energy = sample_energy(rng);
0158 target = 1 - (beta_sq_ / value_as<Energy>(max_energy_)) * energy
0159 + real_type(0.5) * ipow<2>(energy / total_energy_);
0160
0161 if (use_rad_correction_
0162 && energy > value_as<Energy>(kin_energy_limit()))
0163 {
0164 real_type a1 = std::log(1 + 2 * energy / electron_mass_);
0165 real_type a3 = std::log(4 * total_energy_ * (total_energy_ - energy)
0166 / ipow<2>(inc_mass_));
0167 target *= (1 + alpha_over_twopi() * a1 * (a3 - a1));
0168 }
0169 } while (RejectionSampler<>(target, envelope_)(rng));
0170
0171 CELER_ENSURE(energy > 0);
0172 return Energy{energy};
0173 }
0174
0175
0176
0177
0178
0179 CELER_FUNCTION real_type MuBBEnergyDistribution::calc_envelope_distribution() const
0180 {
0181 if (use_rad_correction_)
0182 {
0183 return 1
0184 + alpha_over_twopi()
0185 * ipow<2>(std::log(2 * total_energy_ / inc_mass_));
0186 }
0187 return 1;
0188 }
0189
0190
0191 }