File indexing completed on 2025-09-15 08:54:38
0001
0002
0003
0004
0005
0006
0007 #pragma once
0008
0009 #include <cmath>
0010
0011 #include "corecel/grid/TwodGridCalculator.hh"
0012 #include "corecel/grid/TwodSubgridCalculator.hh"
0013 #include "corecel/math/Algorithms.hh"
0014 #include "corecel/random/distribution/ReciprocalDistribution.hh"
0015 #include "celeritas/Quantities.hh"
0016 #include "celeritas/em/data/SeltzerBergerData.hh"
0017
0018 namespace celeritas
0019 {
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032 class SBEnergyDistHelper
0033 {
0034 public:
0035
0036
0037 using SBDXsec = NativeCRef<SeltzerBergerTableData>;
0038 using Xs = RealQuantity<SBElementTableData::XsUnits>;
0039 using Energy = units::MevEnergy;
0040 using EnergySq = RealQuantity<UnitProduct<units::Mev, units::Mev>>;
0041
0042
0043 public:
0044
0045 inline CELER_FUNCTION SBEnergyDistHelper(SBDXsec const& differential_xs,
0046 Energy inc_energy,
0047 ElementId element,
0048 EnergySq density_correction,
0049 Energy min_gamma_energy);
0050
0051
0052 template<class Engine>
0053 inline CELER_FUNCTION Energy sample_exit_energy(Engine& rng) const;
0054
0055
0056 inline CELER_FUNCTION Xs calc_xs(Energy energy) const;
0057
0058
0059 CELER_FUNCTION Xs max_xs() const { return max_xs_; }
0060
0061 private:
0062
0063
0064 using SBTables = NativeCRef<SeltzerBergerTableData>;
0065 using ReciprocalSampler = ReciprocalDistribution<real_type>;
0066
0067
0068
0069 TwodSubgridCalculator const calc_xs_;
0070 Xs const max_xs_;
0071
0072 real_type const inv_inc_energy_;
0073 real_type const dens_corr_;
0074 ReciprocalSampler const sample_exit_esq_;
0075
0076
0077
0078 inline CELER_FUNCTION TwodSubgridCalculator make_xs_calc(
0079 SBTables const&, real_type inc_energy, ElementId element) const;
0080
0081 inline CELER_FUNCTION Xs calc_max_xs(SBTables const& xs_params,
0082 ElementId element) const;
0083
0084 inline CELER_FUNCTION ReciprocalSampler
0085 make_esq_sampler(real_type inc_energy, real_type min_gamma_energy) const;
0086 };
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097 CELER_FUNCTION
0098 SBEnergyDistHelper::SBEnergyDistHelper(SBDXsec const& differential_xs,
0099 Energy inc_energy,
0100 ElementId element,
0101 EnergySq density_correction,
0102 Energy min_gamma_energy)
0103 : calc_xs_{this->make_xs_calc(differential_xs, inc_energy.value(), element)}
0104 , max_xs_{this->calc_max_xs(differential_xs, element)}
0105 , inv_inc_energy_(1 / inc_energy.value())
0106 , dens_corr_(density_correction.value())
0107 , sample_exit_esq_{
0108 this->make_esq_sampler(inc_energy.value(), min_gamma_energy.value())}
0109 {
0110 CELER_EXPECT(inc_energy > min_gamma_energy);
0111 }
0112
0113
0114
0115
0116
0117 template<class Engine>
0118 CELER_FUNCTION auto
0119 SBEnergyDistHelper::sample_exit_energy(Engine& rng) const -> Energy
0120 {
0121
0122 real_type esq = sample_exit_esq_(rng) - dens_corr_;
0123 CELER_ASSERT(esq >= 0);
0124 return Energy{std::sqrt(esq)};
0125 }
0126
0127
0128
0129
0130
0131 CELER_FUNCTION auto SBEnergyDistHelper::calc_xs(Energy e) const -> Xs
0132 {
0133 CELER_EXPECT(e > zero_quantity());
0134
0135 return Xs{calc_xs_(e.value() * inv_inc_energy_)};
0136 }
0137
0138
0139
0140
0141
0142 CELER_FUNCTION TwodSubgridCalculator SBEnergyDistHelper::make_xs_calc(
0143 SBTables const& xs_params, real_type inc_energy, ElementId element) const
0144 {
0145 CELER_EXPECT(element < xs_params.elements.size());
0146 CELER_EXPECT(inc_energy > 0);
0147
0148 TwodGridData const& grid = xs_params.elements[element].grid;
0149 CELER_ASSERT(inc_energy >= std::exp(xs_params.reals[grid.x.front()])
0150 && inc_energy < std::exp(xs_params.reals[grid.x.back()]));
0151
0152 static_assert(
0153 std::is_same<Energy::unit_type, units::Mev>::value
0154 && std::is_same<SBElementTableData::EnergyUnits, units::LogMev>::value,
0155 "Inconsistent energy units");
0156 return TwodGridCalculator(grid, xs_params.reals)(std::log(inc_energy));
0157 }
0158
0159
0160
0161
0162
0163
0164
0165
0166
0167
0168
0169
0170
0171
0172
0173
0174 CELER_FUNCTION auto
0175 SBEnergyDistHelper::calc_max_xs(SBTables const& xs_params,
0176 ElementId element) const -> Xs
0177 {
0178 CELER_EXPECT(element);
0179 SBElementTableData const& el = xs_params.elements[element];
0180
0181 size_type const x_idx = calc_xs_.x_index();
0182 real_type const x_frac = calc_xs_.x_fraction();
0183 real_type result;
0184
0185
0186 auto get_value = [&xs_params, &el](size_type ix) -> real_type {
0187
0188
0189 size_type iy = xs_params.sizes[el.argmax[ix]];
0190
0191 return xs_params.reals[el.grid.at(ix, iy)];
0192 };
0193 result = (1 - x_frac) * get_value(x_idx) + x_frac * get_value(x_idx + 1);
0194
0195 CELER_ENSURE(result > 0);
0196 return Xs{result};
0197 }
0198
0199
0200
0201
0202
0203 CELER_FUNCTION auto SBEnergyDistHelper::make_esq_sampler(
0204 real_type inc_energy, real_type min_gamma_energy) const -> ReciprocalSampler
0205 {
0206 CELER_EXPECT(min_gamma_energy > 0);
0207 return ReciprocalSampler(ipow<2>(min_gamma_energy) + dens_corr_,
0208 ipow<2>(inc_energy) + dens_corr_);
0209 }
0210
0211
0212 }