/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
Discretization Framework for functional Renormalization Group flows
spline_interpolator_1d_stack.hh
Go to the documentation of this file.
1#pragma once
2
3// DiFfRG
7#include <limits>
8
9namespace DiFfRG
10{
20 template <typename NT, typename Coordinates> class SplineInterpolator1DStack
21 {
22 static_assert(Coordinates::dim == 2, "SplineInterpolator1DStack requires 2D coordinates");
23 // The spline coefficients come from a non-cyclic tridiagonal solve with boundary conditions at the grid edges,
24 // which cannot close a periodic axis. Use LinearInterpolator2D there instead.
26 "SplineInterpolator1DStack does not support periodic coordinates; use LinearInterpolator2D.");
27
28 // SoA layout: separate views for values and spline coefficients, for coalesced GPU access
29 using ValueViewType = Kokkos::View<NT **, GPU_memory, Kokkos::MemoryTraits<Kokkos::RandomAccess>>;
31 using HostValueViewType = typename ValueViewType::host_mirror_type;
32 using HostCoeffViewType = typename CoeffViewType::host_mirror_type;
33
34 static constexpr bool has_separate_device =
35 !std::is_same_v<typename ValueViewType::memory_space, typename HostValueViewType::memory_space>;
36
37 public:
38 using ctype = typename Coordinates::ctype;
39 using value_type = NT;
40 static constexpr size_t dim = 2;
41
49 device_values("SplineInterpolator1DStack_values", coordinates.sizes()[0], coordinates.sizes()[1]),
50 device_coeffs("SplineInterpolator1DStack_coeffs", coordinates.sizes()[0], coordinates.sizes()[1]),
51 host_values(Kokkos::create_mirror_view(device_values)),
52 host_coeffs(Kokkos::create_mirror_view(device_coeffs))
53 {
54 }
55
57 KOKKOS_DEFAULTED_FUNCTION SplineInterpolator1DStack(const SplineInterpolator1DStack &) = default;
58
66 template <typename NT2>
67 void update(const NT2 *in_data, const ctype lower_y1 = std::numeric_limits<ctype>::max(),
68 const ctype upper_y1 = std::numeric_limits<ctype>::max())
69 {
70 // Copy values from input data (row-major)
71 for (size_t i = 0; i < sizes[0]; ++i)
72 for (size_t j = 0; j < sizes[1]; ++j)
73 host_values(i, j) = in_data[i * sizes[1] + j];
74
75 // Build the spline coefficients
76 for (size_t i = 0; i < sizes[0]; ++i)
77 build_y2(i, lower_y1, upper_y1);
78
79 if constexpr (has_separate_device) {
80 typename ValueViewType::execution_space exec;
81 Kokkos::deep_copy(exec, device_values, host_values);
82 Kokkos::deep_copy(exec, device_coeffs, host_coeffs);
83 exec.fence();
84 }
85 }
86
90 NT operator[](size_t i) const { return host_values(i / sizes[1], i % sizes[1]); }
91
110 index(const typename Coordinates::ctype s, const typename Coordinates::ctype x) const
111 {
112 // backward() returns device::array for CoordinatePackND but std::tuple<Idx, NT> for the
113 // combined finite-T systems; the structured binding normalises both onto what at() expects.
114 auto [sidx, xidx] = coordinates.backward(s, x);
115 return {{static_cast<typename Coordinates::ctype>(sidx), static_cast<typename Coordinates::ctype>(xidx)}};
116 }
117
121 NT KOKKOS_FUNCTION at(const device::array<typename Coordinates::ctype, 2> &raw) const
122 {
123 auto _sidx = raw[0];
124 auto xidx = raw[1];
125 // Clamp indices to the range [0, sizes[i] - 1]
126 xidx = Kokkos::max(static_cast<decltype(xidx)>(0), Kokkos::min(xidx, static_cast<decltype(xidx)>(sizes[1] - 1)));
127 _sidx =
128 Kokkos::max(static_cast<decltype(_sidx)>(0), Kokkos::min(_sidx, static_cast<decltype(_sidx)>(sizes[0] - 1)));
129 // for the x part
130 const size_t lidx = Kokkos::min(size_t(Kokkos::floor(xidx)), sizes[1] - 2);
131 const size_t uidx = lidx + 1;
132 // t is the fractional part of the index
133 const ctype t = xidx - lidx;
134
135 // the s part is rounded to the nearest integer
136 const size_t sidx = size_t(Kokkos::round(_sidx));
137
138 const NT lower = value(sidx, lidx);
139 const NT upper = value(sidx, uidx);
140 const NT cl = coeff(sidx, lidx);
141 const NT cu = coeff(sidx, uidx);
142
143 const ctype tm1 = t - 1;
144 const NT cubic = t * tm1 * ((t + 1) * cl - (t - 2) * cu);
145
146 if constexpr (std::is_arithmetic_v<NT>)
147 return Kokkos::fma(t, upper, Kokkos::fma(-t, lower, lower)) + cubic; // linear + cubic
148 else
149 return t * upper + (1 - t) * lower + cubic; // linear + cubic
150 }
151
155 NT KOKKOS_FUNCTION operator()(const typename Coordinates::ctype s,
156 const typename Coordinates::ctype x) const
157 {
158 return at(index(s, x));
159 }
160
166 const Coordinates &get_coordinates() const { return coordinates; }
167
174 const NT *data() const { return host_values.data(); }
175
176 private:
178 KOKKOS_FORCEINLINE_FUNCTION NT value(const size_t i, const size_t j) const
179 {
180 KOKKOS_IF_ON_DEVICE((return device_values(i, j);))
181 KOKKOS_IF_ON_HOST((return host_values(i, j);))
182 }
183
185 KOKKOS_FORCEINLINE_FUNCTION NT coeff(const size_t i, const size_t j) const
186 {
187 KOKKOS_IF_ON_DEVICE((return device_coeffs(i, j);))
188 KOKKOS_IF_ON_HOST((return host_coeffs(i, j);))
189 }
190
191 const Coordinates coordinates;
193
198
199 void build_y2(const size_t sidx, const ctype lower_y1, const ctype upper_y1)
200 {
201 const auto &size = sizes[1];
202
203 NT p, qn, sig, un;
204 std::vector<NT> u(size - 1);
205
206 if (!std::isfinite(lower_y1) || lower_y1 >= std::numeric_limits<ctype>::max() / 2)
207 host_coeffs(sidx, 0) = u[0] = 0.0;
208 else {
209 host_coeffs(sidx, 0) = -0.5;
210 u[0] = 3.0 * ((host_values(sidx, 1) - host_values(sidx, 0)) - lower_y1);
211 }
212 for (size_t i = 1; i < size - 1; i++) {
213 sig = 0.5;
214 p = sig * host_coeffs(sidx, i - 1) + 2.0;
215 host_coeffs(sidx, i) = (sig - 1.0) / p;
216 u[i] = (host_values(sidx, i + 1) - host_values(sidx, i)) - (host_values(sidx, i) - host_values(sidx, i - 1));
217 u[i] = (6.0 * u[i] / 2. - sig * u[i - 1]) / p;
218 }
219 if (!std::isfinite(upper_y1) || upper_y1 >= std::numeric_limits<ctype>::max() / 2)
220 qn = un = 0.0;
221 else {
222 qn = 0.5;
223 un = 3.0 * (upper_y1 - (host_values(sidx, size - 1) - host_values(sidx, size - 2)));
224 }
225 host_coeffs(sidx, size - 1) = (un - qn * u[size - 2]) / (qn * host_coeffs(sidx, size - 2) + 1);
226 for (int k = size - 2; k >= 0; k--)
227 host_coeffs(sidx, k) = host_coeffs(sidx, k) * host_coeffs(sidx, k + 1) + u[k];
228
229 // Precompute division by 6 so operator() avoids per-call divides
230 for (size_t k = 0; k < size; ++k)
231 host_coeffs(sidx, k) /= (ctype)6;
232 }
233 };
234} // namespace DiFfRG
A stack of 1D splines, callable from host AND device code.
Definition spline_interpolator_1d_stack.hh:21
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:155
HostCoeffViewType host_coeffs
Definition spline_interpolator_1d_stack.hh:197
typename CoeffViewType::host_mirror_type HostCoeffViewType
Definition spline_interpolator_1d_stack.hh:32
ValueViewType device_values
Definition spline_interpolator_1d_stack.hh:194
const device::array< size_t, 2 > sizes
Definition spline_interpolator_1d_stack.hh:192
typename Coordinates::ctype ctype
Definition spline_interpolator_1d_stack.hh:38
NT value_type
Definition spline_interpolator_1d_stack.hh:39
const Coordinates & get_coordinates() const
Get the coordinate system of the data.
Definition spline_interpolator_1d_stack.hh:166
ValueViewType CoeffViewType
Definition spline_interpolator_1d_stack.hh:30
static constexpr bool has_separate_device
Definition spline_interpolator_1d_stack.hh:34
SplineInterpolator1DStack(const Coordinates &coordinates)
Construct a SplineInterpolator1DStack with zeroed data and a coordinate system.
Definition spline_interpolator_1d_stack.hh:47
const Coordinates coordinates
Definition spline_interpolator_1d_stack.hh:191
KOKKOS_FORCEINLINE_FUNCTION NT coeff(const size_t i, const size_t j) const
Read one spline coefficient from whichever buffer belongs to the executing side.
Definition spline_interpolator_1d_stack.hh:185
static constexpr size_t dim
Definition spline_interpolator_1d_stack.hh:40
HostValueViewType host_values
Definition spline_interpolator_1d_stack.hh:196
const NT * data() const
Read-only handle to the host values, in the mirror's storage order.
Definition spline_interpolator_1d_stack.hh:174
Kokkos::View< NT **, GPU_memory, Kokkos::MemoryTraits< Kokkos::RandomAccess > > ValueViewType
Definition spline_interpolator_1d_stack.hh:29
void build_y2(const size_t sidx, const ctype lower_y1, const ctype upper_y1)
Definition spline_interpolator_1d_stack.hh:199
CoeffViewType device_coeffs
Definition spline_interpolator_1d_stack.hh:195
void update(const NT2 *in_data, const ctype lower_y1=std::numeric_limits< ctype >::max(), const ctype upper_y1=std::numeric_limits< ctype >::max())
Replace the data, leaving host AND device current. The only mutator.
Definition spline_interpolator_1d_stack.hh:67
NT operator[](size_t i) const
Host-side element access, in the row-major order update() takes its input in.
Definition spline_interpolator_1d_stack.hh:90
KOKKOS_DEFAULTED_FUNCTION SplineInterpolator1DStack(const SplineInterpolator1DStack &)=default
Shallow copy of ALL views, valid in host and in device code. See LinearInterpolator1D.
NT KOKKOS_FUNCTION at(const device::array< typename Coordinates::ctype, 2 > &raw) const
Interpolate at grid indices previously obtained from index().
Definition spline_interpolator_1d_stack.hh:121
typename ValueViewType::host_mirror_type HostValueViewType
Definition spline_interpolator_1d_stack.hh:31
device::array< typename Coordinates::ctype, 2 > KOKKOS_FUNCTION index(const typename Coordinates::ctype s, const typename Coordinates::ctype x) const
Map physical coordinates onto grid indices.
Definition spline_interpolator_1d_stack.hh:110
KOKKOS_FORCEINLINE_FUNCTION NT value(const size_t i, const size_t j) const
Read one value from whichever buffer belongs to the executing side.
Definition spline_interpolator_1d_stack.hh:178
std::array< T, N > array
Definition kokkos.hh:155
Definition complex_math.hh:10
constexpr bool is_periodic_axis_v
Whether axis i of a (possibly multi-dimensional) coordinate system is periodic. Falls back to false f...
Definition coordinates.hh:59
Definition kokkos.hh:538