/home/runner/work/DiFfRG_current/DiFfRG_current/DiFfRG/include/DiFfRG/physics/interpolation/spline_interpolator_1d_stack.hh Source File#

DiFfRG: /home/runner/work/DiFfRG_current/DiFfRG_current/DiFfRG/include/DiFfRG/physics/interpolation/spline_interpolator_1d_stack.hh Source File
DiFfRG
spline_interpolator_1d_stack.hh
Go to the documentation of this file.
1#pragma once
2
3// DiFfRG
6#include <limits>
7
8namespace DiFfRG
9{
16 template <typename NT, typename Coordinates, typename DefaultMemorySpace = CPU_memory> class SplineInterpolator1DStack
17 {
18 static_assert(Coordinates::dim == 2, "SplineInterpolator1DStack requires 2D coordinates");
19
20 public:
21 using memory_space = DefaultMemorySpace;
23 using ctype = typename Coordinates::ctype;
24 using value_type = NT;
25 static constexpr size_t dim = 2;
26
34 {
35 // Allocate separate views for values and spline coefficients (SoA layout)
36 device_values = ValueViewType("SplineInterpolator1DStack_values", sizes[0], sizes[1]);
37 device_coeffs = CoeffViewType("SplineInterpolator1DStack_coeffs", sizes[0], sizes[1]);
38 // Create host mirrors
39 host_values = Kokkos::create_mirror_view(device_values);
40 host_coeffs = Kokkos::create_mirror_view(device_coeffs);
41 }
42
47 KOKKOS_FUNCTION
49 : coordinates(other.coordinates), sizes(other.sizes)
50 {
51 // Use the same data (reference-counted)
54 }
55
57 {
58 KOKKOS_IF_ON_HOST((if (owns_other_instance) delete other_instance;))
59 }
60
61 template <typename NT2>
62 void update(const NT2 *in_data, const ctype lower_y1 = std::numeric_limits<ctype>::max(),
63 const ctype upper_y1 = std::numeric_limits<ctype>::max())
64 {
65 // Check if the host data is already allocated
66 if (!host_values.is_allocated())
67 throw std::runtime_error(
68 "SplineInterpolator1DStack: You probably called update() on a copied instance. This is not allowed. "
69 "You need to call update() on the original instance.");
70
71 // Copy values from input data (LayoutRight: row-major)
72 for (size_t i = 0; i < sizes[0]; ++i)
73 for (size_t j = 0; j < sizes[1]; ++j)
74 host_values(i, j) = in_data[i * sizes[1] + j];
75
76 // Build the spline coefficients
77 for (size_t i = 0; i < sizes[0]; ++i)
78 build_y2(i, lower_y1, upper_y1);
79
80 // Copy data to device
81 Kokkos::deep_copy(device_values, host_values);
82 Kokkos::deep_copy(device_coeffs, host_coeffs);
83 }
84
85 template <typename View>
86 requires(Kokkos::is_view<View>::value && View::rank == 2)
87 void update(const View &view, const ctype lower_y1 = std::numeric_limits<ctype>::max(),
88 const ctype upper_y1 = std::numeric_limits<ctype>::max())
89 {
90 // Check if the host data is already allocated
91 if (!host_values.is_allocated())
92 throw std::runtime_error(
93 "SplineInterpolator1DStack: You probably called update() on a copied instance. This is not allowed. "
94 "You need to call update() on the original instance.");
95
96 // Copy values from input view
97 Kokkos::deep_copy(host_values, view);
98
99 // Build the spline coefficients
100 for (size_t i = 0; i < sizes[0]; ++i)
101 build_y2(i, lower_y1, upper_y1);
102
103 // Copy data to device
104 Kokkos::deep_copy(device_values, host_values);
105 Kokkos::deep_copy(device_coeffs, host_coeffs);
106 }
107
114 NT KOKKOS_FUNCTION operator()(const typename Coordinates::ctype s, const typename Coordinates::ctype x) const
115 {
116 auto [_sidx, xidx] = coordinates.backward(s, x);
117 // Clamp indices to the range [0, sizes[i] - 1]
118 xidx = Kokkos::max(static_cast<decltype(xidx)>(0), Kokkos::min(xidx, static_cast<decltype(xidx)>(sizes[1] - 1)));
119 _sidx =
120 Kokkos::max(static_cast<decltype(_sidx)>(0), Kokkos::min(_sidx, static_cast<decltype(_sidx)>(sizes[0] - 1)));
121 // for the x part
122 const size_t lidx = Kokkos::min(size_t(Kokkos::floor(xidx)), sizes[1] - 2);
123 const size_t uidx = lidx + 1;
124 // t is the fractional part of the index
125 const ctype t = xidx - lidx;
126
127 // the s part is rounded to the nearest integer
128 const size_t sidx = size_t(Kokkos::round(_sidx));
129
130 // SoA layout: separate reads from values and coefficients views for coalesced GPU access
131 const NT lower = device_values(sidx, lidx);
132 const NT upper = device_values(sidx, uidx);
133 const NT cl = device_coeffs(sidx, lidx);
134 const NT cu = device_coeffs(sidx, uidx);
135
136 const ctype tm1 = t - 1;
137 const NT cubic = t * tm1 * ((t + 1) * cl - (t - 2) * cu);
138
139 if constexpr (std::is_arithmetic_v<NT>)
140 return Kokkos::fma(t, upper, Kokkos::fma(-t, lower, lower)) + cubic; // linear + cubic
141 else
142 return t * upper + (1 - t) * lower + cubic; // linear + cubic
143 }
144
145 NT operator[](size_t i) const
146 {
147 // Check if the host data is already allocated
148 if (!host_values.is_allocated())
149 throw std::runtime_error(
150 "SplineInterpolator1DStack: You probably called operator[]() on a copied instance. This is not allowed. "
151 "You need to call operator[]() on the original instance.");
152
153 return host_values.data()[i];
154 }
155
156 auto &CPU() const { return get_on<CPU_memory>(); }
157 auto &GPU() const { return get_on<GPU_memory>(); }
158
159 template <typename MemorySpace> auto &get_on() const
160 {
161 // Check if the host data is already allocated
162 if (!host_values.is_allocated())
163 throw std::runtime_error(
164 "SplineInterpolator1DStack: You probably called get_on() on a copied instance. This is not allowed. "
165 "You need to call get_on() on the original instance.");
166
167 if constexpr (std::is_same_v<MemorySpace, DefaultMemorySpace>) {
168 // remove constness
170 } else {
171 // Create a new instance with the same data but in the requested memory space
172 if (other_instance == nullptr) {
174 owns_other_instance = true;
175 other_instance->other_instance = const_cast<std::decay_t<decltype(*this)> *>(this);
176 }
177 // Copy the data from the current instance to the new one
179 // Return the new instance
180 return *other_instance;
181 }
182 }
183
189 const Coordinates &get_coordinates() const { return coordinates; }
190
191 NT *data()
192 {
193 if (!host_values.is_allocated())
194 throw std::runtime_error(
195 "SplineInterpolator1DStack: You probably called data() on a copied instance. This is not allowed. "
196 "You need to call data() on the original instance.");
197 return host_values.data();
198 }
199
200 friend class SplineInterpolator1DStack<NT, Coordinates, other_memory_space>;
201
202 private:
203 const Coordinates coordinates;
205
206 using ValueViewType = Kokkos::View<NT **, DefaultMemorySpace, Kokkos::MemoryTraits<Kokkos::RandomAccess>>;
207 using CoeffViewType = Kokkos::View<NT **, DefaultMemorySpace, Kokkos::MemoryTraits<Kokkos::RandomAccess>>;
208 using HostValueViewType = typename ValueViewType::host_mirror_type;
209 using HostCoeffViewType = typename CoeffViewType::host_mirror_type;
210
215
217 mutable bool owns_other_instance = false;
218
219 void build_y2(const size_t sidx, const ctype lower_y1, const ctype upper_y1)
220 {
221 const auto &size = sizes[1];
222
223 NT p, qn, sig, un;
224 std::vector<NT> u(size - 1);
225
226 if (!std::isfinite(lower_y1) || lower_y1 >= std::numeric_limits<ctype>::max() / 2)
227 host_coeffs(sidx, 0) = u[0] = 0.0;
228 else {
229 host_coeffs(sidx, 0) = -0.5;
230 u[0] = 3.0 * ((host_values(sidx, 1) - host_values(sidx, 0)) - lower_y1);
231 }
232 for (size_t i = 1; i < size - 1; i++) {
233 sig = 0.5;
234 p = sig * host_coeffs(sidx, i - 1) + 2.0;
235 host_coeffs(sidx, i) = (sig - 1.0) / p;
236 u[i] = (host_values(sidx, i + 1) - host_values(sidx, i)) - (host_values(sidx, i) - host_values(sidx, i - 1));
237 u[i] = (6.0 * u[i] / 2. - sig * u[i - 1]) / p;
238 }
239 if (!std::isfinite(upper_y1) || upper_y1 >= std::numeric_limits<ctype>::max() / 2)
240 qn = un = 0.0;
241 else {
242 qn = 0.5;
243 un = 3.0 * (upper_y1 - (host_values(sidx, size - 1) - host_values(sidx, size - 2)));
244 }
245 host_coeffs(sidx, size - 1) = (un - qn * u[size - 2]) / (qn * host_coeffs(sidx, size - 2) + 1);
246 for (int k = size - 2; k >= 0; k--)
247 host_coeffs(sidx, k) = host_coeffs(sidx, k) * host_coeffs(sidx, k + 1) + u[k];
248
249 // Precompute division by 6 so operator() avoids per-call divides
250 for (size_t k = 0; k < size; ++k)
251 host_coeffs(sidx, k) /= (ctype)6;
252 }
253 };
254} // namespace DiFfRG
A linear interpolator for 1D data, using texture memory on the GPU and floating point arithmetic on t...
Definition spline_interpolator_1d_stack.hh:17
other_memory_space_t< DefaultMemorySpace > other_memory_space
Definition spline_interpolator_1d_stack.hh:22
auto & GPU() const
Definition spline_interpolator_1d_stack.hh:157
NT value_type
Definition spline_interpolator_1d_stack.hh:24
Kokkos::View< NT **, DefaultMemorySpace, Kokkos::MemoryTraits< Kokkos::RandomAccess > > CoeffViewType
Definition spline_interpolator_1d_stack.hh:207
const Coordinates & get_coordinates() const
Get the coordinate system of the data.
Definition spline_interpolator_1d_stack.hh:189
SplineInterpolator1DStack(const Coordinates &coordinates)
Construct a SplineInterpolator1DStack with zeroed data and a coordinate system.
Definition spline_interpolator_1d_stack.hh:32
KOKKOS_FUNCTION ~SplineInterpolator1DStack()
Definition spline_interpolator_1d_stack.hh:56
bool owns_other_instance
Definition spline_interpolator_1d_stack.hh:217
void build_y2(const size_t sidx, const ctype lower_y1, const ctype upper_y1)
Definition spline_interpolator_1d_stack.hh:219
CoeffViewType device_coeffs
Definition spline_interpolator_1d_stack.hh:212
typename CoeffViewType::host_mirror_type HostCoeffViewType
Definition spline_interpolator_1d_stack.hh:209
const Coordinates coordinates
Definition spline_interpolator_1d_stack.hh:203
typename ValueViewType::host_mirror_type HostValueViewType
Definition spline_interpolator_1d_stack.hh:208
DefaultMemorySpace memory_space
Definition spline_interpolator_1d_stack.hh:21
SplineInterpolator1DStack< NT, Coordinates, other_memory_space > * other_instance
Definition spline_interpolator_1d_stack.hh:216
KOKKOS_FUNCTION SplineInterpolator1DStack(const SplineInterpolator1DStack &other)
Copy constructor for SplineInterpolator1DStack. This is ONLY for usage inside Kokkos parallel loops.
Definition spline_interpolator_1d_stack.hh:48
NT operator[](size_t i) const
Definition spline_interpolator_1d_stack.hh:145
auto & CPU() const
Definition spline_interpolator_1d_stack.hh:156
void update(const View &view, const ctype lower_y1=std::numeric_limits< ctype >::max(), const ctype upper_y1=std::numeric_limits< ctype >::max())
Definition spline_interpolator_1d_stack.hh:87
auto & get_on() const
Definition spline_interpolator_1d_stack.hh:159
Kokkos::View< NT **, DefaultMemorySpace, Kokkos::MemoryTraits< Kokkos::RandomAccess > > ValueViewType
Definition spline_interpolator_1d_stack.hh:206
const device::array< size_t, 2 > sizes
Definition spline_interpolator_1d_stack.hh:204
typename Coordinates::ctype ctype
Definition spline_interpolator_1d_stack.hh:23
NT * data()
Definition spline_interpolator_1d_stack.hh:191
void update(const NT2 *in_data, const ctype lower_y1=std::numeric_limits< ctype >::max(), const ctype upper_y1=std::numeric_limits< ctype >::max())
Definition spline_interpolator_1d_stack.hh:62
static constexpr size_t dim
Definition spline_interpolator_1d_stack.hh:25
ValueViewType device_values
Definition spline_interpolator_1d_stack.hh:211
HostValueViewType host_values
Definition spline_interpolator_1d_stack.hh:213
NT KOKKOS_FUNCTION operator()(const typename Coordinates::ctype s, const typename Coordinates::ctype x) const
Interpolate the data at a given point.
Definition spline_interpolator_1d_stack.hh:114
HostCoeffViewType host_coeffs
Definition spline_interpolator_1d_stack.hh:214
std::array< T, N > array
Definition kokkos.hh:133
Definition complex_math.hh:10
std::conditional_t< std::is_same_v< MemorySpace, GPU_memory >, CPU_memory, GPU_memory > other_memory_space_t
Definition kokkos.hh:58