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

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