File indexing completed on 2025-09-13 08:53:32
0001
0002
0003
0004
0005
0006
0007 #pragma once
0008
0009 #include <cmath>
0010
0011 #include "corecel/grid/Interpolator.hh"
0012 #include "corecel/grid/UniformGrid.hh"
0013 #include "corecel/grid/UniformGridData.hh"
0014 #include "corecel/math/Quantity.hh"
0015 #include "celeritas/Quantities.hh"
0016
0017 namespace celeritas
0018 {
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038 class SplineCalculator
0039 {
0040 public:
0041
0042
0043 using Energy = units::MevEnergy;
0044 using Values
0045 = Collection<real_type, Ownership::const_reference, MemSpace::native>;
0046
0047
0048 public:
0049
0050 inline CELER_FUNCTION
0051 SplineCalculator(UniformGridRecord const& grid, Values const& reals);
0052
0053
0054 inline CELER_FUNCTION real_type operator()(Energy energy) const;
0055
0056
0057 inline CELER_FUNCTION real_type operator[](size_type index) const;
0058
0059
0060 CELER_FUNCTION Energy energy_min() const
0061 {
0062 return Energy(std::exp(loge_grid_.front()));
0063 }
0064
0065
0066 CELER_FUNCTION Energy energy_max() const
0067 {
0068 return Energy(std::exp(loge_grid_.back()));
0069 }
0070
0071 private:
0072 UniformGridRecord const& data_;
0073 Values const& reals_;
0074 UniformGrid loge_grid_;
0075
0076 CELER_FORCEINLINE_FUNCTION real_type interpolate(real_type energy,
0077 size_type low_idx,
0078 size_type high_idx) const;
0079 };
0080
0081
0082
0083
0084
0085
0086
0087 CELER_FUNCTION
0088 SplineCalculator::SplineCalculator(UniformGridRecord const& grid,
0089 Values const& reals)
0090 : data_(grid), reals_(reals), loge_grid_(data_.grid)
0091 {
0092 CELER_EXPECT(data_);
0093 }
0094
0095
0096
0097
0098
0099
0100
0101
0102 CELER_FUNCTION real_type SplineCalculator::operator()(Energy energy) const
0103 {
0104 real_type const loge = std::log(energy.value());
0105
0106
0107 if (loge <= loge_grid_.front())
0108 {
0109 return (*this)[0];
0110 }
0111 if (loge >= loge_grid_.back())
0112 {
0113 return (*this)[loge_grid_.size() - 1];
0114 }
0115
0116
0117 size_type lower_idx = loge_grid_.find(loge);
0118 CELER_ASSERT(lower_idx + 1 < loge_grid_.size());
0119
0120
0121
0122 size_type order_steps = data_.spline_order / 2 + 1;
0123
0124
0125
0126
0127
0128
0129
0130 size_type true_low_idx;
0131 if (lower_idx >= order_steps - 1)
0132 {
0133 true_low_idx = lower_idx - order_steps + 1;
0134 }
0135 else
0136 {
0137 true_low_idx = 0;
0138 }
0139 size_type true_high_idx
0140 = min(lower_idx + order_steps + 1, loge_grid_.size());
0141
0142 if (data_.spline_order % 2 == 0)
0143 {
0144
0145
0146 real_type low_dist = std::fabs(loge - loge_grid_[lower_idx]);
0147 real_type high_dist = std::fabs(loge_grid_[lower_idx + 1] - loge);
0148
0149 if (true_high_idx - true_low_idx > data_.spline_order + 1)
0150 {
0151
0152
0153 if (low_dist > high_dist)
0154 {
0155 true_low_idx += 1;
0156 }
0157 else
0158 {
0159 true_high_idx -= 1;
0160 }
0161 }
0162 }
0163 return this->interpolate(energy.value(), true_low_idx, true_high_idx);
0164 }
0165
0166
0167
0168
0169
0170 CELER_FUNCTION real_type SplineCalculator::operator[](size_type index) const
0171 {
0172 CELER_EXPECT(index < data_.value.size());
0173 return reals_[data_.value[index]];
0174 }
0175
0176
0177
0178
0179
0180 CELER_FUNCTION real_type SplineCalculator::interpolate(real_type energy,
0181 size_type low_idx,
0182 size_type high_idx) const
0183 {
0184 CELER_EXPECT(high_idx <= loge_grid_.size());
0185 real_type result = 0;
0186
0187
0188 for (size_type outer_idx = low_idx; outer_idx < high_idx; ++outer_idx)
0189 {
0190 real_type outer_e = std::exp(loge_grid_[outer_idx]);
0191 real_type num = 1;
0192 real_type denom = 1;
0193
0194
0195 for (size_type inner_idx = low_idx; inner_idx < high_idx; ++inner_idx)
0196 {
0197
0198 if (inner_idx != outer_idx)
0199 {
0200 real_type inner_e = std::exp(loge_grid_[inner_idx]);
0201 num *= (energy - inner_e);
0202 denom *= (outer_e - inner_e);
0203 }
0204 }
0205 result += (num / denom) * (*this)[outer_idx];
0206 }
0207 CELER_ENSURE(result >= 0);
0208 return result;
0209 }
0210
0211
0212 }