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