From 5891d22f9821713b49f8d1c3130a54d270f17a82 Mon Sep 17 00:00:00 2001 From: Sichao25 Date: Mon, 28 Jul 2025 17:04:51 -0400 Subject: [PATCH 01/18] initial commit for cubic spline interpolator --- src/pcms/interpolator/CMakeLists.txt | 1 + src/pcms/interpolator/spline_interpolator.hpp | 2364 +++++++++++++++++ test/CMakeLists.txt | 3 +- test/test_spline_interpolator.cpp | 503 ++++ 4 files changed, 2870 insertions(+), 1 deletion(-) create mode 100644 src/pcms/interpolator/spline_interpolator.hpp create mode 100644 test/test_spline_interpolator.cpp diff --git a/src/pcms/interpolator/CMakeLists.txt b/src/pcms/interpolator/CMakeLists.txt index 5e3a55893..f286107dc 100644 --- a/src/pcms/interpolator/CMakeLists.txt +++ b/src/pcms/interpolator/CMakeLists.txt @@ -10,6 +10,7 @@ set(PCMS_FIELD_TRANSFER_HEADERS mls_interpolation.hpp pcms_interpolator_view_utils.hpp pcms_interpolator_logger.hpp + spline_interpolator.hpp ) set(PCMS_FIELD_TRANSFER_SOURCES diff --git a/src/pcms/interpolator/spline_interpolator.hpp b/src/pcms/interpolator/spline_interpolator.hpp new file mode 100644 index 000000000..1fd3d6341 --- /dev/null +++ b/src/pcms/interpolator/spline_interpolator.hpp @@ -0,0 +1,2364 @@ + +#ifndef MLS_RBF_OPTIONS_HPP +#define MLS_RBF_OPTIONS_HPP + +#include "mdspan/mdspan.hpp" +#include "pcms/arrays.h" +#include "pcms/assert.h" +#include "pcms/memory_spaces.h" +#include "pcms/types.h" +#include +#include + +namespace pcms { + +// Todo: remove this once target PR is merged +// Declaration of customized Kokkos types copied from existing PR +template +struct memory_space_accessor : public Kokkos::default_accessor { + using memory_space = MemorySpace; +}; + +template +using View = Kokkos::mdspan< + ElementType, Kokkos::dextents, Kokkos::layout_right, + detail::memory_space_accessor, + MemorySpace>>; + +template +using Rank1View = View<1, ElementType, MemorySpace>; + +template +using Rank2View = View<2, ElementType, MemorySpace>; + +template +using Rank3View = View<3, ElementType, MemorySpace>; + +template +using Rank4View = View<4, ElementType, MemorySpace>; + +void ibc_check(LO ibc, const std::string &slbl, const std::string &xlbl, + LO imin, LO imax) { + + PCMS_ALWAYS_ASSERT(ibc >= imin && ibc <= imax); +} + +template +T get_element_from_span(Rank1View span, LO index) { + T element; + Kokkos::View data_view(span.data_handle() + index, 1); + auto element_host = Kokkos::create_mirror_view(data_view); + Kokkos::deep_copy(element_host, data_view); + element = element_host(0); + printf("Element at index %d: %f\n", index, element); + return element; +} + +// TODO: better documentation +// TODO: add more checks/assetions for input parameters +template class CubicSplineInterpolator { +public: + CubicSplineInterpolator() = default; + using execution_space = typename MemorySpace::execution_space; + using member_type = typename Kokkos::TeamPolicy::member_type; + Rank1View x_; + LO nx_; + static void sanity_check(Rank1View x, const T &ztol); + + static KOKKOS_INLINE_FUNCTION void range_check(T &xget, T &zxget, + Rank1View x, + const LO &nx, LO &ier); + + static KOKKOS_FUNCTION void v_spline(const LO &k_bc1, const LO &k_bcn, + const LO &n, Rank1View x, + Rank2View f, + Rank1View wk); + + static void correction_detect(Rank1View bcmin, LO &ibcmin, + LO &iflg2, LO &nx); + +}; // end of cubic spline class + +template +class ExplicitCubicSplineInterpolator + : public CubicSplineInterpolator { +public: + using typename CubicSplineInterpolator::execution_space; + using member_type = typename Kokkos::TeamPolicy::member_type; + ExplicitCubicSplineInterpolator() = default; + ExplicitCubicSplineInterpolator(Rank1View x, const LO &nx, + Rank2View fspl, + const LO &ibcxmin, const T &bcxmin, + const LO &ibcxmax, const T &bcxmax, + Rank1View wk); + Rank2View fspl_; + void setup(Rank1View x, const LO &nx, + Rank2View fspl, const LO &ibcxmin, const T &bcxmin, + const LO &ibcxmax, const T &bcxmax, Rank1View wk); + static KOKKOS_FUNCTION void solve_spline(Rank1View x, + const LO &nx, + Rank2View fspl, + const LO &ibcxmin, const T &bcxmin, + const LO &ibcxmax, const T &bcxmax, + Rank1View wk); + static KOKKOS_INLINE_FUNCTION void + evalfn(Kokkos::View selector, + Rank1View fval, const LO &i, const T &dx, + Rank2View fspl); + + static KOKKOS_INLINE_FUNCTION void + eval(T xget, Kokkos::View iselect, + Rank1View fval, Rank1View x, + const LO &nx, Rank2View fspl, LO &ier); + + static KOKKOS_INLINE_FUNCTION void lookup(T xget, Rank1View x, + const LO &nx, LO &i, T &dx, + LO &ier); + void evaluate(Kokkos::View selector, + Rank1View xvec, Rank2View fval); +}; + +template +class CompactCubicSplineInterpolator + : public ExplicitCubicSplineInterpolator { +public: + using typename CubicSplineInterpolator::execution_space; + using member_type = typename Kokkos::TeamPolicy::member_type; + Rank2View fs2_; + CompactCubicSplineInterpolator() = default; + CompactCubicSplineInterpolator(Rank1View x, const LO &nx, + Rank2View fspl, + Rank2View fspl4, + const LO &ibcxmin, const T &bcxmin, + const LO &ibcxmax, const T &bcxmax, + Rank1View wk); + void setup(Rank1View x, const LO &nx, + Rank2View fspl, Rank2View fspl4, + const LO &ibcxmin, const T &bcxmin, const LO &ibcxmax, + const T &bcxmax, Rank1View wk); + static KOKKOS_FUNCTION void + solve_spline(Rank1View x, const LO &nx, + Rank2View fspl, Rank2View fspl4, + const LO &ibcxmin, const T &bcxmin, const LO &ibcxmax, + const T &bcxmax, Rank1View wk); + + static KOKKOS_INLINE_FUNCTION void + evalfn(Kokkos::View selector, + Rank1View fval, const LO &i, const T &xparam, + const T &hx, const T &hxi, Rank2View fs2); + + static KOKKOS_INLINE_FUNCTION void + eval(T xget, Kokkos::View ict, + Rank1View fval, Rank1View x, + const LO &nx, Rank2View fs2, LO &ier); + + static KOKKOS_INLINE_FUNCTION void lookup(T xget, Rank1View x, + const LO &nx, LO &i, T &xparam, + T &hx, T &hxi, LO &ier); + + void evaluate(Kokkos::View selector, + Rank1View xvec, Rank2View fval); +}; + +template +class ExplicitBiCubicSplineInterpolator + : public ExplicitCubicSplineInterpolator { +public: + using typename CubicSplineInterpolator::execution_space; + using member_type = typename Kokkos::TeamPolicy::member_type; + + Rank4View fspl_; + Rank1View y_; + LO ny_; + + ExplicitBiCubicSplineInterpolator() = default; + + ExplicitBiCubicSplineInterpolator( + Rank1View x, // size: inx + LO inx, Rank1View th, // size: inth + LO inth, Rank4View fspl, // [4, 4, inx, inth] + LO ibcxmin, + Rank1View bcxmin, // size: inth (used if ibcxmin = 1 or 2) + LO ibcxmax, + Rank1View bcxmax, // size: inth (used if ibcxmax = 1 or 2) + LO ibcthmin, + Rank1View + bcthmin, // size: inx (used if ibcthmin = 1 or 2) + LO ibcthmax, + Rank1View + bcthmax, // size: inx (used if ibcthmax = 1 or 2) + Rank1View wk // size: nwk + ); + + static void solve_spline( + Rank1View x, // size: inx + LO inx, Rank1View th, // size: inth + LO inth, Rank4View fspl, // [4, 4, inx, inth] + LO ibcxmin, + Rank1View bcxmin, // size: inth (used if ibcxmin = 1 or 2) + LO ibcxmax, + Rank1View bcxmax, // size: inth (used if ibcxmax = 1 or 2) + LO ibcthmin, + Rank1View + bcthmin, // size: inx (used if ibcthmin = 1 or 2) + LO ibcthmax, + Rank1View + bcthmax, // size: inx (used if ibcthmax = 1 or 2) + Rank1View wk // size: nwk + ); + + static KOKKOS_INLINE_FUNCTION void + eval(T xget, T yget, Kokkos::View iselect, + Rank1View fval, Rank1View x, + const LO &nx, Rank1View y, const LO &ny, + Rank4View fspl, LO &ier); + + static KOKKOS_INLINE_FUNCTION void + lookup(T xget, T yget, Rank1View x, const LO &nx, + Rank1View y, const LO &ny, LO &i, LO &j, T &dx, T &dy, + LO &ier); + + static KOKKOS_INLINE_FUNCTION void evalfn( + Kokkos::View + ict, // Selector array for which derivatives to compute + Rank1View fval, // Output array: size [ivd, *] (flattened) + const LO &i, // Grid cell indices in x direction + const LO &j, // Grid cell indices in y direction + const T &dx, // x displacements within cells + const T &dy, // y displacements within cells + Rank4View fspl // Spline coefficients: [4, 4, nx, ny] + ); + + void evaluate(Kokkos::View iselect, + Rank1View xvec, Rank1View yvec, + Rank2View fval); +}; + +template +class CompactBiCubicSplineInterpolator + : public CompactCubicSplineInterpolator { +public: + using typename CubicSplineInterpolator::execution_space; + using member_type = typename Kokkos::TeamPolicy::member_type; + Rank3View f_; + Rank1View y_; + LO ny_; + + CompactBiCubicSplineInterpolator() = default; + + CompactBiCubicSplineInterpolator(Rank1View x, LO nx, + Rank1View y, LO ny, + Rank3View f, LO ibcxmin, + Rank1View bcxmin, LO ibcxmax, + Rank1View bcxmax, LO ibcymin, + Rank1View bcymin, LO ibcymax, + Rank1View bcymax, + Rank1View wk); + + static void solve_spline(Rank1View x, LO nx, + Rank1View y, LO ny, + Rank3View f, LO ibcxmin, + Rank1View bcxmin, LO ibcxmax, + Rank1View bcxmax, LO ibcymin, + Rank1View bcymin, LO ibcymax, + Rank1View bcymax, + Rank1View wk); + + static KOKKOS_INLINE_FUNCTION void + lookup(T xget, T yget, Rank1View x, const LO &nx, + Rank1View y, const LO &ny, LO &i, LO &j, T &xparam, + T &yparam, T &hx, T &hxi, T &hy, T &hyi, LO &ier); + + static KOKKOS_INLINE_FUNCTION void + evalfn(Kokkos::View ict, LO ivec, LO ivecd, + Rank1View fval, const LO &i, const LO &j, + const T &xparam, const T &yparam, const T &hx, const T &hxi, + const T &hy, const T &hyi, Rank3View f); + + static KOKKOS_INLINE_FUNCTION void + eval(T xget, T yget, Kokkos::View ict, + Rank1View fval, // output (size depends on ict) + Rank1View x, const LO &nx, Rank1View y, + const LO &ny, Rank3View f, LO &ier); + void evaluate(Kokkos::View iselect, + Rank1View xvec, Rank1View yvec, + Rank2View fval); +}; + +template +void CubicSplineInterpolator::correction_detect( + Rank1View bcmin, LO &ibcmin, LO &iflg2, LO &nx) { + if (ibcmin == 1 || ibcmin == 2) { + Kokkos::parallel_reduce( + "check_nonzero", Kokkos::RangePolicy(0, nx), + KOKKOS_LAMBDA(const LO ix, LO &local_flag) { + if (bcmin(ix) != 0.0) { + local_flag = 1; + } + }, + Kokkos::Max(iflg2)); + } +} + +template +void CubicSplineInterpolator::sanity_check( + Rank1View x, const T &ztol) { + LO inx = static_cast(x.extent(0)); + + if (inx <= 1) + return; + + T dxavg = (get_element_from_span(x, inx - 1) - get_element_from_span(x, 0)) / + (inx - 1); + T zeps = std::abs(ztol * dxavg); + + Kokkos::parallel_for( + Kokkos::RangePolicy(1, inx), KOKKOS_LAMBDA(const LO ix) { + T zdiffx = x(ix) - x(ix - 1); + assert(zdiffx > 0.0); + T zdiff = zdiffx - dxavg; + assert(std::abs(zdiff) <= zeps); + }); +} + +template +ExplicitCubicSplineInterpolator:: + ExplicitCubicSplineInterpolator(Rank1View x, const LO &nx, + Rank2View fspl, + const LO &ibcxmin, const T &bcxmin, + const LO &ibcxmax, const T &bcxmax, + Rank1View wk) { + PCMS_ALWAYS_ASSERT(x.extent(0) >= 2); + this->nx_ = x.extent(0); + this->x_ = x; + setup(x, nx, fspl, ibcxmin, bcxmin, ibcxmax, bcxmax, wk); + this->fspl_ = fspl; +} + +template +void ExplicitCubicSplineInterpolator::setup( + Rank1View x, const LO &nx, Rank2View fspl, + const LO &ibcxmin, const T &bcxmin, const LO &ibcxmax, const T &bcxmax, + Rank1View wk) { + // TODO: pass member type to solve_spline + Kokkos::parallel_for( + "explicit cubic", Kokkos::TeamPolicy(1, Kokkos::AUTO), + KOKKOS_LAMBDA(const member_type &team_member) { + Kokkos::single(Kokkos::PerTeam(team_member), [=]() { + solve_spline(x, nx, fspl, ibcxmin, bcxmin, ibcxmax, bcxmax, wk); + }); + }); +} + +template +CompactCubicSplineInterpolator::CompactCubicSplineInterpolator( + Rank1View x, const LO &nx, Rank2View fspl, + Rank2View fspl4, const LO &ibcxmin, const T &bcxmin, + const LO &ibcxmax, const T &bcxmax, Rank1View wk) { + this->nx_ = x.extent(0); + this->x_ = x; + setup(x, nx, fspl, fspl4, ibcxmin, bcxmin, ibcxmax, bcxmax, wk); + this->fs2_ = fspl; +} + +template +void CompactCubicSplineInterpolator::setup( + Rank1View x, const LO &nx, Rank2View fspl, + Rank2View fspl4, const LO &ibcxmin, const T &bcxmin, + const LO &ibcxmax, const T &bcxmax, Rank1View wk) { + Kokkos::parallel_for( + "compact cubic", Kokkos::TeamPolicy(1, Kokkos::AUTO), + KOKKOS_LAMBDA(const member_type &team_member) { + Kokkos::single(Kokkos::PerTeam(team_member), [=]() { + solve_spline(x, nx, fspl, fspl4, ibcxmin, bcxmin, ibcxmax, bcxmax, + wk); + }); + }); +} + +template +KOKKOS_FUNCTION void +ExplicitCubicSplineInterpolator::solve_spline( + Rank1View x, const LO &nx, Rank2View fspl, + const LO &ibcxmin, const T &bcxmin, const LO &ibcxmax, const T &bcxmax, + Rank1View wk) { + + T half = 0.5; + T sixth = 0.166666666666666667; + + if (ibcxmin == 1) { + fspl(1, 0) = bcxmin; + } else if (ibcxmin == 2) { + fspl(2, 0) = bcxmin; + } + + if (ibcxmax == 1) { + fspl(1, nx - 1) = bcxmax; + } else if (ibcxmax == 2) { + fspl(2, nx - 1) = bcxmax; + } + CubicSplineInterpolator::v_spline(ibcxmin, ibcxmax, nx, x, + fspl, wk); + for (LO i = 0; i < nx; ++i) { + fspl(2, i) = half * fspl(2, i); + fspl(3, i) = sixth * fspl(3, i); + } +} + +template +KOKKOS_FUNCTION void CubicSplineInterpolator::v_spline( + const LO &k_bc1, const LO &k_bcn, const LO &n, Rank1View x, + Rank2View f, Rank1View wk) { + LO i_bc1 = k_bc1; + LO i_bcn = k_bcn; + LO iord1, iord2, imin, imax; + T a1, b1, an, bn, f0, fh, h; + const T dx = x(1) - x(0); + + // Clip to allowed ranges + if (i_bc1 < -1 || i_bc1 > 7) + i_bc1 = 0; // outside [-1,7] -> not-a-knot + if (i_bcn < 0 || i_bcn > 7) + i_bcn = 0; // outside [0,7] -> not-a-knot + + // Periodic BC handling + if (i_bc1 == -1) + i_bcn = -1; + + LO i3knots = 0; + LO i3perio = 0; + + if (n == 3) { + i_bc1 = std::min(6, i_bc1); + i_bcn = std::min(6, i_bcn); + + if (i_bc1 == 0) + i3knots += 1; + if (i_bcn == 0) + i3knots += 1; + if (i_bc1 == -1) + i3perio = 1; + } + + if (n == 2) { + if (i_bc1 == -1) { + i_bc1 = 5; + i_bcn = 5; + } + + if (i_bc1 == 0 || i_bc1 > 5) + i_bc1 = 5; + if (i_bcn == 0 || i_bcn > 5) + i_bcn = 5; + + // LHS match + if (i_bc1 == 1 || i_bc1 == 3 || i_bc1 == 5) + iord1 = 1; // first derivative match + else + iord1 = 2; // second derivative match + // RHS match + if (i_bcn == 1 || i_bcn == 3 || i_bcn == 5) + iord2 = 1; + else + iord2 = 2; + } + imin = 0; + imax = n - 1; + + a1 = 0.0; + b1 = 0.0; + an = 0.0; + bn = 0.0; + + if (i_bc1 == 1) { + a1 = f(1, 0); + } else if (i_bc1 == 2) { + b1 = f(2, 0); + } else if (i_bc1 == 5) { + a1 = (f(0, 1) - f(0, 0)) / dx; + } else if (i_bc1 == 6) { + b1 = 2.0 * ((f(0, 2) - f(0, 1)) / dx - (f(0, 1) - f(0, 0)) / dx) / (2 * dx); + } + + if (i_bcn == 1) { + an = f(1, n - 1); + } else if (i_bcn == 2) { + bn = f(2, n - 1); + } else if (i_bcn == 5) { + an = (f(0, n - 1) - f(0, n - 2)) / dx; + } else if (i_bcn == 6) { + bn = 2.0 * + ((f(0, n - 1) - f(0, n - 2)) / dx - (f(0, n - 2) - f(0, n - 3)) / dx) / + (2 * dx); + } + f(1, n - 1) = 0.0; + f(2, n - 1) = 0.0; + f(3, n - 1) = 0.0; + if (n == 2) { + if (i_bc1 == 5 && i_bcn == 5) { + // Coefficients for n = 2 + f(1, 0) = (f(0, 1) - f(0, 0)) / dx; + f(2, 0) = 0.0; + f(3, 0) = 0.0; + f(1, 1) = f(1, 0); + f(2, 1) = 0.0; + f(3, 1) = 0.0; + } else if (iord1 == 1 && iord2 == 1) { + T a1 = f(1, 0), an = f(1, 1); + f(1, 0) = a1; + f(1, 1) = an; + h = dx; + f0 = f(0, 0); + fh = f(0, 1); + + f(2, 0) = (3 * (fh - f0) / (h * h) - (2 * a1 + an) / h) * 2; // 2*c2 + f(3, 0) = + (-2 * (fh - f0) / (h * h * h) + (a1 + an) / (h * h)) * 6; // 6*c1 + + f(3, 1) = f(3, 0); + f(2, 1) = f(3, 0) * h + f(2, 0); + + } else if (iord1 == 1 && iord2 == 2) { + T a1 = f(1, 0), bn = f(2, 1); + f(1, 0) = a1; + f(2, 1) = bn; + h = dx; + f0 = f(0, 0); + fh = f(0, 1); + + f(2, 0) = (-bn / 4 + 3 * (fh - f0) / (2 * h * h) - 3 * a1 / (2 * h)) * 2; + f(3, 0) = + (bn / (4 * h) - (fh - f0) / (2 * h * h * h) + a1 / (2 * h * h)) * 6; + + f(3, 1) = f(3, 0); + f(1, 1) = f(3, 0) * h * h / 2 + f(2, 0) * h + a1; + + } else if (iord1 == 2 && iord2 == 1) { + T b1 = f(2, 0), an = f(1, 1); + f(2, 0) = b1; + f(1, 1) = an; + h = dx; + f0 = f(0, 0); + fh = f(0, 1); + + f(1, 0) = 3 * (fh - f0) / (2 * h) - b1 * h / 4 - an / 2; // c3 + f(3, 0) = + (an / (2 * h * h) - (fh - f0) / (2 * h * h * h) - b1 / (4 * h)) * 6; + + f(3, 1) = f(3, 0); + f(2, 1) = f(3, 0) * h + f(2, 0); + + } else if (iord1 == 2 && iord2 == 2) { + T b1 = f(2, 0), bn = f(2, 1); + f(2, 0) = b1; + f(2, 1) = bn; + h = dx; + f0 = f(0, 0); + fh = f(0, 1); + + f(1, 0) = (fh - f0) / h - b1 * h / 3 - bn * h / 6; + f(3, 0) = (bn - b1) / h; + + f(3, 1) = f(3, 0); + f(1, 1) = f(3, 0) * h * h / 2 + b1 * h + f(1, 0); + } + } // n == 2 + else if (i3perio == 1) { + h = 2 * dx; + + T dels = (f(0, 2) - f(0, 1)) / dx - (f(0, 1) - f(0, 0)) / dx; + + f(1, 0) = (f(0, 1) - f(0, 0)) / dx + (dx * dels) / h; + f(2, 0) = -6.0 * dels / h; + f(3, 0) = 12.0 * dels / (dx * h); + + f(1, 1) = (f(0, 2) - f(0, 1)) / dx - (dx * dels) / h; + f(2, 1) = 6.0 * dels / h; + f(3, 1) = -12.0 * dels / (dx * h); + + f(1, 2) = f(1, 0); + f(2, 2) = f(2, 0); + f(3, 2) = f(3, 0); + } // i3perio == 1 + else if (i3knots == 2) { + // Special case: nx = 3, not-a-knot on both sides + h = 2 * dx; + + T f1 = f(0, 0) - f(0, 1); + T f2 = f(0, 2) - f(0, 1); + + // Solve quadratic through 3 points centered at x[1] + T aa = (f2 * dx + f1 * dx) / (dx * dx * h); + T bb = (f2 * dx * dx - f1 * dx * dx) / (dx * dx * h); + + // Third derivative = 0 (quadratic) + f(3, 0) = 0.0; + f(3, 1) = 0.0; + f(3, 2) = 0.0; + + // Second derivative is constant + f(2, 0) = 2 * aa; + f(2, 1) = 2 * aa; + f(2, 2) = 2 * aa; + + // First derivatives + f(1, 0) = bb - 2 * aa * dx; + f(1, 1) = bb; + f(1, 2) = bb + 2 * aa * dx; + } // i3knots == 2 + else if (i3knots == 1) { + if (i_bc1 == 1 || i_bc1 == 3 || i_bc1 == 5) { + // f' LHS condition; not-a-knot RHS + T h3 = 2 * dx; + + T f2 = f(0, 1) - f(0, 0); + T f3 = f(0, 2) - f(0, 0); + + T aa = a1 / (dx * h3) + f3 / (h3 * h3 * (h3 - dx)) - + f2 / (dx * dx * (h3 - dx)); + T bb = -a1 * (h3 * h3 - dx * dx) / (dx * h3 * (h3 - dx)) + + f2 * h3 / (dx * dx * (h3 - dx)) - f3 * dx / (h3 * h3 * (h3 - dx)); + + f(1, 0) = a1; + f(2, 0) = 2 * bb; + f(3, 0) = 6 * aa; + + f(1, 1) = 3 * aa * dx * dx + 2 * bb * dx + a1; + f(2, 1) = 6 * aa * dx + 2 * bb; + f(3, 1) = 6 * aa; + + f(1, 2) = 3 * aa * h3 * h3 + 2 * bb * h3 + a1; + f(2, 2) = 6 * aa * h3 + 2 * bb; + f(3, 2) = 6 * aa; + + } else if (i_bc1 == 2 || i_bc1 == 4 || i_bc1 == 6) { + // f'' LHS condition; not-a-knot RHS + T h3 = 2 * dx; + + T f2 = f(0, 1) - f(0, 0); + T f3 = f(0, 2) - f(0, 0); + + T aa = -(b1 / 2.0) * (h3 - dx) / (h3 * h3 - dx * dx) - + f2 / (dx * (h3 * h3 - dx * dx)) + f3 / (h3 * (h3 * h3 - dx * dx)); + T bb = -(b1 / 2.0) * dx * h3 * (h3 - dx) / (h3 * h3 - dx * dx) + + f2 * h3 * h3 / (dx * (h3 * h3 - dx * dx)) - + f3 * dx * dx / (h3 * (h3 * h3 - dx * dx)); + + f(1, 0) = bb; + f(2, 0) = b1; + f(3, 0) = 6 * aa; + + f(1, 1) = 3 * aa * dx * dx + b1 * dx + bb; + f(2, 1) = 6 * aa * dx + b1; + f(3, 1) = 6 * aa; + + f(1, 2) = 3 * aa * h3 * h3 + b1 * h3 + bb; + f(2, 2) = 6 * aa * h3 + b1; + f(3, 2) = 6 * aa; + + } else if (i_bcn == 1 || i_bcn == 3 || i_bcn == 5) { + // f' RHS condition; not-a-knot LHS + T h2 = -dx; + T h3 = -2 * dx; + + T f2 = f(0, 1) - f(0, 2); + T f3 = f(0, 0) - f(0, 2); + + T aa = an / (h2 * h3) + f3 / (h3 * h3 * (h3 - h2)) - + f2 / (h2 * h2 * (h3 - h2)); + T bb = -an * (h3 * h3 - h2 * h2) / (h2 * h3 * (h3 - h2)) + + f2 * h3 / (h2 * h2 * (h3 - h2)) - f3 * h2 / (h3 * h3 * (h3 - h2)); + + f(1, 2) = an; + f(2, 2) = 2 * bb; + f(3, 2) = 6 * aa; + + f(1, 1) = 3 * aa * h2 * h2 + 2 * bb * h2 + an; + f(2, 1) = 6 * aa * h2 + 2 * bb; + f(3, 1) = 6 * aa; + + f(1, 0) = 3 * aa * h3 * h3 + 2 * bb * h3 + an; + f(2, 0) = 6 * aa * h3 + 2 * bb; + f(3, 0) = 6 * aa; + + } else if (i_bcn == 2 || i_bcn == 4 || i_bcn == 6) { + // f'' RHS condition; not-a-knot LHS + T h2 = -dx; + T h3 = -2 * dx; + + T f2 = f(0, 1) - f(0, 2); + T f3 = f(0, 0) - f(0, 2); + + T aa = -(bn / 2.0) * (h3 - h2) / (h3 * h3 - h2 * h2) - + f2 / (h2 * (h3 * h3 - h2 * h2)) + f3 / (h3 * (h3 * h3 - h2 * h2)); + T bb = -(bn / 2.0) * h2 * h3 * (h3 - h2) / (h3 * h3 - h2 * h2) + + f2 * h3 * h3 / (h2 * (h3 * h3 - h2 * h2)) - + f3 * h2 * h2 / (h3 * (h3 * h3 - h2 * h2)); + + f(1, 2) = bb; + f(2, 2) = bn; + f(3, 2) = 6 * aa; + + f(1, 1) = 3 * aa * h2 * h2 + bn * h2 + bb; + f(2, 1) = 6 * aa * h2 + bn; + f(3, 1) = 6 * aa; + + f(1, 0) = 3 * aa * h3 * h3 + bn * h3 + bb; + f(2, 0) = 6 * aa * h3 + bn; + f(3, 0) = 6 * aa; + } + } // i3knots == 1 + else if (n > 2) { + f(3, 0) = dx; + f(2, 1) = (f(0, 1) - f(0, 0)) / f(3, 0); + + for (LO i = 1; i < n - 1; ++i) { + f(3, i) = dx; + f(1, i) = 2.0 * (f(3, i - 1) + f(3, i)); + f(2, i + 1) = (f(0, i + 1) - f(0, i)) / f(3, i); + f(2, i) = f(2, i + 1) - f(2, i); + } + + T elem21 = f(3, 0); + T elemnn1 = f(3, n - 2); + + // Left boundary conditions + if (i_bc1 == -1) { + f(1, 0) = 2.0 * (f(3, 0) + f(3, n - 2)); + f(2, 0) = (f(0, 1) - f(0, 0)) / f(3, 0) - + (f(0, n - 1) - f(0, n - 2)) / f(3, n - 2); + wk[0] = f(3, n - 2); + for (LO i = 1; i <= n - 4; ++i) + wk[i] = 0.0; + wk[n - 3] = f(3, n - 3); + wk[n - 2] = f(3, n - 2); + } else if (i_bc1 == 1 || i_bc1 == 3 || i_bc1 == 5) { + f(1, 0) = 2.0 * f(3, 0); + f(2, 0) = (f(0, 1) - f(0, 0)) / f(3, 0) - a1; + } else if (i_bc1 == 2 || i_bc1 == 4 || i_bc1 == 6) { + f(1, 0) = 2.0 * f(3, 0); + f(2, 0) = f(3, 0) * b1 / 3.0; + f(3, 0) = 0.0; + } else if (i_bc1 == 7) { + f(1, 0) = -f(3, 0); + f(2, 0) = f(2, 2) / (2 * dx) - f(2, 1) / (2 * dx); + f(2, 0) *= f(3, 0) * f(3, 0) / (3 * dx); + } else { + imin = 1; + f(1, 1) = f(3, 0) + 2.0 * f(3, 1); + f(2, 1) = f(2, 1) * f(3, 1) / (f(3, 0) + f(3, 1)); + } + + // Right boundary conditions + if (i_bcn == 1 || i_bcn == 3 || i_bcn == 5) { + f(1, n - 1) = 2.0 * f(3, n - 2); + f(2, n - 1) = -(f(0, n - 1) - f(0, n - 2)) / f(3, n - 2) + an; + } else if (i_bcn == 2 || i_bcn == 4 || i_bcn == 6) { + f(1, n - 1) = 2.0 * f(3, n - 2); + f(2, n - 1) = f(3, n - 2) * bn / 3.0; + elemnn1 = 0.0; + } else if (i_bcn == 7) { + f(1, n - 1) = -f(3, n - 2); + f(2, n - 1) = f(2, n - 2) / (2 * dx) - f(2, n - 3) / (2 * dx); + f(2, n - 1) = -f(2, n - 1) * f(3, n - 2) * f(3, n - 2) / (3 * dx); + } else if (i_bc1 != -1) { + imax = n - 2; + f(1, n - 2) = 2.0 * f(3, n - 3) + f(3, n - 2); + f(2, n - 2) = f(2, n - 2) * f(3, n - 3) / (f(3, n - 2) + f(3, n - 3)); + } + if (i_bc1 == -1) { + // Periodic Boundary Conditions + + // Forward elimination + for (LO i = 1; i <= n - 3; ++i) { + T t = f(3, i - 1) / f(1, i - 1); + f(1, i) -= t * f(3, i - 1); + f(2, i) -= t * f(2, i - 1); + wk[i] -= t * wk[i - 1]; + + T q = wk[n - 2] / f(1, i - 1); + wk[n - 2] = -q * f(3, i - 1); + f(1, n - 2) -= q * wk[i - 1]; + f(2, n - 2) -= q * f(2, i - 1); + } + + wk[n - 2] += f(3, n - 3); + + // Complete forward elimination + T t = wk[n - 2] / f(1, n - 3); + f(1, n - 2) -= t * wk[n - 3]; + f(2, n - 2) -= t * f(2, n - 3); + + // Back substitution + f(2, n - 2) /= f(1, n - 2); + f(2, n - 3) = (f(2, n - 3) - wk[n - 3] * f(2, n - 2)) / f(1, n - 3); + for (LO ib = 2; ib <= n - 2; ++ib) { + LO i = n - ib - 2; + f(2, i) = + (f(2, i) - f(3, i) * f(2, i + 1) - wk[i] * f(2, n - 2)) / f(1, i); + } + + f(2, n - 1) = f(2, 0); + + } else { + // Non-periodic Boundary Conditions + + for (LO i = imin + 1; i <= imax; ++i) { + T t; + if ((i == n - 2) && (imax == n - 2)) { + t = (f(3, i - 1) - f(3, i)) / f(1, i - 1); + } else if (i == 1) { + t = elem21 / f(1, i - 1); + } else if (i == n - 1) { + t = elemnn1 / f(1, i - 1); + } else { + t = f(3, i - 1) / f(1, i - 1); + } + + if ((i == imin + 1) && (imin == 1)) { + f(1, i) -= t * (f(3, i - 1) - f(3, i - 2)); + } else { + f(1, i) -= t * f(3, i - 1); + } + + f(2, i) -= t * f(2, i - 1); + } + + f(2, imax) /= f(1, imax); + for (LO ib = 0; ib < imax - imin; ++ib) { + LO i = imax - 1 - ib; + if ((i == 1) && (imin == 1)) { + f(2, i) = (f(2, i) - (f(3, i) - f(3, i - 1)) * f(2, i + 1)) / f(1, i); + } else { + f(2, i) = (f(2, i) - f(3, i) * f(2, i + 1)) / f(1, i); + } + } + + f(3, 0) = dx; + f(3, n - 2) = dx; + + if (i_bc1 <= 0 || i_bc1 > 7) { + f(2, 0) = (f(2, 1) * (f(3, 0) + f(3, 1)) - f(2, 2) * f(3, 0)) / f(3, 1); + } + + if (i_bcn <= 0 || i_bcn > 7) { + f(2, n - 1) = f(2, n - 2) + + (f(2, n - 2) - f(2, n - 3)) * f(3, n - 2) / f(3, n - 3); + } + } + + // Polynomial coefficient computation + for (LO i = 0; i < n - 1; ++i) { + f(1, i) = (f(0, i + 1) - f(0, i)) / f(3, i) - + f(3, i) * (f(2, i + 1) + 2.0 * f(2, i)); + f(3, i) = (f(2, i + 1) - f(2, i)) / f(3, i); + f(2, i) *= 6.0; + f(3, i) *= 6.0; + } + + if (i_bc1 == -1) { + f(1, n - 1) = f(1, 0); + f(2, n - 1) = f(2, 0); + f(3, n - 1) = f(3, 0); + } else { + f(1, n - 1) = f(1, n - 2) + dx * (f(2, n - 2) + 0.5 * dx * f(3, n - 2)); + f(2, n - 1) = f(2, n - 2) + dx * f(3, n - 2); + f(3, n - 1) = f(3, n - 2); + + if (i_bcn == 1 || i_bcn == 3 || i_bcn == 5) { + f(1, n - 1) = an; + } else if (i_bcn == 2 || i_bcn == 4 || i_bcn == 6) { + f(2, n - 1) = bn; + } + } + } +} // v_spline + +template +KOKKOS_INLINE_FUNCTION void +CubicSplineInterpolator::range_check( + T &xget, T &zxget, Rank1View x, const LO &nx, LO &ier) { + if (xget < x[0] || xget > x[nx - 1]) { + T zxtol = 4.0e-7 * std::max(std::abs(x[0]), std::abs(x[nx - 1])); + + if (xget < x[0] - zxtol || xget > x[nx - 1] + zxtol) { + ier = 1; // Error code for out of range + printf("lookup: xget=%.6f out of range %.6f to %.6f\n", xget, x[0], + x[nx - 1]); + + return; + } else { + printf("lookup: xget=%.6f beyond range %.6f to %.6f (fixup applied)\n", + xget, x[0], x[nx - 1]); + zxget = (xget < x[0]) ? x[0] : x[nx - 1]; + } + } +} + +template +KOKKOS_INLINE_FUNCTION void +ExplicitCubicSplineInterpolator::evalfn( + Kokkos::View selector, Rank1View fval, + const LO &i, const T &dx, Rank2View fspl) { + + LO iaval = 0; + + if (selector[0] == 3) { + // Third derivative only + iaval++; + fval(iaval - 1) = 6.0 * fspl(3, i); + } else { + if (selector[0] > 0) { + // Evaluate f + iaval++; + fval(iaval - 1) = + fspl(0, i) + dx * (fspl(1, i) + dx * (fspl(2, i) + dx * fspl(3, i))); + } + + if (selector[1] > 0) { + // Evaluate df/dx + iaval++; + fval(iaval - 1) = + fspl(1, i) + dx * (2.0 * fspl(2, i) + dx * 3.0 * fspl(3, i)); + } + + if (selector[2] > 0) { + // Evaluate d2f/dx2 + iaval++; + fval(iaval - 1) = 2.0 * fspl(2, i) + dx * 6.0 * fspl(3, i); + } + } +} // end evalfn + +template +KOKKOS_INLINE_FUNCTION void +ExplicitCubicSplineInterpolator::eval( + T xget, Kokkos::View iselect, + Rank1View fval, Rank1View x, const LO &nx, + Rank2View fspl, LO &ier) { + LO ia = 0; + T dxa = 0.0; + lookup(xget, x, nx, ia, dxa, ier); + if (ier != 0) { + printf("error in evaluation, ier = %d\n", ier); + return; + } + + evalfn(iselect, fval, ia, dxa, fspl); +} + +template +KOKKOS_INLINE_FUNCTION void +ExplicitCubicSplineInterpolator::lookup( + T xget, Rank1View x, const LO &nx, LO &i, T &dx, LO &ier) { + LO nxm = nx - 1; + T zxget = xget; + + // Range check + CubicSplineInterpolator::range_check(xget, zxget, x, nx, ier); + + LO ii = static_cast(nxm * (zxget - x[0]) / (x[nx - 1] - x[0])); + i = std::min(nxm - 1, ii); + + if (zxget < x[i]) { + i = std::max(0, i - 1); + } else if (zxget > x[i + 1]) { + i = std::min(nxm - 1, i + 1); + } + + dx = zxget - x[i]; +} + +// TODO: take member type as parameter for further optimization +template +KOKKOS_FUNCTION void +CompactCubicSplineInterpolator::solve_spline( + Rank1View x, const LO &nx, Rank2View fspl, + Rank2View fspl4, const LO &ibcxmin, const T &bcxmin, + const LO &ibcxmax, const T &bcxmax, Rank1View wk) { + // Copy f data to fspl4 and zero out second derivative output + for (LO i = 0; i < nx; ++i) { + fspl4(0, i) = fspl(0, i); + fspl(1, i) = 0.0; + } + + // Call traditional spline generator + ExplicitCubicSplineInterpolator::solve_spline( + x, nx, fspl4, ibcxmin, bcxmin, ibcxmax, bcxmax, wk); + + for (LO i = 0; i < nx - 1; ++i) { + fspl(1, i) = 2.0 * fspl4(2, i); + } + + fspl(1, nx - 1) = + 2.0 * fspl4(2, nx - 2) + (x[nx - 1] - x[nx - 2]) * 6.0 * fspl4(3, nx - 2); +} + +template +void ExplicitCubicSplineInterpolator::evaluate( + const Kokkos::View selector, + Rank1View xvec, Rank2View fval) { + LO ivd = fval.extent(1); + Kokkos::parallel_for( + Kokkos::RangePolicy(0, xvec.extent(0)), + KOKKOS_CLASS_LAMBDA(const LO i) { + LO ier = 0; + auto fval_view = + Rank1View(fval.data_handle() + i * ivd, ivd); + eval(xvec(i), selector, fval_view, this->x_, this->nx_, this->fspl_, + ier); + }); +} + +template +void CompactCubicSplineInterpolator::evaluate( + Kokkos::View selector, Rank1View xvec, + Rank2View fval) { + LO ivd = fval.extent(1); + Kokkos::parallel_for( + Kokkos::RangePolicy(0, xvec.extent(0)), + KOKKOS_CLASS_LAMBDA(const LO i) { + LO ier = 0; + auto fval_view = + Rank1View(fval.data_handle() + i * ivd, ivd); + eval(xvec(i), selector, fval_view, this->x_, this->nx_, this->fs2_, + ier); + }); +} + +template +KOKKOS_INLINE_FUNCTION void +CompactCubicSplineInterpolator::evalfn( + Kokkos::View selector, Rank1View fval, + const LO &i, const T &xparam, const T &hx, const T &hxi, + Rank2View fs2) { + const T sixth = 1.0 / 6.0; + LO iadr = 0; + + if (selector[0] <= 2) { + if (selector[0] == 1) { + // Function value f(x) + ++iadr; + // TODO: too much temp varibale created? + T xp = xparam; + T xpi = 1.0 - xp; + T xp2 = xp * xp; + T xpi2 = xpi * xpi; + T cx = xp * (xp2 - 1.0); + T cxi = xpi * (xpi2 - 1.0); + T hx2 = hx * hx; + + T sum = xpi * fs2(0, i) + xp * fs2(0, i + 1); + sum += sixth * hx2 * (cxi * fs2(1, i) + cx * fs2(1, i + 1)); + + fval(iadr - 1) = sum; // zero-based indexing + } + + if (selector[1] == 1) { + // First derivative df/dx + ++iadr; + T xp = xparam; + T xpi = 1.0 - xp; + T xp2 = xp * xp; + T xpi2 = xpi * xpi; + + T cxd = 3.0 * xp2 - 1.0; + T cxdi = -3.0 * xpi2 + 1.0; + + T sum = hxi * (fs2(0, i + 1) - fs2(0, i)); + sum += sixth * hx * (cxdi * fs2(1, i) + cxd * fs2(1, i + 1)); + + fval(iadr - 1) = sum; + } + + if (selector[2] == 1) { + // Second derivative d2f/dx2 + ++iadr; + T xp = xparam; + T xpi = 1.0 - xp; + + T sum = xpi * fs2(1, i) + xp * fs2(1, i + 1); + fval(iadr - 1) = sum; + } + + } else { + // Third derivative d3f/dx3 + iadr = 1; + fval(iadr - 1) = hxi * (fs2(1, i + 1) - fs2(1, i)); + } +} + +template +KOKKOS_INLINE_FUNCTION void +CompactCubicSplineInterpolator::lookup( + T xget, Rank1View x, const LO &nx, LO &i, T &xparam, T &hx, + T &hxi, LO &ier) { + ier = 0; + + T zxget = xget; + + CubicSplineInterpolator::range_check(xget, zxget, x, nx, ier); + + LO nxm = nx - 1; + + // TODO: potential duplicate code + LO ii = static_cast(nxm * (zxget - x[0]) / (x[nx - 1] - x[0])); + i = std::min(nxm - 1, ii); + if (zxget < x[i]) { + i = std::max(0, i - 1); + } else if (zxget > x[i + 1]) { + i = std::min(nxm - 2, i + 1); + } + + hx = x[i + 1] - x[i]; + hxi = 1.0 / hx; + xparam = (zxget - x[i]) * hxi; +} + +template +KOKKOS_INLINE_FUNCTION void +CompactCubicSplineInterpolator::eval( + T xget, Kokkos::View ict, Rank1View fval, + Rank1View x, + const LO &nx, // size of x + Rank2View fs2, LO &ier) { + + // Initialize output zone info + LO i = 0; + T xparam = 0.0; + T hx = 0.0; + T hxi = 0.0; + + // Find the interval containing xget + lookup(xget, x, nx, i, xparam, hx, hxi, ier); + if (ier != 0) + return; + + // Evaluate spline at the points + evalfn(ict, fval, i, xparam, hx, hxi, fs2); +} + +template +ExplicitBiCubicSplineInterpolator:: + ExplicitBiCubicSplineInterpolator( + Rank1View x, // size: inx + LO inx, Rank1View th, // size: inth + LO inth, Rank4View fspl, // [4, 4, inx, inth] + LO ibcxmin, + Rank1View + bcxmin, // size: inth (used if ibcxmin = 1 or 2) + LO ibcxmax, + Rank1View + bcxmax, // size: inth (used if ibcxmax = 1 or 2) + LO ibcthmin, + Rank1View + bcthmin, // size: inx (used if ibcthmin = 1 or 2) + LO ibcthmax, + Rank1View + bcthmax, // size: inx (used if ibcthmax = 1 or 2) + Rank1View wk // size: nwk + ) { + PCMS_ALWAYS_ASSERT(inx >= 2); + PCMS_ALWAYS_ASSERT(inth >= 2); + + // Check boundary condition values + ibc_check(ibcxmin, "2d spline", "xmin", -1, 7); + if (ibcxmin >= 0) + ibc_check(ibcxmax, "2d spline", "xmax", 0, 7); + ibc_check(ibcthmin, "2d spline", "thmin", -1, 7); + if (ibcthmin >= 0) + ibc_check(ibcthmax, "2d spline", "thmax", 0, 7); + + CubicSplineInterpolator::sanity_check(x, 1.0e-3); + CubicSplineInterpolator::sanity_check(th, 1.0e-3); + this->x_ = x; + this->nx_ = inx; + this->y_ = th; + this->ny_ = inth; + + solve_spline(x, inx, th, inth, fspl, ibcxmin, bcxmin, ibcxmax, bcxmax, + ibcthmin, bcthmin, ibcthmax, bcthmax, wk); + + fspl_ = fspl; +} + +template +void ExplicitBiCubicSplineInterpolator::solve_spline( + Rank1View x, // size: inx + LO inx, Rank1View th, // size: inth + LO inth, Rank4View fspl, // [4, 4, inx, inth] + LO ibcxmin, + Rank1View bcxmin, // size: inth (used if ibcxmin = 1 or 2) + LO ibcxmax, + Rank1View bcxmax, // size: inth (used if ibcxmax = 1 or 2) + LO ibcthmin, + Rank1View bcthmin, // size: inx (used if ibcthmin = 1 or 2) + LO ibcthmax, + Rank1View bcthmax, // size: inx (used if ibcthmax = 1 or 2) + Rank1View wk // size: nwk +) { + LO iflg2 = 0; + + auto fspl_l_x = Rank2View(wk.data_handle() + 4 * inx * inth, + 4 * inx, inth); + auto wk_l = Rank1View(wk.data_handle() + 2 * 4 * inx * inth, + inx * inth); + auto fspl_l_th = Rank2View(wk.data_handle(), 4 * inx, inth); + + if (ibcthmin != -1) { + CubicSplineInterpolator::correction_detect( + bcthmin, ibcthmin, iflg2, inx); + CubicSplineInterpolator::correction_detect( + bcthmax, ibcthmax, iflg2, inx); + } + + T xo2 = 0.5; + T xo6 = 1.0 / 6.0; + + Kokkos::parallel_for( + Kokkos::TeamPolicy(inth, Kokkos::AUTO), + KOKKOS_LAMBDA(const member_type &team) { + const LO ith = team.league_rank(); + + auto fspl_x_view = Rank2View( + fspl_l_x.data_handle() + 4 * inx * ith, 4, inx); + auto wk_x_view = + Rank1View(wk_l.data_handle() + ith * inx, inx); + + Kokkos::parallel_for(Kokkos::TeamThreadRange(team, inx), [=](LO ix) { + fspl_x_view(0, ix) = fspl(0, 0, ix, ith); + }); + + if (team.team_rank() == 0) { + if (ibcxmin == 1) + fspl_x_view(1, 0) = bcxmin[ith]; + else if (ibcxmin == 2) + fspl_x_view(2, 0) = bcxmin[ith]; + + if (ibcxmax == 1) + fspl_x_view(1, inx - 1) = bcxmax[ith]; + else if (ibcxmax == 2) + fspl_x_view(2, inx - 1) = bcxmax[ith]; + + CubicSplineInterpolator::v_spline( + ibcxmin, ibcxmax, inx, x, fspl_x_view, wk_x_view); + } + + Kokkos::parallel_for(Kokkos::TeamThreadRange(team, inx), [=](LO ix) { + fspl(1, 0, ix, ith) = fspl_x_view(1, ix); + fspl(2, 0, ix, ith) = fspl_x_view(2, ix) * xo2; + fspl(3, 0, ix, ith) = fspl_x_view(3, ix) * xo6; + }); + }); + + Kokkos::parallel_for( + Kokkos::TeamPolicy(inx, Kokkos::AUTO), + KOKKOS_LAMBDA(const member_type &team) { + const LO ix = team.league_rank(); + + auto fspl_th_view = Rank2View( + fspl_l_th.data_handle() + 4 * ix * inth, 4, inth); + auto wk_th_view = + Rank1View(wk_l.data_handle() + ix * inth, inth); + + for (LO ic = 0; ic < 4; ++ic) { + Kokkos::parallel_for( + Kokkos::TeamThreadRange(team, inth), + [=](LO ith) { fspl_th_view(0, ith) = fspl(ic, 0, ix, ith); }); + + // Set linear BCs initially + if (team.team_rank() == 0) { + fspl_th_view(1, 0) = 0.0; + fspl_th_view(2, 0) = 0.0; + fspl_th_view(1, inth - 1) = 0.0; + fspl_th_view(2, inth - 1) = 0.0; + + LO ibcthmina = ibcthmin; + LO ibcthmaxa = ibcthmax; + if (iflg2 == 1) { + if (ibcthmin == 1 || ibcthmin == 2) + ibcthmina = 0; + if (ibcthmax == 1 || ibcthmax == 2) + ibcthmaxa = 0; + } + + CubicSplineInterpolator::v_spline( + ibcthmina, ibcthmaxa, inth, th, fspl_th_view, wk_th_view); + } + + Kokkos::parallel_for( + Kokkos::TeamThreadRange(team, inth), [=](LO ith) { + fspl(ic, 1, ix, ith) = fspl_th_view(1, ith); + fspl(ic, 2, ix, ith) = fspl_th_view(2, ith) * xo2; + fspl(ic, 3, ix, ith) = fspl_th_view(3, ith) * xo6; + }); + } + }); + + if (iflg2 == 1) { + LO iasc = 0; // Workspace base for correction splines + LO iinc = 4 * inth; // Spacing between correction splines + + T zhxn = + get_element_from_span(x, inx - 1) - get_element_from_span(x, inx - 2); + T zhth = get_element_from_span(th, inth - 1) - + get_element_from_span(th, inth - 2); + + LO jx = inx - 2; + LO jth = inth - 2; + + LO iselect1_arr[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + LO iselect2_arr[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + if (ibcthmin == 1) + iselect1_arr[2] = 1; + if (ibcthmin == 2) + iselect1_arr[4] = 1; + if (ibcthmax == 1) + iselect2_arr[2] = 1; + if (ibcthmax == 2) + iselect2_arr[4] = 1; + Kokkos::View iselect1("iselect1", 10); + Kokkos::parallel_for( + Kokkos::RangePolicy(0, iselect1.size()), + KOKKOS_LAMBDA(const LO i) { iselect1(i) = iselect1_arr[i]; }); + Kokkos::View iselect2("iselect2", 10); + Kokkos::parallel_for( + Kokkos::RangePolicy(0, iselect2.size()), + KOKKOS_LAMBDA(const LO i) { iselect2(i) = iselect2_arr[i]; }); + + auto zcur_shared = + Rank1View(fspl_l_x.data_handle(), inx * 3); + + Kokkos::parallel_for( + Kokkos::RangePolicy(0, inx), + KOKKOS_LAMBDA(const LO ix) { + LO ier = 0; + auto zcur = + Rank1View(zcur_shared.data_handle() + ix * 3, 3); + T zdiff1 = 0.0, zdiff2 = 0.0; + auto wk_th = Rank1View(wk_l.data_handle(), inth); + + if (ibcthmin == 1) { + zcur[0] = (ix < inx - 1) + ? fspl(0, 1, ix, 0) + : fspl(0, 1, jx, 0) + + zhxn * (fspl(1, 1, jx, 0) + + zhxn * (fspl(2, 1, jx, 0) + + zhxn * fspl(3, 1, jx, 0))); + zdiff1 = bcthmin[ix] - zcur[0]; + } else if (ibcthmin == 2) { + zcur[0] = (ix < inx - 1) + ? 2.0 * fspl(0, 2, ix, 0) + : 2.0 * (fspl(0, 2, jx, 0) + + zhxn * (fspl(1, 2, jx, 0) + + zhxn * (fspl(2, 2, jx, 0) + + zhxn * fspl(3, 2, jx, 0)))); + zdiff1 = bcthmin[ix] - zcur[0]; + } + + // auto zcur = Rank1View(zcur_vec.data(), 3); + if (ibcthmax == 1) { + if (ix < inx - 1) { + zcur(0) = fspl(0, 1, ix, jth) + + zhth * (2.0 * fspl(0, 2, ix, jth) + + zhth * 3.0 * fspl(0, 3, ix, jth)); + } else { + // TODO: check if this is correct + eval(x[inx - 1], th[inth - 1], iselect2, zcur, x, inx, th, inth, + fspl, ier); + if (ier != 0) + return; + } + zdiff2 = bcthmax[ix] - zcur(0); + } else if (ibcthmax == 2) { + if (ix < inx - 1) { + zcur(0) = + 2.0 * fspl(0, 2, ix, jth) + 6.0 * zhth * fspl(0, 3, ix, jth); + } else { + // TODO: check if this is correct + eval(x[inx - 1], th[inth - 1], iselect2, zcur, x, inx, th, inth, + fspl, ier); + if (ier != 0) + return; + } + zdiff2 = bcthmax[ix] - zcur(0); + } + + LO iadr = iasc + ix * iinc; + for (LO ith = 0; ith < inth; ++ith) + fspl_l_th(ix * 4, ith) = 0.0; + + fspl_l_th(1 + ix * 4, 0) = 0.0; + fspl_l_th(2 + ix * 4, 0) = 0.0; + fspl_l_th(1 + ix * 4, inth - 1) = 0.0; + fspl_l_th(2 + ix * 4, inth - 1) = 0.0; + + if (ibcthmin == 1) + fspl_l_th(1 + ix * 4, 0) = zdiff1; + else if (ibcthmin == 2) + fspl_l_th(2 + ix * 4, 0) = zdiff1; + + if (ibcthmax == 1) + fspl_l_th(1 + ix * 4, inth - 1) = zdiff2; + else if (ibcthmax == 2) + fspl_l_th(2 + ix * 4, inth - 1) = zdiff2; + + auto fspl_s_th = Rank2View( + fspl_l_th.data_handle() + iadr, 4, inth); + CubicSplineInterpolator::v_spline( + ibcthmin, ibcthmax, inth, th, fspl_s_th, wk_th); + }); + + Kokkos::parallel_for( + Kokkos::MDRangePolicy>({0, 0}, {inx, inth - 1}), + KOKKOS_LAMBDA(const LO ix, const LO ith) { + // Multiply local coefficients + fspl_l_th(2 + ix * 4, ith) *= xo2; + fspl_l_th(3 + ix * 4, ith) *= xo6; + + // Conditional accumulation LOo global fspl + if (ix < inx - 1) { + fspl(0, 1, ix, ith) += fspl_l_th(1 + ix * 4, ith); + fspl(0, 2, ix, ith) += fspl_l_th(2 + ix * 4, ith); + fspl(0, 3, ix, ith) += fspl_l_th(3 + ix * 4, ith); + } + }); + Kokkos::parallel_for( + Kokkos::TeamPolicy(inth - 1, Kokkos::AUTO), + KOKKOS_LAMBDA(const member_type &team) { + const LO ith = team.league_rank(); + + auto fspl_x_view = Rank2View( + fspl_l_x.data_handle() + 4 * inx * ith, 4, inx); + auto wk_x_view = + Rank1View(wk_l.data_handle() + ith * inx, inx); + + for (LO ic = 1; ic < 4; ++ic) { + Kokkos::parallel_for( + Kokkos::TeamThreadRange(team, inx), [=](LO ix) { + fspl_x_view(0, ix) = fspl_l_th(ic + ix * 4, ith); + }); + + if (team.team_rank() == 0) { + fspl_x_view(1, 0) = 0.0; + fspl_x_view(2, 0) = 0.0; + fspl_x_view(1, inx - 1) = 0.0; + fspl_x_view(2, inx - 1) = 0.0; + + CubicSplineInterpolator::v_spline( + ibcxmin, ibcxmax, inx, x, fspl_x_view, wk_x_view); + } + + Kokkos::parallel_for( + Kokkos::TeamThreadRange(team, inx - 1), [=](LO ix) { + fspl(1, ic, ix, ith) += fspl_x_view(1, ix); + fspl(2, ic, ix, ith) += fspl_x_view(2, ix) * xo2; + fspl(3, ic, ix, ith) += fspl_x_view(3, ix) * xo6; + }); + } + }); + } +} + +template +void ExplicitBiCubicSplineInterpolator::evaluate( + Kokkos::View iselect, Rank1View xvec, + Rank1View yvec, Rank2View fval) { + PCMS_ALWAYS_ASSERT(xvec.extent(0) == yvec.extent(0) && + xvec.extent(0) == fval.extent(0)); + + LO ivd = fval.extent(1); + Kokkos::parallel_for( + Kokkos::RangePolicy(0, xvec.extent(0)), + KOKKOS_CLASS_LAMBDA(const LO i) { + LO ier = 0; + auto fval_view = + Rank1View(fval.data_handle() + i * ivd, ivd); + eval(xvec(i), yvec(i), iselect, fval_view, this->x_, this->nx_, + this->y_, this->ny_, this->fspl_, ier); + }); +} + +template +void CompactBiCubicSplineInterpolator::evaluate( + Kokkos::View iselect, Rank1View xvec, + Rank1View yvec, Rank2View fval) { + + PCMS_ALWAYS_ASSERT(xvec.extent(0) == yvec.extent(0) && + xvec.extent(0) == fval.extent(0)); + LO ivd = fval.extent(1); + Kokkos::parallel_for( + Kokkos::RangePolicy(0, xvec.extent(0)), + KOKKOS_CLASS_LAMBDA(const LO i) { + LO ier = 0; + auto fval_view = + Rank1View(fval.data_handle() + i * ivd, ivd); + eval(xvec(i), yvec(i), iselect, fval_view, this->x_, this->nx_, + this->y_, this->ny_, this->f_, ier); + }); +} + +template +KOKKOS_INLINE_FUNCTION void +ExplicitBiCubicSplineInterpolator::eval( + T xget, T yget, Kokkos::View iselect, + Rank1View fval, Rank1View x, const LO &nx, + Rank1View y, const LO &ny, Rank4View fspl, + LO &ier) { + LO i = 0; + LO j = 0; + T dx = 0.0; + T dy = 0.0; + + // Range finding + lookup(xget, yget, x, nx, y, ny, i, j, dx, dy, ier); + if (ier != 0) + return; + + // Evaluate spline function + evalfn(iselect, fval, i, j, dx, dy, fspl); +} + +template +KOKKOS_INLINE_FUNCTION void +ExplicitBiCubicSplineInterpolator::lookup( + T xget, T yget, Rank1View x, const LO &nx, + Rank1View y, const LO &ny, LO &i, LO &j, T &dx, T &dy, + LO &ier) { + LO nxm = nx - 1; + LO nym = ny - 1; + LO ii, jj; + + ier = 0; + T zxget = xget; + T zyget = yget; + + CubicSplineInterpolator::range_check(xget, zxget, x, nx, ier); + CubicSplineInterpolator::range_check(yget, zyget, y, ny, ier); + + if (ier != 0) + return; + + ii = static_cast(nxm * (zxget - x[0]) / (x[nx - 1] - x[0])); + i = std::min(nxm - 2, ii); + if (zxget < x[i]) { + i--; + } else if (zxget > x[i + 1]) { + i++; + } + + jj = static_cast(nym * (zyget - y[0]) / (y[ny - 1] - y[0])); + j = std::min(nym - 2, jj); + if (zyget < y[j]) { + j--; + } else if (zyget > y[j + 1]) { + j++; + } + + dx = zxget - x[i]; + dy = zyget - y[j]; +} + +template +KOKKOS_INLINE_FUNCTION void +ExplicitBiCubicSplineInterpolator::evalfn( + Kokkos::View + ict, // Selector array for which derivatives to compute + Rank1View fval, // Output array: size [ivd, *] (flattened) + const LO &i, // Grid cell indices in x direction + const LO &j, // Grid cell indices in y direction + const T &dx, // x displacements within cells + const T &dy, // y displacements within cells + Rank4View fspl // Spline coefficients +) { + LO iaval = 0; // Index for fval + if (ict[0] <= 2) { + if ((ict[0] > 0) || (ict[0] == -1)) { + // Evaluate f + iaval++; + fval(iaval - 1) = + fspl(0, 0, i, j) + + dy * (fspl(0, 1, i, j) + + dy * (fspl(0, 2, i, j) + dy * fspl(0, 3, i, j))) + + dx * (fspl(1, 0, i, j) + + dy * (fspl(1, 1, i, j) + + dy * (fspl(1, 2, i, j) + dy * fspl(1, 3, i, j))) + + dx * (fspl(2, 0, i, j) + + dy * (fspl(2, 1, i, j) + + dy * (fspl(2, 2, i, j) + dy * fspl(2, 3, i, j))) + + dx * (fspl(3, 0, i, j) + + dy * (fspl(3, 1, i, j) + + dy * (fspl(3, 2, i, j) + + dy * fspl(3, 3, i, j)))))); + } + + if ((ict[1] > 0) && (ict[0] != -1)) { + // Evaluate df/dx + iaval++; + fval(iaval - 1) = + fspl(1, 0, i, j) + + dy * (fspl(1, 1, i, j) + + dy * (fspl(1, 2, i, j) + dy * fspl(1, 3, i, j))) + + 2.0 * dx * + (fspl(2, 0, i, j) + + dy * (fspl(2, 1, i, j) + + dy * (fspl(2, 2, i, j) + dy * fspl(2, 3, i, j))) + + 1.5 * dx * + (fspl(3, 0, i, j) + + dy * (fspl(3, 1, i, j) + + dy * (fspl(3, 2, i, j) + dy * fspl(3, 3, i, j))))); + } + + if ((ict[2] > 0) && (ict[0] != -1)) { + // Evaluate df/dy + iaval++; + fval(iaval - 1) = + fspl(0, 1, i, j) + + dy * (2.0 * fspl(0, 2, i, j) + dy * 3.0 * fspl(0, 3, i, j)) + + dx * (fspl(1, 1, i, j) + + dy * (2.0 * fspl(1, 2, i, j) + dy * 3.0 * fspl(1, 3, i, j)) + + dx * (fspl(2, 1, i, j) + + dy * (2.0 * fspl(2, 2, i, j) + + dy * 3.0 * fspl(2, 3, i, j)) + + dx * (fspl(3, 1, i, j) + + dy * (2.0 * fspl(3, 2, i, j) + + dy * 3.0 * fspl(3, 3, i, j))))); + } + + if ((ict[3] > 0) || (ict[0] == -1)) { + // Evaluate d2f/dx2 + iaval++; + fval(iaval - 1) = + 2.0 * (fspl(2, 0, i, j) + + dy * (fspl(2, 1, i, j) + + dy * (fspl(2, 2, i, j) + dy * fspl(2, 3, i, j)))) + + 6.0 * dx * + (fspl(3, 0, i, j) + + dy * (fspl(3, 1, i, j) + + dy * (fspl(3, 2, i, j) + dy * fspl(3, 3, i, j)))); + } + + if ((ict[4] > 0) || (ict[0] == -1)) { + // Evaluate d2f/dy2 + iaval++; + fval(iaval - 1) = + 2.0 * fspl(0, 2, i, j) + 6.0 * dy * fspl(0, 3, i, j) + + dx * (2.0 * fspl(1, 2, i, j) + 6.0 * dy * fspl(1, 3, i, j) + + dx * (2.0 * fspl(2, 2, i, j) + 6.0 * dy * fspl(2, 3, i, j) + + dx * (2.0 * fspl(3, 2, i, j) + + 6.0 * dy * fspl(3, 3, i, j)))); + } + + if ((ict[5] > 0) && (ict[0] != -1)) { + // Evaluate d2f/dxdy + iaval++; + fval(iaval - 1) = + fspl(1, 1, i, j) + + dy * (2.0 * fspl(1, 2, i, j) + dy * 3.0 * fspl(1, 3, i, j)) + + 2.0 * dx * + (fspl(2, 1, i, j) + + dy * (2.0 * fspl(2, 2, i, j) + dy * 3.0 * fspl(2, 3, i, j)) + + 1.5 * dx * + (fspl(3, 1, i, j) + dy * (2.0 * fspl(3, 2, i, j) + + dy * 3.0 * fspl(3, 3, i, j)))); + } + + if (ict[0] == -1) { + // Evaluate d4f/dx2dy2 + iaval++; + fval(iaval - 1) = + 4.0 * fspl(2, 2, i, j) + 12.0 * dy * fspl(2, 3, i, j) + + dx * (12.0 * fspl(3, 2, i, j) + 36.0 * dy * fspl(3, 3, i, j)); + } + } else if (ict[0] == 3) { + if (ict[1] == 1) { + // d³f/dx³ (not continuous) + iaval++; + fval(iaval - 1) = + 6.0 * (fspl(3, 0, i, j) + + dy * (fspl(3, 1, i, j) + + dy * (fspl(3, 2, i, j) + dy * fspl(3, 3, i, j)))); + } + + if (ict[2] == 1) { + // d³f/dx²dy + iaval++; + fval(iaval - 1) = + 2.0 * (fspl(2, 1, i, j) + + dy * (2.0 * fspl(2, 2, i, j) + dy * 3.0 * fspl(2, 3, i, j))) + + 6.0 * dx * + (fspl(3, 1, i, j) + + dy * (2.0 * fspl(3, 2, i, j) + dy * 3.0 * fspl(3, 3, i, j))); + } + + if (ict[3] == 1) { + // d³f/dxdy² + iaval++; + fval(iaval - 1) = + 2.0 * fspl(1, 2, i, j) + 6.0 * dy * fspl(1, 3, i, j) + + 2.0 * dx * + (2.0 * fspl(2, 2, i, j) + 6.0 * dy * fspl(2, 3, i, j) + + 1.5 * dx * + (2.0 * fspl(3, 2, i, j) + 6.0 * dy * fspl(3, 3, i, j))); + } + + if (ict[4] == 1) { + // d³f/dy³ (not continuous) + iaval++; + fval(iaval - 1) = + 6.0 * (fspl(0, 3, i, j) + + dx * (fspl(1, 3, i, j) + + dx * (fspl(2, 3, i, j) + dx * fspl(3, 3, i, j)))); + } + + } else if (ict[0] == 4) { + if (ict[1] == 1) { + // d⁴f/dx³dy + iaval++; + fval(iaval - 1) = + 6.0 * (fspl(3, 1, i, j) + + dy * 2.0 * (fspl(3, 2, i, j) + dy * 1.5 * fspl(3, 3, i, j))); + } + + if (ict[2] == 1) { + // d⁴f/dx²dy² + iaval++; + fval(iaval - 1) = + 4.0 * fspl(2, 2, i, j) + 12.0 * dy * fspl(2, 3, i, j) + + dx * (12.0 * fspl(3, 2, i, j) + 36.0 * dy * fspl(3, 3, i, j)); + } + + if (ict[3] == 1) { + // d⁴f/dxdy³ (not continuous) + iaval++; + fval(iaval - 1) = + 6.0 * (fspl(1, 3, i, j) + + 2.0 * dx * (fspl(2, 3, i, j) + 1.5 * dx * fspl(3, 3, i, j))); + } + + } else if (ict[0] == 5) { + if (ict[1] == 1) { + // d⁵f/dx³dy² (not continuous) + iaval++; + fval(iaval - 1) = 12.0 * (fspl(3, 2, i, j) + dy * 3.0 * fspl(3, 3, i, j)); + } + + if (ict[2] == 1) { + // d⁵f/dx²dy³ (not continuous) + iaval++; + fval(iaval - 1) = 12.0 * (fspl(2, 3, i, j) + dx * 3.0 * fspl(3, 3, i, j)); + } + + } else if (ict[0] == 6) { + // d⁶f/dx³dy³ (not continuous) + iaval++; + fval(iaval - 1) = 36.0 * fspl(3, 3, i, j); + } +} // end evalfn + +template +CompactBiCubicSplineInterpolator:: + CompactBiCubicSplineInterpolator( + Rank1View x, LO nx, Rank1View y, LO ny, + Rank3View f, LO ibcxmin, + Rank1View bcxmin, LO ibcxmax, + Rank1View bcxmax, LO ibcymin, + Rank1View bcymin, LO ibcymax, + Rank1View bcymax, Rank1View wk) { + // Check bc validity + ibc_check(ibcxmin, "2d spline", "xmin", -1, 7); + if (ibcxmin >= 0) + ibc_check(ibcxmax, "2d spline", "xmax", 0, 7); + ibc_check(ibcymin, "2d spline", "ymin", -1, 7); + if (ibcymin >= 0) + ibc_check(ibcymax, "2d spline", "ymax", 0, 7); + + CubicSplineInterpolator::sanity_check(x, 1.0e-3); + CubicSplineInterpolator::sanity_check(y, 1.0e-3); + this->x_ = x; // Store the x-coordinates + this->y_ = y; // Store the y-coordinates + this->nx_ = nx; // Store the number of x-coordinates + this->ny_ = ny; // Store the number of y-coordinates + solve_spline(x, nx, y, ny, f, ibcxmin, bcxmin, ibcxmax, bcxmax, ibcymin, + bcymin, ibcymax, bcymax, wk); + this->f_ = f; // Store the spline coefficients +} + +template +void CompactBiCubicSplineInterpolator::solve_spline( + Rank1View x, LO nx, Rank1View y, LO ny, + Rank3View f, LO ibcxmin, Rank1View bcxmin, + LO ibcxmax, Rank1View bcxmax, LO ibcymin, + Rank1View bcymin, LO ibcymax, + Rank1View bcymax, Rank1View wk) { + LO iflg2 = 0; + + // Check if inhomogeneous y-boundary conditions exist + if (ibcymin != -1) { + CubicSplineInterpolator::correction_detect(bcymin, ibcymin, + iflg2, nx); + CubicSplineInterpolator::correction_detect(bcymax, ibcymax, + iflg2, nx); + } + + auto fspl_l_x = Rank2View(wk.data_handle(), 2 * ny, nx); + auto wk_l = + Rank1View(wk.data_handle() + 2 * ny * nx, nx * ny); + auto fwk4_l_x = + Rank2View(wk.data_handle() + 3 * ny * nx, 4 * ny, nx); + + Kokkos::parallel_for( + Kokkos::TeamPolicy(ny, Kokkos::AUTO), + KOKKOS_LAMBDA(const member_type &team) { + const LO iy = team.league_rank(); + T zbcmin = 0.0, zbcmax = 0.0; + + auto fwk_x_view = Rank2View( + fspl_l_x.data_handle() + 2 * nx * iy, 2, nx); + auto wk_x_view = + Rank1View(wk_l.data_handle() + nx * iy, nx); + auto fwk4_x_view = Rank2View( + fwk4_l_x.data_handle() + 4 * nx * iy, 4, nx); + + Kokkos::parallel_for(Kokkos::TeamThreadRange(team, nx), + [=](LO ix) { fwk_x_view(0, ix) = f(0, ix, iy); }); + + if (team.team_rank() == 0) { + if (ibcxmin == 1 || ibcxmin == 2) + zbcmin = bcxmin[iy]; + if (ibcxmax == 1 || ibcxmax == 2) + zbcmax = bcxmax[iy]; + + CompactCubicSplineInterpolator::solve_spline( + x, nx, fwk_x_view, fwk4_x_view, ibcxmin, zbcmin, ibcxmax, zbcmax, + wk_x_view); + } + + Kokkos::parallel_for(Kokkos::TeamThreadRange(team, nx), + [=](LO ix) { f(1, ix, iy) = fwk_x_view(1, ix); }); + }); + + Kokkos::parallel_for( + Kokkos::TeamPolicy(nx, Kokkos::AUTO), + KOKKOS_LAMBDA(const member_type &team) { + const LO ix = team.league_rank(); + LO ibcmin = ibcymin, ibcmax = ibcymax; + + auto fwk_y_view = Rank2View( + fspl_l_x.data_handle() + 2 * ny * ix, 2, ny); + auto wk_y_view = + Rank1View(wk_l.data_handle() + ny * ix, ny); + auto fwk4_y_view = Rank2View( + fwk4_l_x.data_handle() + 4 * ny * ix, 4, ny); + + Kokkos::parallel_for(Kokkos::TeamThreadRange(team, ny), + [=](LO iy) { fwk_y_view(0, iy) = f(0, ix, iy); }); + + if (team.team_rank() == 0) { + if (iflg2 == 1) { + if (ibcymin == 1 || ibcymin == 2) + ibcmin = 0; + if (ibcymax == 1 || ibcymax == 2) + ibcmax = 0; + } + + CompactCubicSplineInterpolator::solve_spline( + y, ny, fwk_y_view, fwk4_y_view, ibcmin, 0.0, ibcmax, 0.0, + wk_y_view); + } + Kokkos::parallel_for(Kokkos::TeamThreadRange(team, ny), + [=](LO iy) { f(2, ix, iy) = fwk_y_view(1, iy); }); + }); + + Kokkos::parallel_for( + Kokkos::TeamPolicy(nx, Kokkos::AUTO), + KOKKOS_LAMBDA(const member_type &team) { + const LO ix = team.league_rank(); + LO ibcmin = ibcymin, ibcmax = ibcymax; + + auto fwk_y_view = Rank2View( + fspl_l_x.data_handle() + 2 * ny * ix, 2, ny); + auto wk_y_view = + Rank1View(wk_l.data_handle() + ny * ix, ny); + auto fwk4_y_view = Rank2View( + fwk4_l_x.data_handle() + 4 * ny * ix, 4, ny); + + Kokkos::parallel_for(Kokkos::TeamThreadRange(team, ny), + [=](LO iy) { fwk_y_view(0, iy) = f(1, ix, iy); }); + + if (team.team_rank() == 0) { + if (iflg2 == 1) { + if (ibcymin == 1 || ibcymin == 2) + ibcmin = 0; + if (ibcymax == 1 || ibcymax == 2) + ibcmax = 0; + } + + CompactCubicSplineInterpolator::solve_spline( + y, ny, fwk_y_view, fwk4_y_view, ibcmin, 0.0, ibcmax, 0.0, + wk_y_view); + } + Kokkos::parallel_for(Kokkos::TeamThreadRange(team, ny), + [=](LO iy) { f(3, ix, iy) = fwk_y_view(1, iy); }); + }); + + LO zbcmin = 0.0; + LO zbcmax = 0.0; + + // Correct for inhomogeneous boundary conditions if needed + if (iflg2 == 1) { + auto fcorr = + Rank3View(wk.data_handle() + 7 * ny * nx, 2, nx, ny); + + Kokkos::parallel_for( + Kokkos::TeamPolicy(nx, Kokkos::AUTO), + KOKKOS_LAMBDA(const member_type &team) { + const LO ix = team.league_rank(); + T zdiff1 = 0.0, zdiff2 = 0.0; + + auto fwk_y_view = Rank2View( + fspl_l_x.data_handle() + 2 * ny * ix, 2, ny); + auto wk_y_view = + Rank1View(wk_l.data_handle() + ny * ix, ny); + auto fwk4_y_view = Rank2View( + fwk4_l_x.data_handle() + 4 * ny * ix, 4, ny); + + if (ibcymin == 1) { + zdiff1 = bcymin[ix] - + ((f(0, ix, 1) - f(0, ix, 0)) / (y[1] - y[0]) + + (y[1] - y[0]) * (-2.0 * f(2, ix, 0) - f(2, ix, 1)) / 6.0); + } else if (ibcymin == 2) { + zdiff1 = bcymin[ix] - f(2, ix, 0); + } else { + zdiff1 = 0.0; + } + + if (ibcymax == 1) { + zdiff2 = bcymax[ix] - + ((f(0, ix, ny - 1) - f(0, ix, ny - 2)) / + (y[ny - 1] - y[ny - 2]) + + (y[ny - 1] - y[ny - 2]) * + (2.0 * f(2, ix, ny - 1) + f(2, ix, ny - 2)) / 6.0); + } else if (ibcymax == 2) { + zdiff2 = bcymax[ix] - f(2, ix, ny - 1); + } else { + zdiff2 = 0.0; + } + + Kokkos::parallel_for(Kokkos::TeamThreadRange(team, ny), + [=](LO iy) { fwk_y_view(0, iy) = 0.0; }); + if (team.team_rank() == 0) { + CompactCubicSplineInterpolator::solve_spline( + y, ny, fwk_y_view, fwk4_y_view, ibcymin, zdiff1, ibcymax, + zdiff2, wk_y_view); + } + Kokkos::parallel_for(Kokkos::TeamThreadRange(team, ny), [=](LO iy) { + fcorr(0, ix, iy) = fwk_y_view(1, iy); + }); + }); + + Kokkos::parallel_for( + Kokkos::TeamPolicy(ny, Kokkos::AUTO), + KOKKOS_LAMBDA(const member_type &team) { + const LO iy = team.league_rank(); + auto fwk_x_view = Rank2View( + fspl_l_x.data_handle() + 2 * nx * iy, 2, nx); + auto wk_x_view = + Rank1View(wk_l.data_handle() + nx * iy, nx); + auto fwk4_x_view = Rank2View( + fwk4_l_x.data_handle() + 4 * nx * iy, 4, nx); + + Kokkos::parallel_for(Kokkos::TeamThreadRange(team, nx), [=](LO ix) { + fwk_x_view(0, ix) = fcorr(0, ix, iy); + }); + + if (team.team_rank() == 0) { + CompactCubicSplineInterpolator::solve_spline( + x, nx, fwk_x_view, fwk4_x_view, ibcxmin, zbcmin, ibcxmax, + zbcmax, wk_x_view); + } + + Kokkos::parallel_for(Kokkos::TeamThreadRange(team, nx), [=](LO ix) { + fcorr(1, ix, iy) = fwk_x_view(1, ix); + }); + }); + + Kokkos::parallel_for( + Kokkos::MDRangePolicy>({0, 0}, {nx, ny}), + KOKKOS_LAMBDA(const LO ix, const LO iy) { + f(2, ix, iy) += fcorr(0, ix, iy); + f(3, ix, iy) += fcorr(1, ix, iy); + }); + } +} + +template +KOKKOS_INLINE_FUNCTION void +CompactBiCubicSplineInterpolator::lookup( + T xget, T yget, Rank1View x, const LO &nx, + Rank1View y, const LO &ny, LO &i, LO &j, T &xparam, + T &yparam, T &hx, T &hxi, T &hy, T &hyi, LO &ier) { + ier = 0; + + T zxget = xget; + T zyget = yget; + + CubicSplineInterpolator::range_check(xget, zxget, x, nx, ier); + CubicSplineInterpolator::range_check(yget, zyget, y, ny, ier); + + LO nxm = nx - 1; // Number of LOervals in x + LO nym = ny - 1; // Number of LOervals in y + // Determine zone index i + LO ii = static_cast(nxm * (zxget - x[0]) / (x[nx - 1] - x[0])); + i = std::min(nxm - 1, ii); + if (zxget < x[i]) + --i; + else if (zxget > x[i + 1]) + ++i; + + // Determine zone index j + ii = static_cast(nym * (zyget - y[0]) / (y[ny - 1] - y[0])); + j = std::min(nym - 1, ii); + if (zyget < y[j]) + --j; + else if (zyget > y[j + 1]) + ++j; + + hx = x[i + 1] - x[i]; + hy = y[j + 1] - y[j]; + + hxi = 1.0 / hx; + hyi = 1.0 / hy; + + xparam = (zxget - x[i]) * hxi; + yparam = (zyget - y[j]) * hyi; +} + +template +KOKKOS_INLINE_FUNCTION void +CompactBiCubicSplineInterpolator::evalfn( + Kokkos::View ict, LO ivec, LO ivecd, + Rank1View fval, const LO &i, const LO &j, const T &xparam, + const T &yparam, const T &hx, const T &hxi, const T &hy, const T &hyi, + Rank3View f) { + constexpr T sixth = 1.0 / 6.0; + const T z36th = sixth * sixth; + LO iadr = 0; + + // ict[0] = 1 or 2 → f, df/dx, df/dy, d²f/dx², d²f/dy², d²f/dxdy + if (ict[0] <= 2) { + // f (function value) + if (ict[0] == 1) { + iadr++; + T xp = xparam, xpi = 1.0 - xp; + T xp2 = xp * xp, xpi2 = xpi * xpi; + T cx = xp * (xp2 - 1.0); + T cxi = xpi * (xpi2 - 1.0); + T hx2 = hx * hx; + + T yp = yparam, ypi = 1.0 - yp; + T yp2 = yp * yp, ypi2 = ypi * ypi; + T cy = yp * (yp2 - 1.0); + T cyi = ypi * (ypi2 - 1.0); + T hy2 = hy * hy; + + T sum = xpi * (ypi * f(0, i, j) + yp * f(0, i, j + 1)) + + xp * (ypi * f(0, i + 1, j) + yp * f(0, i + 1, j + 1)); + sum += sixth * hx2 * + (cxi * (ypi * f(1, i, j) + yp * f(1, i, j + 1)) + + cx * (ypi * f(1, i + 1, j) + yp * f(1, i + 1, j + 1))); + sum += sixth * hy2 * + (xpi * (cyi * f(2, i, j) + cy * f(2, i, j + 1)) + + xp * (cyi * f(2, i + 1, j) + cy * f(2, i + 1, j + 1))); + sum += z36th * hx2 * hy2 * + (cxi * (cyi * f(3, i, j) + cy * f(3, i, j + 1)) + + cx * (cyi * f(3, i + 1, j) + cy * f(3, i + 1, j + 1))); + fval(iadr - 1) = sum; + } + + // df/dx + if (ict[1] == 1) { + iadr++; + T xp = xparam, xpi = 1.0 - xp; + T xp2 = xp * xp, xpi2 = xpi * xpi; + T cxd = 3.0 * xp2 - 1.0; + T cxdi = -3.0 * xpi2 + 1.0; + T yp = yparam, ypi = 1.0 - yp; + T yp2 = yp * yp, ypi2 = ypi * ypi; + T cy = yp * (yp2 - 1.0); + T cyi = ypi * (ypi2 - 1.0); + T hy2 = hy * hy; + + T sum = hxi * (-(ypi * f(0, i, j) + yp * f(0, i, j + 1)) + + (ypi * f(0, i + 1, j) + yp * f(0, i + 1, j + 1))); + sum += sixth * hx * + (cxdi * (ypi * f(1, i, j) + yp * f(1, i, j + 1)) + + cxd * (ypi * f(1, i + 1, j) + yp * f(1, i + 1, j + 1))); + sum += sixth * hxi * hy2 * + (-(cyi * f(2, i, j) + cy * f(2, i, j + 1)) + + (cyi * f(2, i + 1, j) + cy * f(2, i + 1, j + 1))); + sum += z36th * hx * hy2 * + (cxdi * (cyi * f(3, i, j) + cy * f(3, i, j + 1)) + + cxd * (cyi * f(3, i + 1, j) + cy * f(3, i + 1, j + 1))); + fval(iadr - 1) = sum; + } + + // df/dy + if (ict[2] == 1) { + iadr++; + T xp = xparam, xpi = 1.0 - xp; + T xp2 = xp * xp, xpi2 = xpi * xpi; + T cx = xp * (xp2 - 1.0); + T cxi = xpi * (xpi2 - 1.0); + T hx2 = hx * hx; + T yp = yparam, ypi = 1.0 - yp; + T yp2 = yp * yp, ypi2 = ypi * ypi; + T cyd = 3.0 * yp2 - 1.0; + T cydi = -3.0 * ypi2 + 1.0; + + T sum = hyi * (xpi * (-f(0, i, j) + f(0, i, j + 1)) + + xp * (-f(0, i + 1, j) + f(0, i + 1, j + 1))); + sum += sixth * hx2 * hyi * + (cxi * (-f(1, i, j) + f(1, i, j + 1)) + + cx * (-f(1, i + 1, j) + f(1, i + 1, j + 1))); + sum += sixth * hy * + (xpi * (cydi * f(2, i, j) + cyd * f(2, i, j + 1)) + + xp * (cydi * f(2, i + 1, j) + cyd * f(2, i + 1, j + 1))); + sum += z36th * hx2 * hy * + (cxi * (cydi * f(3, i, j) + cyd * f(3, i, j + 1)) + + cx * (cydi * f(3, i + 1, j) + cyd * f(3, i + 1, j + 1))); + fval(iadr - 1) = sum; + } + + // d2f/dx2 + if (ict[3] == 1) { + iadr++; + T xp = xparam, xpi = 1.0 - xp; + T yp = yparam, ypi = 1.0 - yp; + T yp2 = yp * yp, ypi2 = ypi * ypi; + T cy = yp * (yp2 - 1.0); + T cyi = ypi * (ypi2 - 1.0); + T hy2 = hy * hy; + + T sum = xpi * (ypi * f(1, i, j) + yp * f(1, i, j + 1)) + + xp * (ypi * f(1, i + 1, j) + yp * f(1, i + 1, j + 1)); + sum += sixth * hy2 * + (xpi * (cyi * f(3, i, j) + cy * f(3, i, j + 1)) + + xp * (cyi * f(3, i + 1, j) + cy * f(3, i + 1, j + 1))); + fval(iadr - 1) = sum; + } + + // d2f/dy2 + if (ict[4] == 1) { + iadr++; + T xp = xparam, xpi = 1.0 - xp; + T xp2 = xp * xp, xpi2 = xpi * xpi; + T cx = xp * (xp2 - 1.0); + T cxi = xpi * (xpi2 - 1.0); + T hx2 = hx * hx; + T yp = yparam, ypi = 1.0 - yp; + + T sum = xpi * (ypi * f(2, i, j) + yp * f(2, i, j + 1)) + + xp * (ypi * f(2, i + 1, j) + yp * f(2, i + 1, j + 1)); + sum += sixth * hx2 * + (cxi * (ypi * f(3, i, j) + yp * f(3, i, j + 1)) + + cx * (ypi * f(3, i + 1, j) + yp * f(3, i + 1, j + 1))); + fval(iadr - 1) = sum; + } + + // d2f/dxdy + if (ict[5] == 1) { + iadr++; + T xp = xparam, xpi = 1.0 - xp; + T xp2 = xp * xp, xpi2 = xpi * xpi; + T cxd = 3.0 * xp2 - 1.0; + T cxdi = -3.0 * xpi2 + 1.0; + T yp = yparam, ypi = 1.0 - yp; + T yp2 = yp * yp, ypi2 = ypi * ypi; + T cyd = 3.0 * yp2 - 1.0; + T cydi = -3.0 * ypi2 + 1.0; + + T sum = + hxi * hyi * + (f(0, i, j) - f(0, i, j + 1) - f(0, i + 1, j) + f(0, i + 1, j + 1)); + sum += sixth * hx * hyi * + (cxdi * (-f(1, i, j) + f(1, i, j + 1)) + + cxd * (-f(1, i + 1, j) + f(1, i + 1, j + 1))); + sum += sixth * hxi * hy * + (-(cydi * f(2, i, j) + cyd * f(2, i, j + 1)) + + (cydi * f(2, i + 1, j) + cyd * f(2, i + 1, j + 1))); + sum += z36th * hx * hy * + (cxdi * (cydi * f(3, i, j) + cyd * f(3, i, j + 1)) + + cxd * (cydi * f(3, i + 1, j) + cyd * f(3, i + 1, j + 1))); + fval(iadr - 1) = sum; + } + } + + // ict[0] = 3 → 3rd‑order derivative combinations + else if (ict[0] == 3) { + // d3f/dx3 + if (ict[1] == 1) { + iadr++; + T yp = yparam, ypi = 1.0 - yp; + T yp2 = yp * yp, ypi2 = ypi * ypi; + T cy = yp * (yp2 - 1.0); + T cyi = ypi * (ypi2 - 1.0); + T hy2 = hy * hy; + T sum = hxi * (-(ypi * f(1, i, j) + yp * f(1, i, j + 1)) + + (ypi * f(1, i + 1, j) + yp * f(1, i + 1, j + 1))); + sum += sixth * hy2 * hxi * + (-(cyi * f(3, i, j) + cy * f(3, i, j + 1)) + + (cyi * f(3, i + 1, j) + cy * f(3, i + 1, j + 1))); + fval(iadr - 1) = sum; + } + + // d3f/dx2dy + if (ict[2] == 1) { + iadr++; + T xp = xparam, xpi = 1.0 - xp; + T yp = yparam, ypi = 1.0 - yp; + T yp2 = yp * yp, ypi2 = ypi * ypi; + T cyd = 3.0 * yp2 - 1.0; + T cydi = -3.0 * ypi2 + 1.0; + T sum = hyi * (xpi * (-f(1, i, j) + f(1, i, j + 1)) + + xp * (-f(1, i + 1, j) + f(1, i + 1, j + 1))); + sum += sixth * hy * + (xpi * (cydi * f(3, i, j) + cyd * f(3, i, j + 1)) + + xp * (cydi * f(3, i + 1, j) + cyd * f(3, i + 1, j + 1))); + fval(iadr - 1) = sum; + } + + // d3f/dxdy2 + if (ict[3] == 1) { + iadr++; + T xp = xparam, xpi = 1.0 - xp; + T xp2 = xp * xp, xpi2 = xpi * xpi; + T cxd = 3.0 * xp2 - 1.0; + T cxdi = -3.0 * xpi2 + 1.0; + T yp = yparam, ypi = 1.0 - yp; + T sum = hxi * (-(ypi * f(2, i, j) + yp * f(2, i, j + 1)) + + (ypi * f(2, i + 1, j) + yp * f(2, i + 1, j + 1))); + sum += sixth * hx * + (cxdi * (ypi * f(3, i, j) + yp * f(3, i, j + 1)) + + cxd * (ypi * f(3, i + 1, j) + yp * f(3, i + 1, j + 1))); + fval(iadr - 1) = sum; + } + + // d3f/dy3 + if (ict[4] == 1) { + iadr++; + T xp = xparam, xpi = 1.0 - xp; + T xp2 = xp * xp, xpi2 = xpi * xpi; + T cx = xp * (xp2 - 1.0); + T cxi = xpi * (xpi2 - 1.0); + T hx2 = hx * hx; + T sum = hyi * (xpi * (-f(2, i, j) + f(2, i, j + 1)) + + xp * (-f(2, i + 1, j) + f(2, i + 1, j + 1))); + sum += sixth * hx2 * hyi * + (cxi * (-f(3, i, j) + f(3, i, j + 1)) + + cx * (-f(3, i + 1, j) + f(3, i + 1, j + 1))); + fval(iadr - 1) = sum; + } + } + + // ict[0] = 4 → 4th‑order derivative combinations + else if (ict[0] == 4) { + // d4f/dx3dy + if (ict[1] == 1) { + iadr++; + T yp = yparam, ypi = 1.0 - yp; + T yp2 = yp * yp, ypi2 = ypi * ypi; + T cyd = 3.0 * yp2 - 1.0; + T cydi = -3.0 * ypi2 + 1.0; + T sum = + hxi * hyi * + (f(1, i, j) - f(1, i, j + 1) - f(1, i + 1, j) + f(1, i + 1, j + 1)); + sum += sixth * hy * hxi * + (-(cydi * f(3, i, j) + cyd * f(3, i, j + 1)) + + (cydi * f(3, i + 1, j) + cyd * f(3, i + 1, j + 1))); + fval(iadr - 1) = sum; + } + + // d4f/dx2dy2 + if (ict[2] == 1) { + iadr++; + T xp = xparam, xpi = 1.0 - xp; + T yp = yparam, ypi = 1.0 - yp; + T sum = xpi * (ypi * f(3, i, j) + yp * f(3, i, j + 1)) + + xp * (ypi * f(3, i + 1, j) + yp * f(3, i + 1, j + 1)); + fval(iadr - 1) = sum; + } + + // d4f/dxdy3 + if (ict[3] == 1) { + iadr++; + T xp = xparam, xpi = 1.0 - xp; + T xp2 = xp * xp, xpi2 = xpi * xpi; + T cxd = 3.0 * xp2 - 1.0; + T cxdi = -3.0 * xpi2 + 1.0; + T sum = + hxi * hyi * + (f(2, i, j) - f(2, i, j + 1) - f(2, i + 1, j) + f(2, i + 1, j + 1)); + sum += sixth * hx * hyi * + (cxdi * (-f(3, i, j) + f(3, i, j + 1)) + + cxd * (-f(3, i + 1, j) + f(3, i + 1, j + 1))); + fval(iadr - 1) = sum; + } + } + + // ict[0] = 5 → 5th‑order derivative combinations + else if (ict[0] == 5) { + // d5f/dx3dy2 + if (ict[1] == 1) { + iadr++; + T yp = yparam, ypi = 1.0 - yp; + T sum = hxi * (-(ypi * f(3, i, j) + yp * f(3, i, j + 1)) + + (ypi * f(3, i + 1, j) + yp * f(3, i + 1, j + 1))); + fval(iadr - 1) = sum; + } + + // d5f/dx2dy3 + if (ict[2] == 1) { + iadr++; + T xp = xparam, xpi = 1.0 - xp; + T sum = hyi * (xpi * (-f(3, i, j) + f(3, i, j + 1)) + + xp * (-f(3, i + 1, j) + f(3, i + 1, j + 1))); + fval(iadr - 1) = sum; + } + } + + // ict[0] = 6 → 6th‑order derivative (dx³dy³) + else if (ict[0] == 6) { + iadr++; + T sum = hxi * hyi * + (f(3, i, j) - f(3, i, j + 1) - f(3, i + 1, j) + f(3, i + 1, j + 1)); + fval(iadr - 1) = sum; + } +} + +template +KOKKOS_INLINE_FUNCTION void +CompactBiCubicSplineInterpolator::eval( + T xget, T yget, Kokkos::View ict, + Rank1View fval, // output (size depends on ict) + Rank1View x, const LO &nx, Rank1View y, + const LO &ny, Rank3View f, // input (size depends on ict) + LO &ier) { + // Local variables + LO i = 0, j = 0; + T xparam = 0.0, yparam = 0.0; + T hx = 0.0, hy = 0.0; + T hxi = 0.0, hyi = 0.0; + + // Call herm2xy to locate cell and compute params + lookup(xget, yget, x, nx, y, ny, i, j, xparam, yparam, hx, hxi, hy, hyi, ier); + + if (ier != 0) + return; + + // Call evalfn with scalar-vector LOerface + evalfn(ict, 1, 1, fval, i, j, xparam, yparam, hx, hxi, hy, hyi, f); +} + +} // namespace pcms +#endif \ No newline at end of file diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 27b0a3c06..2e7c87fe4 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -111,7 +111,8 @@ if(Catch2_FOUND) test_mls_basis.cpp test_rbf_interp.cpp test_normalisation.cpp - test_svd_serial.cpp) + test_svd_serial.cpp + test_spline_interpolator.cpp) endif () add_executable(unit_tests ${PCMS_UNIT_TEST_SOURCES}) target_link_libraries(unit_tests PUBLIC Catch2::Catch2 pcms::core pcms_interpolator) diff --git a/test/test_spline_interpolator.cpp b/test/test_spline_interpolator.cpp new file mode 100644 index 000000000..1a3cd1815 --- /dev/null +++ b/test/test_spline_interpolator.cpp @@ -0,0 +1,503 @@ +#include +#include +#include "mdspan/mdspan.hpp" +#include "pcms.h" +#include +#include +#include + +using namespace pcms; + +using TestMemorySpace = Kokkos::DefaultExecutionSpace; + +bool are_equal(double a, double b, double tolerance = 1e-7) { + return std::abs(a - b) < tolerance; +} + +void createFlatGrid(Rank1View xvec, + Rank1View yvec, + Kokkos::View X_flat, + Kokkos::View Y_flat) { + size_t nx = xvec.size(); + size_t ny = yvec.size(); + + Kokkos::parallel_for( + Kokkos::MDRangePolicy>({0, 0}, {ny, nx}), + KOKKOS_LAMBDA(const int i, const int j) { + size_t idx = i * nx + j; + X_flat[idx] = xvec[j]; + Y_flat[idx] = yvec[i]; + }); +} + +void tset(int nth, Kokkos::View th, + Kokkos::View sth, + Kokkos::View cth, double thmin, + double thmax) { + Kokkos::parallel_for( + Kokkos::RangePolicy(0, nth), + KOKKOS_LAMBDA(const int ith) { + th[ith] = thmin + static_cast(ith) * (thmax - thmin) / + static_cast(nth - 1); + sth[ith] = 2.0 + std::sin(th[ith]); + cth[ith] = std::cos(th[ith]); + }); +} + +void xset(int nx, Kokkos::View x, + Kokkos::View ex, double xmin, + double xmax) { + if (nx < 2) + return; // avoid division by zero + + Kokkos::parallel_for( + Kokkos::RangePolicy(0, nx), KOKKOS_LAMBDA(const int ix) { + x[ix] = xmin + static_cast(ix) * (xmax - xmin) / + static_cast(nx - 1); + ex[ix] = std::exp(2.0 * x[ix] - 1.0); + }); +} + +void ffset(int num, Kokkos::View xf, + Kokkos::View tf, + Kokkos::View f) { + Kokkos::parallel_for( + Kokkos::MDRangePolicy>({0, 0}, {num, num}), + KOKKOS_LAMBDA(const int i, const int j) { + f(i * num + j) = xf[i] * tf[j]; + }); +} + +void bset(Rank1View fx, int nx, + Rank1View fth, int nth, + Rank1View bcx1, + Rank1View bcx2, + Rank1View bcth1, + Rank1View bcth2) { + Kokkos::parallel_for( + Kokkos::RangePolicy(0, nth), + KOKKOS_LAMBDA(const int ith) { + bcx1[ith] = 2.0 * fx(0) * fth(ith); // df/dx at x(1) + bcx2[ith] = 2.0 * fx(nx - 1) * fth(ith); // df/dx at x(nx) + }); + + Kokkos::parallel_for( + Kokkos::RangePolicy(0, nx), KOKKOS_LAMBDA(const int ix) { + bcth1(ix) = fx(ix); // df/dth at th = 0 (th[0]) + bcth2(ix) = fx(ix); // df/dth at th = 2π (th[nth - 1]) + }); +} + +void generate_gt_2d(Rank1View gt_splinv, + Rank1View fxtest, + Rank1View fthtest, int ntest) { + Kokkos::parallel_for( + Kokkos::MDRangePolicy>({0, 0}, {ntest, ntest}), + KOKKOS_LAMBDA(const int j, const int i) { + gt_splinv(j * ntest + i) = fxtest(i) * fthtest(j); + }); +} + +void compare_1doutput(Rank2View splinv, + Rank1View gt_splinv, + const double gt_dif, const double gt_difr, + std::string label) { + // Compare the output of splinv with gt_splinv + double result_fdif = 0.0; + double result_fdifr = 0.0; + Kokkos::parallel_reduce( + "compare_splinv", splinv.extent(0), + KOKKOS_LAMBDA(const int i, double &max_fdif, double &max_fdifr) { + if (splinv(i, 0) != 0.0) { + double dif = Kokkos::abs(splinv(i, 0) - gt_splinv(i)); + max_fdif = Kokkos::max(max_fdif, dif); + max_fdifr = Kokkos::max(max_fdifr, dif / gt_splinv(i)); + } + }, + Kokkos::Max(result_fdif), Kokkos::Max(result_fdifr)); + double fdif = result_fdif; + double fdifr = result_fdifr; + std::cout << "1d " << label << " max absolute difference: " << fdif + << ", relative difference: " << fdifr << std::endl; + assert(are_equal(fdif, gt_dif)); + assert(are_equal(fdifr, gt_difr)); +} + +void compare_output(Rank2View splinv, + Rank1View gt_splinv, + const double gt_dif, const double gt_difr, + std::string label) { + // Compare the output of splinv with gt_splinv + double result_fdif = 0.0; + double result_fdifr = 0.0; + Kokkos::parallel_reduce( + "compare_splinv", splinv.extent(0), + KOKKOS_LAMBDA(const int i, double &max_fdif, double &max_fdifr) { + if (splinv(i, 0) != 0.0) { + double dif = Kokkos::abs(splinv(i, 0) - gt_splinv(i)); + max_fdif = Kokkos::max(max_fdif, dif); + max_fdifr = Kokkos::max(max_fdifr, + dif / (0.5 * (splinv(i, 0) + gt_splinv(i)))); + } + }, + Kokkos::Max(result_fdif), Kokkos::Max(result_fdifr)); + double fdif = result_fdif; + double fdifr = result_fdifr; + std::cout << "2d " << label << " max absolute difference: " << fdif + << ", relative difference: " << fdifr << std::endl; + assert(are_equal(fdif, gt_dif)); + assert(are_equal(fdifr, gt_difr)); +} + +void compare(Rank2View splinv, + Rank1View gt_splinv, + Rank1View res, std::string label) { + // Compare the output of splinv with gt_splinv + double result_fdif = 0.0; + double result_fdifr = 0.0; + Kokkos::parallel_reduce( + "compare_splinv", splinv.extent(0), + KOKKOS_LAMBDA(const int i, double &max_fdif, double &max_fdifr) { + if (splinv(i, 0) != 0.0) { + double dif = Kokkos::abs(splinv(i, 0) - gt_splinv(i)); + max_fdif = Kokkos::max(max_fdif, dif); + max_fdifr = Kokkos::max(max_fdifr, dif / gt_splinv(i)); + } + }, + Kokkos::Max(result_fdif), Kokkos::Max(result_fdifr)); + res(0) = result_fdif; + res(1) = result_fdifr; + std::cout << "2d " << label << " max absolute difference: " << res(0) + << ", relative difference: " << res(1) << std::endl; +} + +void compare_2d(Rank2View splinv, + Rank1View gt_splinv, + Rank1View res, std::string label) { + // Compare the output of splinv with gt_splinv + double result_fdif = 0.0; + double result_fdifr = 0.0; + Kokkos::parallel_reduce( + "compare_splinv", splinv.extent(0), + KOKKOS_LAMBDA(const int i, double &max_fdif, double &max_fdifr) { + if (splinv(i, 0) != 0.0) { + double dif = Kokkos::abs(splinv(i, 0) - gt_splinv(i)); + max_fdif = Kokkos::max(max_fdif, dif); + max_fdifr = Kokkos::max(max_fdifr, + dif / (0.5 * (splinv(i, 0) + gt_splinv(i)))); + } + }, + Kokkos::Max(result_fdif), Kokkos::Max(result_fdifr)); + res(0) = result_fdif; + res(1) = result_fdifr; + std::cout << "2d " << label << " max absolute difference: " << res(0) + << ", relative difference: " << res(1) << std::endl; +} + +void reset_2dspan(Rank2View span) { + Kokkos::parallel_for( + "zero_init", + Kokkos::MDRangePolicy>({0, 0}, + {span.extent(0), span.extent(1)}), + KOKKOS_LAMBDA(int i, int j) { span(i, j) = 0.0; }); +} + +void dotest1(int ns, Rank1View x, + Rank1View f, + Rank1View fd, + Rank2View fspl, + Rank2View fspp, + Rank2View fs2, int nt, + Rank1View xt, + Rank1View ft, + Rank2View xpkg, + Rank2View testa1, + Rank2View testa2, + Rank2View testa3, + Rank1View wk, + Rank1View wk2, + Kokkos::View res_1d) { + using std::data; + using std::size; + + Kokkos::parallel_for( + Kokkos::RangePolicy(0, ns), KOKKOS_LAMBDA(const int i) { + fspl(0, i) = f(i); + fspp(0, i) = f(i); + fs2(0, i) = f(i); + }); + + Kokkos::View fspl4_view("fspl4_view", 40); + auto fspl4 = Rank2View(fspl4_view.data(), 4, 10); + + // interpolator.cspline(x, ns, fspl, 1, 1, 1, 1, wk); + ExplicitCubicSplineInterpolator + explicit_interpolator(x, ns, fspl, 1, 1, 1, 1, wk); + + int ict_arr[3] = {1, 0, 0}; + Kokkos::View ict("ict", 3); + Kokkos::parallel_for( + Kokkos::RangePolicy(0, ict.size()), + KOKKOS_LAMBDA(const int i) { ict(i) = ict_arr[i]; }); + + Kokkos::View splinv_view("splinv_view", 3000); + auto splinv = Rank2View(splinv_view.data(), 1000, 3); + reset_2dspan(splinv); + explicit_interpolator.evaluate(ict, xt, splinv); + + auto res1 = Rank1View(res_1d.data(), 2); + compare(splinv, ft, res1, "cspline"); + + reset_2dspan(splinv); + ExplicitCubicSplineInterpolator + explicit_interpolator_periodic(x, ns, fspp, -1, 0, -1, 0, wk); + explicit_interpolator_periodic.evaluate(ict, xt, splinv); + auto res2 = Rank1View(res_1d.data() + 2, 2); + compare(splinv, ft, res2, "cspline_periodic"); + + reset_2dspan(splinv); + CompactCubicSplineInterpolator compact_interpolator( + x, ns, fs2, fspl4, 1, 1, 1, 1, wk2); + compact_interpolator.evaluate(ict, xt, splinv); + auto res3 = Rank1View(res_1d.data() + 4, 2); + compare(splinv, ft, res3, "compact_cubic"); +} + +void pspltest1(Kokkos::View res_1d) { + const double pi2 = 6.28318530718; + const double zero = 0.0; + int inum = 10; + + // Local arrays + Kokkos::View zdum_view("zdum_view", 1000); + Kokkos::View testa1_view("testa1_view", 1000); + Kokkos::View testa2_view("testa2_view", 1000); + Kokkos::View testa3_view("testa3_view", 1000); + Kokkos::View xtest_view("xtest_view", 1000); + Kokkos::View ftest_view("ftest_view", 1000); + Kokkos::View x_view("x_view", 10); + Kokkos::View zcos_view("zcos_view", 10); + Kokkos::View z2sin_view("z2sin_view", 10); + Kokkos::View xpkg_view("xpkg_view", 10 * 4); + Kokkos::View fs_view("fs_view", 40); + Kokkos::View fsp_view("fsp_view", 40); + Kokkos::View fs2_view("fs2_view", 20); + + // Prepare test data + tset(1000, xtest_view, ftest_view, zdum_view, zero - 0.1, pi2 + 0.1); + tset(inum, x_view, z2sin_view, zcos_view, zero, pi2); + + Kokkos::parallel_for( + Kokkos::RangePolicy(0, inum), + KOKKOS_LAMBDA(const int ix) { zcos_view(ix) = std::cos(x_view(ix)); }); + + auto zdum = Rank1View(zdum_view.data(), 10); + + auto wk2_view = + Kokkos::View(zdum_view.data(), 1000); + auto wk2 = Rank1View(wk2_view.data(), 10); + + auto testa1 = Rank2View(testa1_view.data(), 1000, 3); + auto testa2 = Rank2View(testa2_view.data(), 1000, 3); + auto testa3 = Rank2View(testa3_view.data(), 1000, 3); + auto x = Rank1View(x_view.data(), x_view.size()); + auto zcos = + Rank1View(zcos_view.data(), zcos_view.size()); + auto z2sin = + Rank1View(z2sin_view.data(), z2sin_view.size()); + auto fs = Rank2View(fs_view.data(), 4, 10); + auto fsp = Rank2View(fsp_view.data(), 4, 10); + auto fs2 = Rank2View(fs2_view.data(), 2, 10); + auto xpkg = Rank2View(xpkg_view.data(), 10, 4); + auto xtest = Rank1View(xtest_view.data(), 1000); + auto ftest = Rank1View(ftest_view.data(), 1000); + + // Call test function + dotest1(inum, x, z2sin, zcos, fs, fsp, fs2, 1000, xtest, ftest, xpkg, testa1, + testa2, testa3, zdum, wk2, res_1d); +} + +void dotest2(Rank1View x, + Rank1View fx, int nx, + Rank1View th, + Rank1View fth, + Rank1View dfth, int nth, + Rank4View f, + Rank3View fh, + Rank2View flin, + Rank1View bcx1, + Rank1View bcx2, + Rank1View bcth1, + Rank1View bcth2, + Rank1View xtest, + Rank1View fxtest, + Rank1View thtest, + Rank1View fthtest, int ntest, + Kokkos::View res_2d) { + Kokkos::parallel_for( + Kokkos::MDRangePolicy>({0, 0}, {nth, nx}), + KOKKOS_LAMBDA(const int ith, const int ix) { + flin(ix, ith) = f(0, 0, ix, ith); // f + fh(0, ix, ith) = f(0, 0, ix, ith); // f + fh(1, ix, ith) = 2.0 * f(0, 0, ix, ith); // df/dx + fh(2, ix, ith) = fx(ix) * dfth(ith); // df/dy + fh(3, ix, ith) = 2.0 * fx(ix) * dfth(ith); // d2f/dxdy + }); + + int nbc = 1; + Kokkos::View wk_vec("wk_vec", 900); + auto wk = Rank1View(wk_vec.data(), 900); + bset(fx, nx, fth, nth, bcx1, bcx2, bcth1, bcth2); + + ExplicitBiCubicSplineInterpolator + explicit_interpolator(x, nx, th, nth, f, nbc, bcx1, nbc, bcx2, nbc, bcth1, + nbc, bcth2, wk); + + Kokkos::View splinv_view("splinv_view", 400000); + auto splinv = + Rank2View(splinv_view.data(), 40000, 10); + reset_2dspan(splinv); + int isel_arr[10] = {1, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + Kokkos::View isel("isel", 10); + Kokkos::parallel_for( + Kokkos::RangePolicy(0, isel.size()), + KOKKOS_LAMBDA(const int i) { isel(i) = isel_arr[i]; }); + + Kokkos::View xtest_grid_view("xtest_grid_view", + 40000); + Kokkos::View thtest_grid_view("thtest_grid_view", + 40000); + createFlatGrid(xtest, thtest, xtest_grid_view, thtest_grid_view); + auto xtest_grid = + Rank1View(xtest_grid_view.data(), 40000); + auto thtest_grid = + Rank1View(thtest_grid_view.data(), 40000); + Kokkos::View splinv_gt_view("splinv_view", 40000); + auto splinv_gt = + Rank1View(splinv_gt_view.data(), 40000); + generate_gt_2d(splinv_gt, fxtest, fthtest, ntest); + + // TODO: evaluate function raise memeory acess violation + explicit_interpolator.evaluate(isel, xtest_grid, thtest_grid, splinv); + + auto res1 = Rank1View(res_2d.data(), 2); + compare_2d(splinv, splinv_gt, res1, "bcspline"); + + reset_2dspan(splinv); + CompactBiCubicSplineInterpolator + compact_interpolator(x, nx, th, nth, fh, nbc, bcx1, nbc, bcx2, nbc, bcth1, + nbc, bcth2, wk); + compact_interpolator.evaluate(isel, xtest_grid, thtest_grid, splinv); + auto res2 = Rank1View(res_2d.data() + 2, 2); + compare_2d(splinv, splinv_gt, res2, "mkbicub"); +} + +void pspltest2(Kokkos::View res_2d) { + const double pi2 = 6.28318530718; + const double zero = 0.0; + const double one = 1.0; + + Kokkos::View x1_view("x1_view", 10); + Kokkos::View ex1_view("ex1_view", 10); + Kokkos::View t1_view("t1_view", 10); + Kokkos::View st1_view("st1_view", 10); + Kokkos::View ct1_view("ct1_view", 10); + Kokkos::View xtest_view("xtest_view", 200); + Kokkos::View extest_view("extest_view", 200); + Kokkos::View ttest_view("ttest_view", 200); + Kokkos::View stest_view("stest_view", 200); + Kokkos::View ctest_view("ctest_view", 200); + Kokkos::View f1_view("f1_view", 1600); + Kokkos::View f2_view("f2_view", 6400); + Kokkos::View f4_view("f4_view", 4 * 4 * 40 * 40); + Kokkos::View bcx1_view("bcx1_view", 40); + Kokkos::View bcx2_view("bcx2_view", 40); + Kokkos::View bcth1_view("bcth1_view", 40); + Kokkos::View bcth2_view("bcth2_view", 40); + Kokkos::View fh_view("fh_view", 400); + Kokkos::View flin_view("flin_view", 100); + + xset(10, x1_view, ex1_view, zero, one); + // xset(20, x2_view, ex2_view, zero, one); + // xset(40, x4_view, ex4_view, zero, one); + xset(200, xtest_view, extest_view, zero, one); + + tset(10, t1_view, st1_view, ct1_view, zero, pi2); + // tset(20, t2_view, st2_view, ct2_view, zero, pi2); + // tset(40, t4_view, st4_view, ct4_view, zero, pi2); + tset(200, ttest_view, stest_view, ctest_view, zero, pi2); + + ffset(10, ex1_view, st1_view, f1_view); + // ffset(20, ex2_view, st2_view, f2_view); + // ffset(40, ex4_view, st4_view, f4_view); + + auto x1 = Rank1View(x1_view.data(), x1_view.size()); + auto ex1 = + Rank1View(ex1_view.data(), ex1_view.size()); + auto t1 = Rank1View(t1_view.data(), t1_view.size()); + auto st1 = + Rank1View(st1_view.data(), st1_view.size()); + auto ct1 = + Rank1View(ct1_view.data(), ct1_view.size()); + auto f1 = Rank4View(f1_view.data(), + Kokkos::extents{4, 4, 10, 10}); + auto flin = Rank2View(flin_view.data(), 10, 10); + + auto fh = Rank3View(fh_view.data(), 4, 10, 10); + + auto bcx1 = + Rank1View(bcx1_view.data(), bcx1_view.size()); + auto bcx2 = + Rank1View(bcx2_view.data(), bcx2_view.size()); + auto bcth1 = + Rank1View(bcth1_view.data(), bcth1_view.size()); + auto bcth2 = + Rank1View(bcth2_view.data(), bcth2_view.size()); + + auto xtest = + Rank1View(xtest_view.data(), xtest_view.size()); + auto extest = Rank1View(extest_view.data(), + extest_view.size()); + auto ttest = + Rank1View(ttest_view.data(), ttest_view.size()); + auto stest = + Rank1View(stest_view.data(), stest_view.size()); + + dotest2(x1, ex1, 10, t1, st1, ct1, 10, f1, fh, flin, bcx1, bcx2, bcth1, bcth2, + xtest, extest, ttest, stest, 200, res_2d); + + // dotest2(x2,ex2,20,t2,st2,ct2,20,f2,fh,flin, + // bcx1,bcx2,bcth1,bcth2, + // xtest,extest,ttest,stest,200); + + // dotest2(x4,ex4,40,t4,st4,ct4,40,f4,fh,flin, + // bcx1,bcx2,bcth1,bcth2, + // xtest,extest,ttest,stest,200); +} + +TEST_CASE("test_cubic_spline_interpolator") { + Kokkos::print_configuration(std::cout); + std::cout << "DefaultExecutionSpace: " + << Kokkos::DefaultExecutionSpace::name() << std::endl; + Kokkos::Timer timer; + { + Kokkos::View res_1d("res_1d", 6); + double gt_1d[6] = + {6.7572E-04, 6.6529E-04, 6.8669E-04, 6.7622E-04, 6.7572E-04, 6.6529E-04}; + pspltest1(res_1d); + for (int i = 0; i < 6; ++i) { + REQUIRE(are_equal(res_1d(i), gt_1d[i])); + } + + Kokkos::View res_2d("res_2d", 4); + double gt_2d[4] = {1.8312E-03, 6.7151E-04, 1.8312E-03, 6.7151E-04}; + pspltest2(res_2d); + for (int i = 0; i < 4; ++i) { + REQUIRE(are_equal(res_2d(i), gt_2d[i])); + } + } + + double time = timer.seconds(); + std::cout << "Total time for spline tests: " << time << " seconds" + << std::endl; +} \ No newline at end of file From 4d054d7ee4144e41efb610e27d89c76f9cc56bbe Mon Sep 17 00:00:00 2001 From: Sichao25 Date: Mon, 28 Jul 2025 17:09:51 -0400 Subject: [PATCH 02/18] remove unused test functions --- test/test_spline_interpolator.cpp | 51 ------------------------------- 1 file changed, 51 deletions(-) diff --git a/test/test_spline_interpolator.cpp b/test/test_spline_interpolator.cpp index 1a3cd1815..0f290ef7e 100644 --- a/test/test_spline_interpolator.cpp +++ b/test/test_spline_interpolator.cpp @@ -98,57 +98,6 @@ void generate_gt_2d(Rank1View gt_splinv, }); } -void compare_1doutput(Rank2View splinv, - Rank1View gt_splinv, - const double gt_dif, const double gt_difr, - std::string label) { - // Compare the output of splinv with gt_splinv - double result_fdif = 0.0; - double result_fdifr = 0.0; - Kokkos::parallel_reduce( - "compare_splinv", splinv.extent(0), - KOKKOS_LAMBDA(const int i, double &max_fdif, double &max_fdifr) { - if (splinv(i, 0) != 0.0) { - double dif = Kokkos::abs(splinv(i, 0) - gt_splinv(i)); - max_fdif = Kokkos::max(max_fdif, dif); - max_fdifr = Kokkos::max(max_fdifr, dif / gt_splinv(i)); - } - }, - Kokkos::Max(result_fdif), Kokkos::Max(result_fdifr)); - double fdif = result_fdif; - double fdifr = result_fdifr; - std::cout << "1d " << label << " max absolute difference: " << fdif - << ", relative difference: " << fdifr << std::endl; - assert(are_equal(fdif, gt_dif)); - assert(are_equal(fdifr, gt_difr)); -} - -void compare_output(Rank2View splinv, - Rank1View gt_splinv, - const double gt_dif, const double gt_difr, - std::string label) { - // Compare the output of splinv with gt_splinv - double result_fdif = 0.0; - double result_fdifr = 0.0; - Kokkos::parallel_reduce( - "compare_splinv", splinv.extent(0), - KOKKOS_LAMBDA(const int i, double &max_fdif, double &max_fdifr) { - if (splinv(i, 0) != 0.0) { - double dif = Kokkos::abs(splinv(i, 0) - gt_splinv(i)); - max_fdif = Kokkos::max(max_fdif, dif); - max_fdifr = Kokkos::max(max_fdifr, - dif / (0.5 * (splinv(i, 0) + gt_splinv(i)))); - } - }, - Kokkos::Max(result_fdif), Kokkos::Max(result_fdifr)); - double fdif = result_fdif; - double fdifr = result_fdifr; - std::cout << "2d " << label << " max absolute difference: " << fdif - << ", relative difference: " << fdifr << std::endl; - assert(are_equal(fdif, gt_dif)); - assert(are_equal(fdifr, gt_difr)); -} - void compare(Rank2View splinv, Rank1View gt_splinv, Rank1View res, std::string label) { From b2d70bc4eff7e22eeed3064595f587d0da360dbc Mon Sep 17 00:00:00 2001 From: Sichao25 Date: Thu, 31 Jul 2025 13:13:54 -0400 Subject: [PATCH 03/18] create more constructor --- src/pcms/interpolator/spline_interpolator.hpp | 336 +++++++++++++++++- test/test_spline_interpolator.cpp | 60 +++- 2 files changed, 382 insertions(+), 14 deletions(-) diff --git a/src/pcms/interpolator/spline_interpolator.hpp b/src/pcms/interpolator/spline_interpolator.hpp index 1fd3d6341..a43a975c1 100644 --- a/src/pcms/interpolator/spline_interpolator.hpp +++ b/src/pcms/interpolator/spline_interpolator.hpp @@ -50,20 +50,24 @@ T get_element_from_span(Rank1View span, LO index) { auto element_host = Kokkos::create_mirror_view(data_view); Kokkos::deep_copy(element_host, data_view); element = element_host(0); - printf("Element at index %d: %f\n", index, element); return element; } // TODO: better documentation // TODO: add more checks/assetions for input parameters template class CubicSplineInterpolator { +private: + Kokkos::View coefficients_; public: CubicSplineInterpolator() = default; using execution_space = typename MemorySpace::execution_space; using member_type = typename Kokkos::TeamPolicy::member_type; Rank1View x_; LO nx_; + Kokkos::View get_coefficients(); + void set_coefficients(Kokkos::View coefficients); static void sanity_check(Rank1View x, const T &ztol); + void initialize_fspl(Rank2View fspl, Rank1View values); static KOKKOS_INLINE_FUNCTION void range_check(T &xget, T &zxget, Rank1View x, @@ -91,6 +95,11 @@ class ExplicitCubicSplineInterpolator const LO &ibcxmin, const T &bcxmin, const LO &ibcxmax, const T &bcxmax, Rank1View wk); + ExplicitCubicSplineInterpolator(Rank1View x, Rank1View values, + const LO &ibcxmin, const T &bcxmin, + const LO &ibcxmax, const T &bcxmax); + ExplicitCubicSplineInterpolator(Rank1View x, + Rank1View values); Rank2View fspl_; void setup(Rank1View x, const LO &nx, Rank2View fspl, const LO &ibcxmin, const T &bcxmin, @@ -114,6 +123,9 @@ class ExplicitCubicSplineInterpolator static KOKKOS_INLINE_FUNCTION void lookup(T xget, Rank1View x, const LO &nx, LO &i, T &dx, LO &ier); + + void evaluate(Rank1View xvec, Rank2View fval); + void evaluate(Kokkos::View selector, Rank1View xvec, Rank2View fval); }; @@ -132,6 +144,11 @@ class CompactCubicSplineInterpolator const LO &ibcxmin, const T &bcxmin, const LO &ibcxmax, const T &bcxmax, Rank1View wk); + CompactCubicSplineInterpolator(Rank1View x, Rank1View values, + const LO &ibcxmin, const T &bcxmin, + const LO &ibcxmax, const T &bcxmax); + CompactCubicSplineInterpolator(Rank1View x, + Rank1View values); void setup(Rank1View x, const LO &nx, Rank2View fspl, Rank2View fspl4, const LO &ibcxmin, const T &bcxmin, const LO &ibcxmax, @@ -156,6 +173,8 @@ class CompactCubicSplineInterpolator const LO &nx, LO &i, T &xparam, T &hx, T &hxi, LO &ier); + void evaluate(Rank1View xvec, Rank2View fval); + void evaluate(Kokkos::View selector, Rank1View xvec, Rank2View fval); }; @@ -190,6 +209,29 @@ class ExplicitBiCubicSplineInterpolator Rank1View wk // size: nwk ); + ExplicitBiCubicSplineInterpolator( + Rank1View x, // size: inx + Rank1View th, // size: inth + Rank1View values, + LO ibcxmin, + Rank1View bcxmin, // size: inth (used if ibcxmin = 1 or 2) + LO ibcxmax, + Rank1View bcxmax, // size: inth (used if ibcxmax = 1 or 2) + LO ibcthmin, + Rank1View + bcthmin, // size: inx (used if ibcthmin = 1 or 2) + LO ibcthmax, + Rank1View bcthmax + ); + + ExplicitBiCubicSplineInterpolator( + Rank1View x, // size: inx + Rank1View th, // size: inth + Rank1View values + ); + + void initialize_fspl(Rank4View fspl, Rank1View values); + static void solve_spline( Rank1View x, // size: inx LO inx, Rank1View th, // size: inth @@ -229,6 +271,9 @@ class ExplicitBiCubicSplineInterpolator Rank4View fspl // Spline coefficients: [4, 4, nx, ny] ); + void evaluate(Rank1View xvec, Rank1View yvec, + Rank2View fval); + void evaluate(Kokkos::View iselect, Rank1View xvec, Rank1View yvec, Rank2View fval); @@ -255,6 +300,20 @@ class CompactBiCubicSplineInterpolator Rank1View bcymax, Rank1View wk); + CompactBiCubicSplineInterpolator(Rank1View x, + Rank1View y, + Rank1View values, LO ibcxmin, + Rank1View bcxmin, LO ibcxmax, + Rank1View bcxmax, LO ibcymin, + Rank1View bcymin, LO ibcymax, + Rank1View bcymax); + + CompactBiCubicSplineInterpolator(Rank1View x, + Rank1View y, + Rank1View values); + + void initialize_fspl(Rank3View fspl, Rank1View values); + static void solve_spline(Rank1View x, LO nx, Rank1View y, LO ny, Rank3View f, LO ibcxmin, @@ -280,11 +339,26 @@ class CompactBiCubicSplineInterpolator Rank1View fval, // output (size depends on ict) Rank1View x, const LO &nx, Rank1View y, const LO &ny, Rank3View f, LO &ier); + + void evaluate(Rank1View xvec, Rank1View yvec, + Rank2View fval); + void evaluate(Kokkos::View iselect, Rank1View xvec, Rank1View yvec, Rank2View fval); }; +template +Kokkos::View CubicSplineInterpolator::get_coefficients() { + return coefficients_; +} + +template +void CubicSplineInterpolator::set_coefficients( + Kokkos::View coefficients) { + coefficients_ = coefficients; +} + template void CubicSplineInterpolator::correction_detect( Rank1View bcmin, LO &ibcmin, LO &iflg2, LO &nx) { @@ -321,6 +395,53 @@ void CubicSplineInterpolator::sanity_check( }); } +template +void CubicSplineInterpolator::initialize_fspl(Rank2View fspl, Rank1View values) { + Kokkos::parallel_for( + "set_coefficients", Kokkos::RangePolicy(0, this->nx_), + KOKKOS_LAMBDA(const LO i) { fspl(0, i) = values(i); }); +} + +template +ExplicitCubicSplineInterpolator:: + ExplicitCubicSplineInterpolator(Rank1View x, + Rank1View values, + const LO &ibcxmin, const T &bcxmin, + const LO &ibcxmax, const T &bcxmax) { + PCMS_ALWAYS_ASSERT(x.extent(0) >= 2); + + ibc_check(ibcxmin, "1d spline", "xmin", -1, 7); + if (ibcxmin >= 0) + ibc_check(ibcxmax, "1d spline", "xmax", 0, 7); + CubicSplineInterpolator::sanity_check(x, 1.0e-3); + + this->nx_ = x.extent(0); + this->x_ = x; + + Kokkos::View fspl_view("coefficients", 4 * this->nx_); + CubicSplineInterpolator::set_coefficients(fspl_view); + auto fspl = Rank2View(fspl_view.data(), 4, this->nx_); + // Kokkos::parallel_for( + // "set_coefficients", Kokkos::RangePolicy(0, this->nx_), + // KOKKOS_LAMBDA(const LO i) { fspl(0, i) = values(i); }); + CubicSplineInterpolator::initialize_fspl(fspl, values); + + Kokkos::View wk_view("working space", 10); + auto wk = Rank1View(wk_view.data(), 10); + + setup(x, this->nx_, fspl, ibcxmin, bcxmin, ibcxmax, bcxmax, wk); + + this->fspl_ = fspl; +} + +template +ExplicitCubicSplineInterpolator:: + ExplicitCubicSplineInterpolator(Rank1View x, + Rank1View values) : ExplicitCubicSplineInterpolator( + x, values, 0, 0, 0, 0){ // Delegates to primary constructor + std::cout << "Not a knot boundary condition is applied by default" << std::endl; +} + template ExplicitCubicSplineInterpolator:: ExplicitCubicSplineInterpolator(Rank1View x, const LO &nx, @@ -329,6 +450,10 @@ ExplicitCubicSplineInterpolator:: const LO &ibcxmax, const T &bcxmax, Rank1View wk) { PCMS_ALWAYS_ASSERT(x.extent(0) >= 2); + ibc_check(ibcxmin, "1d spline", "xmin", -1, 7); + if (ibcxmin >= 0) + ibc_check(ibcxmax, "1d spline", "xmax", 0, 7); + CubicSplineInterpolator::sanity_check(x, 1.0e-3); this->nx_ = x.extent(0); this->x_ = x; setup(x, nx, fspl, ibcxmin, bcxmin, ibcxmax, bcxmax, wk); @@ -356,11 +481,55 @@ CompactCubicSplineInterpolator::CompactCubicSplineInterpolator( Rank2View fspl4, const LO &ibcxmin, const T &bcxmin, const LO &ibcxmax, const T &bcxmax, Rank1View wk) { this->nx_ = x.extent(0); + ibc_check(ibcxmin, "1d spline", "xmin", -1, 7); + if (ibcxmin >= 0) + ibc_check(ibcxmax, "1d spline", "xmax", 0, 7); + CubicSplineInterpolator::sanity_check(x, 1.0e-3); this->x_ = x; setup(x, nx, fspl, fspl4, ibcxmin, bcxmin, ibcxmax, bcxmax, wk); this->fs2_ = fspl; } +template +CompactCubicSplineInterpolator:: + CompactCubicSplineInterpolator(Rank1View x, + Rank1View values, + const LO &ibcxmin, const T &bcxmin, + const LO &ibcxmax, const T &bcxmax) { + PCMS_ALWAYS_ASSERT(x.extent(0) >= 2); + ibc_check(ibcxmin, "1d spline", "xmin", -1, 7); + if (ibcxmin >= 0) + ibc_check(ibcxmax, "1d spline", "xmax", 0, 7); + CubicSplineInterpolator::sanity_check(x, 1.0e-3); + this->nx_ = x.extent(0); + this->x_ = x; + + Kokkos::View fspl_view("coefficients", 2 * this->nx_); + CubicSplineInterpolator::set_coefficients(fspl_view); + auto fspl = Rank2View(fspl_view.data(), 2, this->nx_); + // Kokkos::parallel_for( + // "set_coefficients", Kokkos::RangePolicy(0, this->nx_), + // KOKKOS_LAMBDA(const LO i) { fspl(0, i) = values(i); }); + CubicSplineInterpolator::initialize_fspl(fspl, values); + + Kokkos::View fspl4_view("explicit coefficients", 4 * this->nx_); + auto fspl4 = Rank2View(fspl4_view.data(), 4, this->nx_); + Kokkos::View wk_view("working space", 10); + auto wk = Rank1View(wk_view.data(), 10); + + setup(x, this->nx_, fspl, fspl4, ibcxmin, bcxmin, ibcxmax, bcxmax, wk); + + this->fs2_ = fspl; +} + +template +CompactCubicSplineInterpolator:: + CompactCubicSplineInterpolator(Rank1View x, + Rank1View fx) : CompactCubicSplineInterpolator( + x, fx, 0, 0, 0, 0){ // Delegates to primary constructor + std::cout << "Not a knot boundary condition is applied by default" << std::endl; +} + template void CompactCubicSplineInterpolator::setup( Rank1View x, const LO &nx, Rank2View fspl, @@ -1010,6 +1179,13 @@ void ExplicitCubicSplineInterpolator::evaluate( }); } +template +void ExplicitCubicSplineInterpolator::evaluate(Rank1View xvec, + Rank2View fval) { + std::array ict_arr = {1, 0, 0}; + evaluate(Kokkos::View(ict_arr.data(), 3), xvec, fval); +}; + template void CompactCubicSplineInterpolator::evaluate( Kokkos::View selector, Rank1View xvec, @@ -1026,6 +1202,14 @@ void CompactCubicSplineInterpolator::evaluate( }); } +// TODO: evluation functions are exactly the same, so put them in base class? +template +void CompactCubicSplineInterpolator::evaluate(Rank1View xvec, + Rank2View fval) { + std::array ict_arr = {1, 0, 0}; + evaluate(Kokkos::View(ict_arr.data(), 3), xvec, fval); +}; + template KOKKOS_INLINE_FUNCTION void CompactCubicSplineInterpolator::evalfn( @@ -1182,6 +1366,77 @@ ExplicitBiCubicSplineInterpolator:: fspl_ = fspl; } +template +void ExplicitBiCubicSplineInterpolator::initialize_fspl(Rank4View fspl, Rank1View values) { + LO ny = this->ny_; + Kokkos::parallel_for( + Kokkos::MDRangePolicy>({0, 0}, {ny, this->nx_}), + KOKKOS_LAMBDA(const LO ith, const LO ix) { + fspl(0, 0, ix, ith) = values(ix * ny + ith); + }); +} + +template +ExplicitBiCubicSplineInterpolator:: + ExplicitBiCubicSplineInterpolator( + Rank1View x, // size: inx + Rank1View th, // size: inth + Rank1View values, + LO ibcxmin, + Rank1View + bcxmin, // size: inth (used if ibcxmin = 1 or 2) + LO ibcxmax, + Rank1View + bcxmax, // size: inth (used if ibcxmax = 1 or 2) + LO ibcthmin, + Rank1View + bcthmin, // size: inx (used if ibcthmin = 1 or 2) + LO ibcthmax, + Rank1View + bcthmax // size: inx (used if ibcthmax = 1 or 2) + ) { + PCMS_ALWAYS_ASSERT(x.extent(0) >= 2); + PCMS_ALWAYS_ASSERT(th.extent(0) >= 2); + + // Check boundary condition values + ibc_check(ibcxmin, "2d spline", "xmin", -1, 7); + if (ibcxmin >= 0) + ibc_check(ibcxmax, "2d spline", "xmax", 0, 7); + ibc_check(ibcthmin, "2d spline", "thmin", -1, 7); + if (ibcthmin >= 0) + ibc_check(ibcthmax, "2d spline", "thmax", 0, 7); + + CubicSplineInterpolator::sanity_check(x, 1.0e-3); + CubicSplineInterpolator::sanity_check(th, 1.0e-3); + this->x_ = x; + this->nx_ = x.extent(0); + this->y_ = th; + this->ny_ = th.extent(0); + + Kokkos::View fspl_view("fspl view", 4 * 4 * this->nx_ * this->ny_); + CubicSplineInterpolator::set_coefficients(fspl_view); + auto fspl = Rank4View( + fspl_view.data(), 4, 4, this->nx_, this->ny_); + initialize_fspl(fspl, values); + + Kokkos::View wk_view("wk", 9 * this->nx_ * this->ny_); + auto wk = Rank1View(wk_view.data(), 9 * this->nx_ * this->ny_); + + solve_spline(x, this->nx_, th, this->ny_, fspl, ibcxmin, bcxmin, ibcxmax, bcxmax, + ibcthmin, bcthmin, ibcthmax, bcthmax, wk); + + this->fspl_ = fspl; +} + +template +ExplicitBiCubicSplineInterpolator:: + ExplicitBiCubicSplineInterpolator(Rank1View x, // size: inx + Rank1View th, // size: inth + Rank1View values): ExplicitBiCubicSplineInterpolator( + x, th, values, 0, {}, 0, {}, 0, {}, 0, {}){ // Delegates to primary constructor + std::cout << "Not a knot boundary condition is applied by default" << std::endl; +} + template void ExplicitBiCubicSplineInterpolator::solve_spline( Rank1View x, // size: inx @@ -1479,6 +1734,18 @@ void ExplicitBiCubicSplineInterpolator::evaluate( }); } +template +void ExplicitBiCubicSplineInterpolator::evaluate(Rank1View xvec, + Rank1View yvec, Rank2View fval) { + LO ict_arr[10] = {1, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + Kokkos::View ict("select", 10); + Kokkos::parallel_for( + Kokkos::RangePolicy(0, ict.size()), + KOKKOS_LAMBDA(const LO i) { ict(i) = ict_arr[i]; }); + evaluate(ict, xvec, yvec, fval); + +} + template void CompactBiCubicSplineInterpolator::evaluate( Kokkos::View iselect, Rank1View xvec, @@ -1498,6 +1765,18 @@ void CompactBiCubicSplineInterpolator::evaluate( }); } +template +void CompactBiCubicSplineInterpolator::evaluate(Rank1View xvec, + Rank1View yvec, Rank2View fval) { + LO ict_arr[10] = {1, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + Kokkos::View ict("select", 10); + Kokkos::parallel_for( + Kokkos::RangePolicy(0, ict.size()), + KOKKOS_LAMBDA(const LO i) { ict(i) = ict_arr[i]; }); + evaluate(ict, xvec, yvec, fval); + +} + template KOKKOS_INLINE_FUNCTION void ExplicitBiCubicSplineInterpolator::eval( @@ -1766,6 +2045,8 @@ CompactBiCubicSplineInterpolator:: Rank1View bcymin, LO ibcymax, Rank1View bcymax, Rank1View wk) { // Check bc validity + PCMS_ALWAYS_ASSERT(x.extent(0) > 2); + PCMS_ALWAYS_ASSERT(y.extent(0) > 2); ibc_check(ibcxmin, "2d spline", "xmin", -1, 7); if (ibcxmin >= 0) ibc_check(ibcxmax, "2d spline", "xmax", 0, 7); @@ -1784,6 +2065,59 @@ CompactBiCubicSplineInterpolator:: this->f_ = f; // Store the spline coefficients } +template +void CompactBiCubicSplineInterpolator::initialize_fspl( + Rank3View fspl, Rank1View values) { + LO ny = this->ny_; + Kokkos::parallel_for( + Kokkos::MDRangePolicy>({0, 0}, {ny, this->nx_}), + KOKKOS_LAMBDA(const LO ith, const LO ix) { + fspl(0, ix, ith) = values(ix * ny + ith); + }); + } + + +template +CompactBiCubicSplineInterpolator::CompactBiCubicSplineInterpolator(Rank1View x, + Rank1View y, + Rank1View values, LO ibcxmin, + Rank1View bcxmin, LO ibcxmax, + Rank1View bcxmax, LO ibcymin, + Rank1View bcymin, LO ibcymax, + Rank1View bcymax) { + this->x_ = x; // Store the x-coordinates + this->y_ = y; // Store the y-coordinates + this->nx_ = x.extent(0); // Store the number of x-coordinates + this->ny_ = y.extent(0); // Store the number of y-coordinates + + Kokkos::View fspl_view("fspl view", 4 * this->nx_ * this->ny_); + CubicSplineInterpolator::set_coefficients(fspl_view); + auto fspl = Rank3View( + fspl_view.data(), 4, this->nx_, this->ny_); + // Kokkos::parallel_for( + // Kokkos::MDRangePolicy>({0, 0}, {this->ny_, this->nx_}), + // KOKKOS_LAMBDA(const int ith, const int ix) { + // fspl(0, ix, ith) = values(ix * this->ny_ + ith); + // }); + initialize_fspl(fspl, values); + + Kokkos::View wk_view("wk", 9 * this->nx_ * this->ny_); + auto wk = Rank1View(wk_view.data(), 9 * this->nx_ * this->ny_); + + solve_spline(x, this->nx_, y, this->ny_, fspl, ibcxmin, bcxmin, ibcxmax, bcxmax, ibcymin, + bcymin, ibcymax, bcymax, wk); + this->f_ = fspl; // Store the spline coefficients +} + +template +CompactBiCubicSplineInterpolator:: + CompactBiCubicSplineInterpolator(Rank1View x, // size: inx + Rank1View y, // size: inth + Rank1View values): CompactBiCubicSplineInterpolator( + x, y, values, 0, {}, 0, {}, 0, {}, 0, {}){ // Delegates to primary constructor + std::cout << "Not a knot boundary condition is applied by default" << std::endl; +} + template void CompactBiCubicSplineInterpolator::solve_spline( Rank1View x, LO nx, Rank1View y, LO ny, diff --git a/test/test_spline_interpolator.cpp b/test/test_spline_interpolator.cpp index 0f290ef7e..29e3d27ac 100644 --- a/test/test_spline_interpolator.cpp +++ b/test/test_spline_interpolator.cpp @@ -10,6 +10,29 @@ using namespace pcms; using TestMemorySpace = Kokkos::DefaultExecutionSpace; + +void print_4dmdspan( + const Rank4View &span) { + Kokkos::parallel_for( + Kokkos::MDRangePolicy>({0, 0, 0, 0}, + {span.extent(0), span.extent(1), + span.extent(2), span.extent(3)}), + KOKKOS_LAMBDA(int i, int j, int k, int l) { + printf("span(%d, %d, %d, %d) = %f\n", i, j, k, l, span(i, j, k, l)); + }); +} + +void print_3dmdspan( + const Rank3View &span) { + Kokkos::parallel_for( + Kokkos::MDRangePolicy>({0, 0, 0}, + {span.extent(0), span.extent(1), + span.extent(2)}), + KOKKOS_LAMBDA(int i, int j, int k) { + printf("span(%d, %d, %d) = %f\n", i, j, k, span(i, j, k)); + }); +} + bool are_equal(double a, double b, double tolerance = 1e-7) { return std::abs(a - b) < tolerance; } @@ -181,7 +204,7 @@ void dotest1(int ns, Rank1View x, // interpolator.cspline(x, ns, fspl, 1, 1, 1, 1, wk); ExplicitCubicSplineInterpolator - explicit_interpolator(x, ns, fspl, 1, 1, 1, 1, wk); + explicit_interpolator(x, f, 1, 1, 1, 1); int ict_arr[3] = {1, 0, 0}; Kokkos::View ict("ict", 3); @@ -192,22 +215,22 @@ void dotest1(int ns, Rank1View x, Kokkos::View splinv_view("splinv_view", 3000); auto splinv = Rank2View(splinv_view.data(), 1000, 3); reset_2dspan(splinv); - explicit_interpolator.evaluate(ict, xt, splinv); + explicit_interpolator.evaluate(xt, splinv); auto res1 = Rank1View(res_1d.data(), 2); compare(splinv, ft, res1, "cspline"); reset_2dspan(splinv); ExplicitCubicSplineInterpolator - explicit_interpolator_periodic(x, ns, fspp, -1, 0, -1, 0, wk); - explicit_interpolator_periodic.evaluate(ict, xt, splinv); + explicit_interpolator_periodic(x, f, -1, 0, -1, 0); + explicit_interpolator_periodic.evaluate(xt, splinv); auto res2 = Rank1View(res_1d.data() + 2, 2); compare(splinv, ft, res2, "cspline_periodic"); reset_2dspan(splinv); CompactCubicSplineInterpolator compact_interpolator( - x, ns, fs2, fspl4, 1, 1, 1, 1, wk2); - compact_interpolator.evaluate(ict, xt, splinv); + x, f, 1, 1,1 ,1); + compact_interpolator.evaluate(xt, splinv); auto res3 = Rank1View(res_1d.data() + 4, 2); compare(splinv, ft, res3, "compact_cubic"); } @@ -292,6 +315,15 @@ void dotest2(Rank1View x, fh(2, ix, ith) = fx(ix) * dfth(ith); // df/dy fh(3, ix, ith) = 2.0 * fx(ix) * dfth(ith); // d2f/dxdy }); + + Kokkos::View values_view("f_vec", nth * nx); + Kokkos::parallel_for( + Kokkos::MDRangePolicy>({0, 0}, {nth, nx}), + KOKKOS_LAMBDA(const int ith, const int ix) { + values_view(ix * nth + ith) = f(0, 0, ix, ith); + }); + + auto values = Rank1View(values_view.data(), nth * nx); int nbc = 1; Kokkos::View wk_vec("wk_vec", 900); @@ -299,9 +331,8 @@ void dotest2(Rank1View x, bset(fx, nx, fth, nth, bcx1, bcx2, bcth1, bcth2); ExplicitBiCubicSplineInterpolator - explicit_interpolator(x, nx, th, nth, f, nbc, bcx1, nbc, bcx2, nbc, bcth1, - nbc, bcth2, wk); - + explicit_interpolator(x, th, values, nbc, bcx1, nbc, bcx2, nbc, bcth1, + nbc, bcth2); Kokkos::View splinv_view("splinv_view", 400000); auto splinv = Rank2View(splinv_view.data(), 40000, 10); @@ -327,18 +358,21 @@ void dotest2(Rank1View x, generate_gt_2d(splinv_gt, fxtest, fthtest, ntest); // TODO: evaluate function raise memeory acess violation - explicit_interpolator.evaluate(isel, xtest_grid, thtest_grid, splinv); + explicit_interpolator.evaluate(xtest_grid, thtest_grid, splinv); auto res1 = Rank1View(res_2d.data(), 2); compare_2d(splinv, splinv_gt, res1, "bcspline"); reset_2dspan(splinv); CompactBiCubicSplineInterpolator - compact_interpolator(x, nx, th, nth, fh, nbc, bcx1, nbc, bcx2, nbc, bcth1, - nbc, bcth2, wk); - compact_interpolator.evaluate(isel, xtest_grid, thtest_grid, splinv); + compact_interpolator(x, th, values, nbc, bcx1, nbc, bcx2, nbc, bcth1, + nbc, bcth2); + compact_interpolator.evaluate(xtest_grid, thtest_grid, splinv); auto res2 = Rank1View(res_2d.data() + 2, 2); compare_2d(splinv, splinv_gt, res2, "mkbicub"); + + // CompactBiCubicSplineInterpolator + // test_interpolator(x, th, values); } void pspltest2(Kokkos::View res_2d) { From bb26ebfefc5c5acc5dd4ae0be440bcd0cc54d471 Mon Sep 17 00:00:00 2001 From: Sichao25 Date: Thu, 31 Jul 2025 14:33:21 -0400 Subject: [PATCH 04/18] clean the test --- src/pcms/interpolator/spline_interpolator.hpp | 212 +++++++++--------- test/test_spline_interpolator.cpp | 171 +++----------- 2 files changed, 138 insertions(+), 245 deletions(-) diff --git a/src/pcms/interpolator/spline_interpolator.hpp b/src/pcms/interpolator/spline_interpolator.hpp index a43a975c1..85d4a2714 100644 --- a/src/pcms/interpolator/spline_interpolator.hpp +++ b/src/pcms/interpolator/spline_interpolator.hpp @@ -1,4 +1,3 @@ - #ifndef MLS_RBF_OPTIONS_HPP #define MLS_RBF_OPTIONS_HPP @@ -58,6 +57,7 @@ T get_element_from_span(Rank1View span, LO index) { template class CubicSplineInterpolator { private: Kokkos::View coefficients_; + public: CubicSplineInterpolator() = default; using execution_space = typename MemorySpace::execution_space; @@ -67,7 +67,8 @@ template class CubicSplineInterpolator { Kokkos::View get_coefficients(); void set_coefficients(Kokkos::View coefficients); static void sanity_check(Rank1View x, const T &ztol); - void initialize_fspl(Rank2View fspl, Rank1View values); + void initialize_fspl(Rank2View fspl, + Rank1View values); static KOKKOS_INLINE_FUNCTION void range_check(T &xget, T &zxget, Rank1View x, @@ -95,7 +96,8 @@ class ExplicitCubicSplineInterpolator const LO &ibcxmin, const T &bcxmin, const LO &ibcxmax, const T &bcxmax, Rank1View wk); - ExplicitCubicSplineInterpolator(Rank1View x, Rank1View values, + ExplicitCubicSplineInterpolator(Rank1View x, + Rank1View values, const LO &ibcxmin, const T &bcxmin, const LO &ibcxmax, const T &bcxmax); ExplicitCubicSplineInterpolator(Rank1View x, @@ -144,11 +146,12 @@ class CompactCubicSplineInterpolator const LO &ibcxmin, const T &bcxmin, const LO &ibcxmax, const T &bcxmax, Rank1View wk); - CompactCubicSplineInterpolator(Rank1View x, Rank1View values, - const LO &ibcxmin, const T &bcxmin, - const LO &ibcxmax, const T &bcxmax); CompactCubicSplineInterpolator(Rank1View x, - Rank1View values); + Rank1View values, + const LO &ibcxmin, const T &bcxmin, + const LO &ibcxmax, const T &bcxmax); + CompactCubicSplineInterpolator(Rank1View x, + Rank1View values); void setup(Rank1View x, const LO &nx, Rank2View fspl, Rank2View fspl4, const LO &ibcxmin, const T &bcxmin, const LO &ibcxmax, @@ -210,27 +213,23 @@ class ExplicitBiCubicSplineInterpolator ); ExplicitBiCubicSplineInterpolator( - Rank1View x, // size: inx - Rank1View th, // size: inth - Rank1View values, - LO ibcxmin, + Rank1View x, // size: inx + Rank1View th, // size: inth + Rank1View values, LO ibcxmin, Rank1View bcxmin, // size: inth (used if ibcxmin = 1 or 2) LO ibcxmax, Rank1View bcxmax, // size: inth (used if ibcxmax = 1 or 2) LO ibcthmin, Rank1View bcthmin, // size: inx (used if ibcthmin = 1 or 2) - LO ibcthmax, - Rank1View bcthmax - ); + LO ibcthmax, Rank1View bcthmax); - ExplicitBiCubicSplineInterpolator( - Rank1View x, // size: inx - Rank1View th, // size: inth - Rank1View values - ); + ExplicitBiCubicSplineInterpolator(Rank1View x, // size: inx + Rank1View th, // size: inth + Rank1View values); - void initialize_fspl(Rank4View fspl, Rank1View values); + void initialize_fspl(Rank4View fspl, + Rank1View values); static void solve_spline( Rank1View x, // size: inx @@ -307,12 +306,13 @@ class CompactBiCubicSplineInterpolator Rank1View bcxmax, LO ibcymin, Rank1View bcymin, LO ibcymax, Rank1View bcymax); - + CompactBiCubicSplineInterpolator(Rank1View x, Rank1View y, Rank1View values); - - void initialize_fspl(Rank3View fspl, Rank1View values); + + void initialize_fspl(Rank3View fspl, + Rank1View values); static void solve_spline(Rank1View x, LO nx, Rank1View y, LO ny, @@ -349,7 +349,8 @@ class CompactBiCubicSplineInterpolator }; template -Kokkos::View CubicSplineInterpolator::get_coefficients() { +Kokkos::View +CubicSplineInterpolator::get_coefficients() { return coefficients_; } @@ -396,7 +397,8 @@ void CubicSplineInterpolator::sanity_check( } template -void CubicSplineInterpolator::initialize_fspl(Rank2View fspl, Rank1View values) { +void CubicSplineInterpolator::initialize_fspl( + Rank2View fspl, Rank1View values) { Kokkos::parallel_for( "set_coefficients", Kokkos::RangePolicy(0, this->nx_), KOKKOS_LAMBDA(const LO i) { fspl(0, i) = values(i); }); @@ -421,9 +423,6 @@ ExplicitCubicSplineInterpolator:: Kokkos::View fspl_view("coefficients", 4 * this->nx_); CubicSplineInterpolator::set_coefficients(fspl_view); auto fspl = Rank2View(fspl_view.data(), 4, this->nx_); - // Kokkos::parallel_for( - // "set_coefficients", Kokkos::RangePolicy(0, this->nx_), - // KOKKOS_LAMBDA(const LO i) { fspl(0, i) = values(i); }); CubicSplineInterpolator::initialize_fspl(fspl, values); Kokkos::View wk_view("working space", 10); @@ -437,9 +436,11 @@ ExplicitCubicSplineInterpolator:: template ExplicitCubicSplineInterpolator:: ExplicitCubicSplineInterpolator(Rank1View x, - Rank1View values) : ExplicitCubicSplineInterpolator( - x, values, 0, 0, 0, 0){ // Delegates to primary constructor - std::cout << "Not a knot boundary condition is applied by default" << std::endl; + Rank1View values) + : ExplicitCubicSplineInterpolator(x, values, 0, 0, 0, + 0) { // Delegates to primary constructor + std::cout << "Not a knot boundary condition is applied by default" + << std::endl; } template @@ -491,11 +492,9 @@ CompactCubicSplineInterpolator::CompactCubicSplineInterpolator( } template -CompactCubicSplineInterpolator:: - CompactCubicSplineInterpolator(Rank1View x, - Rank1View values, - const LO &ibcxmin, const T &bcxmin, - const LO &ibcxmax, const T &bcxmax) { +CompactCubicSplineInterpolator::CompactCubicSplineInterpolator( + Rank1View x, Rank1View values, + const LO &ibcxmin, const T &bcxmin, const LO &ibcxmax, const T &bcxmax) { PCMS_ALWAYS_ASSERT(x.extent(0) >= 2); ibc_check(ibcxmin, "1d spline", "xmin", -1, 7); if (ibcxmin >= 0) @@ -507,12 +506,10 @@ CompactCubicSplineInterpolator:: Kokkos::View fspl_view("coefficients", 2 * this->nx_); CubicSplineInterpolator::set_coefficients(fspl_view); auto fspl = Rank2View(fspl_view.data(), 2, this->nx_); - // Kokkos::parallel_for( - // "set_coefficients", Kokkos::RangePolicy(0, this->nx_), - // KOKKOS_LAMBDA(const LO i) { fspl(0, i) = values(i); }); CubicSplineInterpolator::initialize_fspl(fspl, values); - Kokkos::View fspl4_view("explicit coefficients", 4 * this->nx_); + Kokkos::View fspl4_view("explicit coefficients", + 4 * this->nx_); auto fspl4 = Rank2View(fspl4_view.data(), 4, this->nx_); Kokkos::View wk_view("working space", 10); auto wk = Rank1View(wk_view.data(), 10); @@ -523,11 +520,12 @@ CompactCubicSplineInterpolator:: } template -CompactCubicSplineInterpolator:: - CompactCubicSplineInterpolator(Rank1View x, - Rank1View fx) : CompactCubicSplineInterpolator( - x, fx, 0, 0, 0, 0){ // Delegates to primary constructor - std::cout << "Not a knot boundary condition is applied by default" << std::endl; +CompactCubicSplineInterpolator::CompactCubicSplineInterpolator( + Rank1View x, Rank1View fx) + : CompactCubicSplineInterpolator(x, fx, 0, 0, 0, + 0) { // Delegates to primary constructor + std::cout << "Not a knot boundary condition is applied by default" + << std::endl; } template @@ -1180,8 +1178,8 @@ void ExplicitCubicSplineInterpolator::evaluate( } template -void ExplicitCubicSplineInterpolator::evaluate(Rank1View xvec, - Rank2View fval) { +void ExplicitCubicSplineInterpolator::evaluate( + Rank1View xvec, Rank2View fval) { std::array ict_arr = {1, 0, 0}; evaluate(Kokkos::View(ict_arr.data(), 3), xvec, fval); }; @@ -1204,8 +1202,8 @@ void CompactCubicSplineInterpolator::evaluate( // TODO: evluation functions are exactly the same, so put them in base class? template -void CompactCubicSplineInterpolator::evaluate(Rank1View xvec, - Rank2View fval) { +void CompactCubicSplineInterpolator::evaluate( + Rank1View xvec, Rank2View fval) { std::array ict_arr = {1, 0, 0}; evaluate(Kokkos::View(ict_arr.data(), 3), xvec, fval); }; @@ -1366,23 +1364,23 @@ ExplicitBiCubicSplineInterpolator:: fspl_ = fspl; } -template -void ExplicitBiCubicSplineInterpolator::initialize_fspl(Rank4View fspl, Rank1View values) { - LO ny = this->ny_; - Kokkos::parallel_for( +template +void ExplicitBiCubicSplineInterpolator::initialize_fspl( + Rank4View fspl, Rank1View values) { + LO ny = this->ny_; + Kokkos::parallel_for( Kokkos::MDRangePolicy>({0, 0}, {ny, this->nx_}), - KOKKOS_LAMBDA(const LO ith, const LO ix) { - fspl(0, 0, ix, ith) = values(ix * ny + ith); + KOKKOS_LAMBDA(const LO ith, const LO ix) { + fspl(0, 0, ix, ith) = values(ix * ny + ith); }); } template ExplicitBiCubicSplineInterpolator:: ExplicitBiCubicSplineInterpolator( - Rank1View x, // size: inx - Rank1View th, // size: inth - Rank1View values, - LO ibcxmin, + Rank1View x, // size: inx + Rank1View th, // size: inth + Rank1View values, LO ibcxmin, Rank1View bcxmin, // size: inth (used if ibcxmin = 1 or 2) LO ibcxmax, @@ -1393,7 +1391,7 @@ ExplicitBiCubicSplineInterpolator:: bcthmin, // size: inx (used if ibcthmin = 1 or 2) LO ibcthmax, Rank1View - bcthmax // size: inx (used if ibcthmax = 1 or 2) + bcthmax // size: inx (used if ibcthmax = 1 or 2) ) { PCMS_ALWAYS_ASSERT(x.extent(0) >= 2); PCMS_ALWAYS_ASSERT(th.extent(0) >= 2); @@ -1413,28 +1411,34 @@ ExplicitBiCubicSplineInterpolator:: this->y_ = th; this->ny_ = th.extent(0); - Kokkos::View fspl_view("fspl view", 4 * 4 * this->nx_ * this->ny_); + Kokkos::View fspl_view("fspl view", + 4 * 4 * this->nx_ * this->ny_); CubicSplineInterpolator::set_coefficients(fspl_view); - auto fspl = Rank4View( - fspl_view.data(), 4, 4, this->nx_, this->ny_); + auto fspl = + Rank4View(fspl_view.data(), 4, 4, this->nx_, this->ny_); initialize_fspl(fspl, values); - + Kokkos::View wk_view("wk", 9 * this->nx_ * this->ny_); - auto wk = Rank1View(wk_view.data(), 9 * this->nx_ * this->ny_); + auto wk = + Rank1View(wk_view.data(), 9 * this->nx_ * this->ny_); - solve_spline(x, this->nx_, th, this->ny_, fspl, ibcxmin, bcxmin, ibcxmax, bcxmax, - ibcthmin, bcthmin, ibcthmax, bcthmax, wk); + solve_spline(x, this->nx_, th, this->ny_, fspl, ibcxmin, bcxmin, ibcxmax, + bcxmax, ibcthmin, bcthmin, ibcthmax, bcthmax, wk); this->fspl_ = fspl; } template ExplicitBiCubicSplineInterpolator:: - ExplicitBiCubicSplineInterpolator(Rank1View x, // size: inx - Rank1View th, // size: inth - Rank1View values): ExplicitBiCubicSplineInterpolator( - x, th, values, 0, {}, 0, {}, 0, {}, 0, {}){ // Delegates to primary constructor - std::cout << "Not a knot boundary condition is applied by default" << std::endl; + ExplicitBiCubicSplineInterpolator( + Rank1View x, // size: inx + Rank1View th, // size: inth + Rank1View values) + : ExplicitBiCubicSplineInterpolator( + x, th, values, 0, {}, 0, {}, 0, {}, 0, + {}) { // Delegates to primary constructor + std::cout << "Not a knot boundary condition is applied by default" + << std::endl; } template @@ -1735,15 +1739,15 @@ void ExplicitBiCubicSplineInterpolator::evaluate( } template -void ExplicitBiCubicSplineInterpolator::evaluate(Rank1View xvec, - Rank1View yvec, Rank2View fval) { +void ExplicitBiCubicSplineInterpolator::evaluate( + Rank1View xvec, Rank1View yvec, + Rank2View fval) { LO ict_arr[10] = {1, 0, 0, 0, 0, 0, 0, 0, 0, 0}; Kokkos::View ict("select", 10); Kokkos::parallel_for( Kokkos::RangePolicy(0, ict.size()), KOKKOS_LAMBDA(const LO i) { ict(i) = ict_arr[i]; }); evaluate(ict, xvec, yvec, fval); - } template @@ -1766,15 +1770,15 @@ void CompactBiCubicSplineInterpolator::evaluate( } template -void CompactBiCubicSplineInterpolator::evaluate(Rank1View xvec, - Rank1View yvec, Rank2View fval) { +void CompactBiCubicSplineInterpolator::evaluate( + Rank1View xvec, Rank1View yvec, + Rank2View fval) { LO ict_arr[10] = {1, 0, 0, 0, 0, 0, 0, 0, 0, 0}; Kokkos::View ict("select", 10); Kokkos::parallel_for( Kokkos::RangePolicy(0, ict.size()), KOKKOS_LAMBDA(const LO i) { ict(i) = ict_arr[i]; }); evaluate(ict, xvec, yvec, fval); - } template @@ -2067,55 +2071,59 @@ CompactBiCubicSplineInterpolator:: template void CompactBiCubicSplineInterpolator::initialize_fspl( - Rank3View fspl, Rank1View values) { + Rank3View fspl, Rank1View values) { LO ny = this->ny_; Kokkos::parallel_for( Kokkos::MDRangePolicy>({0, 0}, {ny, this->nx_}), KOKKOS_LAMBDA(const LO ith, const LO ix) { fspl(0, ix, ith) = values(ix * ny + ith); }); - } - +} template -CompactBiCubicSplineInterpolator::CompactBiCubicSplineInterpolator(Rank1View x, - Rank1View y, - Rank1View values, LO ibcxmin, - Rank1View bcxmin, LO ibcxmax, - Rank1View bcxmax, LO ibcymin, - Rank1View bcymin, LO ibcymax, - Rank1View bcymax) { - this->x_ = x; // Store the x-coordinates - this->y_ = y; // Store the y-coordinates +CompactBiCubicSplineInterpolator:: + CompactBiCubicSplineInterpolator( + Rank1View x, Rank1View y, + Rank1View values, LO ibcxmin, + Rank1View bcxmin, LO ibcxmax, + Rank1View bcxmax, LO ibcymin, + Rank1View bcymin, LO ibcymax, + Rank1View bcymax) { + this->x_ = x; // Store the x-coordinates + this->y_ = y; // Store the y-coordinates this->nx_ = x.extent(0); // Store the number of x-coordinates this->ny_ = y.extent(0); // Store the number of y-coordinates - Kokkos::View fspl_view("fspl view", 4 * this->nx_ * this->ny_); + Kokkos::View fspl_view("fspl view", + 4 * this->nx_ * this->ny_); CubicSplineInterpolator::set_coefficients(fspl_view); - auto fspl = Rank3View( - fspl_view.data(), 4, this->nx_, this->ny_); + auto fspl = + Rank3View(fspl_view.data(), 4, this->nx_, this->ny_); // Kokkos::parallel_for( // Kokkos::MDRangePolicy>({0, 0}, {this->ny_, this->nx_}), // KOKKOS_LAMBDA(const int ith, const int ix) { // fspl(0, ix, ith) = values(ix * this->ny_ + ith); // }); initialize_fspl(fspl, values); - + Kokkos::View wk_view("wk", 9 * this->nx_ * this->ny_); - auto wk = Rank1View(wk_view.data(), 9 * this->nx_ * this->ny_); + auto wk = + Rank1View(wk_view.data(), 9 * this->nx_ * this->ny_); - solve_spline(x, this->nx_, y, this->ny_, fspl, ibcxmin, bcxmin, ibcxmax, bcxmax, ibcymin, - bcymin, ibcymax, bcymax, wk); + solve_spline(x, this->nx_, y, this->ny_, fspl, ibcxmin, bcxmin, ibcxmax, + bcxmax, ibcymin, bcymin, ibcymax, bcymax, wk); this->f_ = fspl; // Store the spline coefficients } template CompactBiCubicSplineInterpolator:: - CompactBiCubicSplineInterpolator(Rank1View x, // size: inx - Rank1View y, // size: inth - Rank1View values): CompactBiCubicSplineInterpolator( - x, y, values, 0, {}, 0, {}, 0, {}, 0, {}){ // Delegates to primary constructor - std::cout << "Not a knot boundary condition is applied by default" << std::endl; + CompactBiCubicSplineInterpolator(Rank1View x, // size: inx + Rank1View y, // size: inth + Rank1View values) + : CompactBiCubicSplineInterpolator(x, y, values, 0, {}, 0, {}, 0, {}, 0, + {}) { // Delegates to primary constructor + std::cout << "Not a knot boundary condition is applied by default" + << std::endl; } template diff --git a/test/test_spline_interpolator.cpp b/test/test_spline_interpolator.cpp index 29e3d27ac..b97666adb 100644 --- a/test/test_spline_interpolator.cpp +++ b/test/test_spline_interpolator.cpp @@ -1,8 +1,8 @@ -#include -#include #include "mdspan/mdspan.hpp" #include "pcms.h" #include +#include +#include #include #include @@ -10,29 +10,6 @@ using namespace pcms; using TestMemorySpace = Kokkos::DefaultExecutionSpace; - -void print_4dmdspan( - const Rank4View &span) { - Kokkos::parallel_for( - Kokkos::MDRangePolicy>({0, 0, 0, 0}, - {span.extent(0), span.extent(1), - span.extent(2), span.extent(3)}), - KOKKOS_LAMBDA(int i, int j, int k, int l) { - printf("span(%d, %d, %d, %d) = %f\n", i, j, k, l, span(i, j, k, l)); - }); -} - -void print_3dmdspan( - const Rank3View &span) { - Kokkos::parallel_for( - Kokkos::MDRangePolicy>({0, 0, 0}, - {span.extent(0), span.extent(1), - span.extent(2)}), - KOKKOS_LAMBDA(int i, int j, int k) { - printf("span(%d, %d, %d) = %f\n", i, j, k, span(i, j, k)); - }); -} - bool are_equal(double a, double b, double tolerance = 1e-7) { return std::abs(a - b) < tolerance; } @@ -175,62 +152,38 @@ void reset_2dspan(Rank2View span) { } void dotest1(int ns, Rank1View x, - Rank1View f, - Rank1View fd, - Rank2View fspl, - Rank2View fspp, - Rank2View fs2, int nt, + Rank1View f, int nt, Rank1View xt, Rank1View ft, - Rank2View xpkg, - Rank2View testa1, - Rank2View testa2, - Rank2View testa3, - Rank1View wk, - Rank1View wk2, Kokkos::View res_1d) { using std::data; using std::size; - Kokkos::parallel_for( - Kokkos::RangePolicy(0, ns), KOKKOS_LAMBDA(const int i) { - fspl(0, i) = f(i); - fspp(0, i) = f(i); - fs2(0, i) = f(i); - }); - - Kokkos::View fspl4_view("fspl4_view", 40); - auto fspl4 = Rank2View(fspl4_view.data(), 4, 10); + Kokkos::View splinv_view("splinv_view", 3 * nt); + auto splinv = Rank2View(splinv_view.data(), nt, 3); + reset_2dspan(splinv); // interpolator.cspline(x, ns, fspl, 1, 1, 1, 1, wk); ExplicitCubicSplineInterpolator explicit_interpolator(x, f, 1, 1, 1, 1); - - int ict_arr[3] = {1, 0, 0}; - Kokkos::View ict("ict", 3); - Kokkos::parallel_for( - Kokkos::RangePolicy(0, ict.size()), - KOKKOS_LAMBDA(const int i) { ict(i) = ict_arr[i]; }); - - Kokkos::View splinv_view("splinv_view", 3000); - auto splinv = Rank2View(splinv_view.data(), 1000, 3); - reset_2dspan(splinv); explicit_interpolator.evaluate(xt, splinv); auto res1 = Rank1View(res_1d.data(), 2); compare(splinv, ft, res1, "cspline"); - reset_2dspan(splinv); + ExplicitCubicSplineInterpolator explicit_interpolator_periodic(x, f, -1, 0, -1, 0); explicit_interpolator_periodic.evaluate(xt, splinv); + auto res2 = Rank1View(res_1d.data() + 2, 2); compare(splinv, ft, res2, "cspline_periodic"); - reset_2dspan(splinv); + CompactCubicSplineInterpolator compact_interpolator( - x, f, 1, 1,1 ,1); + x, f, 1, 1, 1, 1); compact_interpolator.evaluate(xt, splinv); + auto res3 = Rank1View(res_1d.data() + 4, 2); compare(splinv, ft, res3, "compact_cubic"); } @@ -242,51 +195,26 @@ void pspltest1(Kokkos::View res_1d) { // Local arrays Kokkos::View zdum_view("zdum_view", 1000); - Kokkos::View testa1_view("testa1_view", 1000); - Kokkos::View testa2_view("testa2_view", 1000); - Kokkos::View testa3_view("testa3_view", 1000); Kokkos::View xtest_view("xtest_view", 1000); Kokkos::View ftest_view("ftest_view", 1000); Kokkos::View x_view("x_view", 10); Kokkos::View zcos_view("zcos_view", 10); Kokkos::View z2sin_view("z2sin_view", 10); - Kokkos::View xpkg_view("xpkg_view", 10 * 4); - Kokkos::View fs_view("fs_view", 40); - Kokkos::View fsp_view("fsp_view", 40); - Kokkos::View fs2_view("fs2_view", 20); // Prepare test data tset(1000, xtest_view, ftest_view, zdum_view, zero - 0.1, pi2 + 0.1); tset(inum, x_view, z2sin_view, zcos_view, zero, pi2); - Kokkos::parallel_for( - Kokkos::RangePolicy(0, inum), - KOKKOS_LAMBDA(const int ix) { zcos_view(ix) = std::cos(x_view(ix)); }); - - auto zdum = Rank1View(zdum_view.data(), 10); - - auto wk2_view = - Kokkos::View(zdum_view.data(), 1000); - auto wk2 = Rank1View(wk2_view.data(), 10); - - auto testa1 = Rank2View(testa1_view.data(), 1000, 3); - auto testa2 = Rank2View(testa2_view.data(), 1000, 3); - auto testa3 = Rank2View(testa3_view.data(), 1000, 3); auto x = Rank1View(x_view.data(), x_view.size()); - auto zcos = - Rank1View(zcos_view.data(), zcos_view.size()); + auto z2sin = Rank1View(z2sin_view.data(), z2sin_view.size()); - auto fs = Rank2View(fs_view.data(), 4, 10); - auto fsp = Rank2View(fsp_view.data(), 4, 10); - auto fs2 = Rank2View(fs2_view.data(), 2, 10); - auto xpkg = Rank2View(xpkg_view.data(), 10, 4); + auto xtest = Rank1View(xtest_view.data(), 1000); auto ftest = Rank1View(ftest_view.data(), 1000); // Call test function - dotest1(inum, x, z2sin, zcos, fs, fsp, fs2, 1000, xtest, ftest, xpkg, testa1, - testa2, testa3, zdum, wk2, res_1d); + dotest1(inum, x, z2sin, 1000, xtest, ftest, res_1d); } void dotest2(Rank1View x, @@ -295,8 +223,6 @@ void dotest2(Rank1View x, Rank1View fth, Rank1View dfth, int nth, Rank4View f, - Rank3View fh, - Rank2View flin, Rank1View bcx1, Rank1View bcx2, Rank1View bcth1, @@ -306,42 +232,21 @@ void dotest2(Rank1View x, Rank1View thtest, Rank1View fthtest, int ntest, Kokkos::View res_2d) { - Kokkos::parallel_for( - Kokkos::MDRangePolicy>({0, 0}, {nth, nx}), - KOKKOS_LAMBDA(const int ith, const int ix) { - flin(ix, ith) = f(0, 0, ix, ith); // f - fh(0, ix, ith) = f(0, 0, ix, ith); // f - fh(1, ix, ith) = 2.0 * f(0, 0, ix, ith); // df/dx - fh(2, ix, ith) = fx(ix) * dfth(ith); // df/dy - fh(3, ix, ith) = 2.0 * fx(ix) * dfth(ith); // d2f/dxdy - }); - - Kokkos::View values_view("f_vec", nth * nx); + + Kokkos::View values_view("values_view", nth * nx); Kokkos::parallel_for( Kokkos::MDRangePolicy>({0, 0}, {nth, nx}), KOKKOS_LAMBDA(const int ith, const int ix) { values_view(ix * nth + ith) = f(0, 0, ix, ith); }); + auto values = + Rank1View(values_view.data(), nth * nx); - auto values = Rank1View(values_view.data(), nth * nx); - - int nbc = 1; - Kokkos::View wk_vec("wk_vec", 900); - auto wk = Rank1View(wk_vec.data(), 900); bset(fx, nx, fth, nth, bcx1, bcx2, bcth1, bcth2); - - ExplicitBiCubicSplineInterpolator - explicit_interpolator(x, th, values, nbc, bcx1, nbc, bcx2, nbc, bcth1, - nbc, bcth2); Kokkos::View splinv_view("splinv_view", 400000); auto splinv = Rank2View(splinv_view.data(), 40000, 10); reset_2dspan(splinv); - int isel_arr[10] = {1, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - Kokkos::View isel("isel", 10); - Kokkos::parallel_for( - Kokkos::RangePolicy(0, isel.size()), - KOKKOS_LAMBDA(const int i) { isel(i) = isel_arr[i]; }); Kokkos::View xtest_grid_view("xtest_grid_view", 40000); @@ -357,17 +262,19 @@ void dotest2(Rank1View x, Rank1View(splinv_gt_view.data(), 40000); generate_gt_2d(splinv_gt, fxtest, fthtest, ntest); - // TODO: evaluate function raise memeory acess violation + ExplicitBiCubicSplineInterpolator + explicit_interpolator(x, th, values, 1, bcx1, 1, bcx2, 1, bcth1, 1, + bcth2); explicit_interpolator.evaluate(xtest_grid, thtest_grid, splinv); auto res1 = Rank1View(res_2d.data(), 2); compare_2d(splinv, splinv_gt, res1, "bcspline"); - reset_2dspan(splinv); + CompactBiCubicSplineInterpolator - compact_interpolator(x, th, values, nbc, bcx1, nbc, bcx2, nbc, bcth1, - nbc, bcth2); + compact_interpolator(x, th, values, 1, bcx1, 1, bcx2, 1, bcth1, 1, bcth2); compact_interpolator.evaluate(xtest_grid, thtest_grid, splinv); + auto res2 = Rank1View(res_2d.data() + 2, 2); compare_2d(splinv, splinv_gt, res2, "mkbicub"); @@ -391,28 +298,18 @@ void pspltest2(Kokkos::View res_2d) { Kokkos::View stest_view("stest_view", 200); Kokkos::View ctest_view("ctest_view", 200); Kokkos::View f1_view("f1_view", 1600); - Kokkos::View f2_view("f2_view", 6400); - Kokkos::View f4_view("f4_view", 4 * 4 * 40 * 40); Kokkos::View bcx1_view("bcx1_view", 40); Kokkos::View bcx2_view("bcx2_view", 40); Kokkos::View bcth1_view("bcth1_view", 40); Kokkos::View bcth2_view("bcth2_view", 40); - Kokkos::View fh_view("fh_view", 400); - Kokkos::View flin_view("flin_view", 100); xset(10, x1_view, ex1_view, zero, one); - // xset(20, x2_view, ex2_view, zero, one); - // xset(40, x4_view, ex4_view, zero, one); xset(200, xtest_view, extest_view, zero, one); tset(10, t1_view, st1_view, ct1_view, zero, pi2); - // tset(20, t2_view, st2_view, ct2_view, zero, pi2); - // tset(40, t4_view, st4_view, ct4_view, zero, pi2); tset(200, ttest_view, stest_view, ctest_view, zero, pi2); ffset(10, ex1_view, st1_view, f1_view); - // ffset(20, ex2_view, st2_view, f2_view); - // ffset(40, ex4_view, st4_view, f4_view); auto x1 = Rank1View(x1_view.data(), x1_view.size()); auto ex1 = @@ -424,10 +321,6 @@ void pspltest2(Kokkos::View res_2d) { Rank1View(ct1_view.data(), ct1_view.size()); auto f1 = Rank4View(f1_view.data(), Kokkos::extents{4, 4, 10, 10}); - auto flin = Rank2View(flin_view.data(), 10, 10); - - auto fh = Rank3View(fh_view.data(), 4, 10, 10); - auto bcx1 = Rank1View(bcx1_view.data(), bcx1_view.size()); auto bcx2 = @@ -446,16 +339,8 @@ void pspltest2(Kokkos::View res_2d) { auto stest = Rank1View(stest_view.data(), stest_view.size()); - dotest2(x1, ex1, 10, t1, st1, ct1, 10, f1, fh, flin, bcx1, bcx2, bcth1, bcth2, - xtest, extest, ttest, stest, 200, res_2d); - - // dotest2(x2,ex2,20,t2,st2,ct2,20,f2,fh,flin, - // bcx1,bcx2,bcth1,bcth2, - // xtest,extest,ttest,stest,200); - - // dotest2(x4,ex4,40,t4,st4,ct4,40,f4,fh,flin, - // bcx1,bcx2,bcth1,bcth2, - // xtest,extest,ttest,stest,200); + dotest2(x1, ex1, 10, t1, st1, ct1, 10, f1, bcx1, bcx2, bcth1, bcth2, xtest, + extest, ttest, stest, 200, res_2d); } TEST_CASE("test_cubic_spline_interpolator") { @@ -465,8 +350,8 @@ TEST_CASE("test_cubic_spline_interpolator") { Kokkos::Timer timer; { Kokkos::View res_1d("res_1d", 6); - double gt_1d[6] = - {6.7572E-04, 6.6529E-04, 6.8669E-04, 6.7622E-04, 6.7572E-04, 6.6529E-04}; + double gt_1d[6] = {6.7572E-04, 6.6529E-04, 6.8669E-04, + 6.7622E-04, 6.7572E-04, 6.6529E-04}; pspltest1(res_1d); for (int i = 0; i < 6; ++i) { REQUIRE(are_equal(res_1d(i), gt_1d[i])); From e76d9266867745ffa32c1f7b6cd52bf63e0589c8 Mon Sep 17 00:00:00 2001 From: Sichao25 Date: Fri, 1 Aug 2025 22:01:53 -0400 Subject: [PATCH 05/18] remove base class --- src/pcms/interpolator/spline_interpolator.hpp | 500 +++++++----------- 1 file changed, 186 insertions(+), 314 deletions(-) diff --git a/src/pcms/interpolator/spline_interpolator.hpp b/src/pcms/interpolator/spline_interpolator.hpp index 85d4a2714..8cd7a1311 100644 --- a/src/pcms/interpolator/spline_interpolator.hpp +++ b/src/pcms/interpolator/spline_interpolator.hpp @@ -54,58 +54,38 @@ T get_element_from_span(Rank1View span, LO index) { // TODO: better documentation // TODO: add more checks/assetions for input parameters -template class CubicSplineInterpolator { + +template +class ExplicitCubicSplineInterpolator{ private: Kokkos::View coefficients_; - public: - CubicSplineInterpolator() = default; using execution_space = typename MemorySpace::execution_space; using member_type = typename Kokkos::TeamPolicy::member_type; + ExplicitCubicSplineInterpolator() = default; + + ExplicitCubicSplineInterpolator(Rank1View x, + Rank1View values, + const LO &ibcxmin, const T &bcxmin, + const LO &ibcxmax, const T &bcxmax); + ExplicitCubicSplineInterpolator(Rank1View x, + Rank1View values); + Rank1View x_; LO nx_; + Rank2View fspl_; + Kokkos::View get_coefficients(); void set_coefficients(Kokkos::View coefficients); static void sanity_check(Rank1View x, const T &ztol); - void initialize_fspl(Rank2View fspl, - Rank1View values); static KOKKOS_INLINE_FUNCTION void range_check(T &xget, T &zxget, Rank1View x, const LO &nx, LO &ier); - static KOKKOS_FUNCTION void v_spline(const LO &k_bc1, const LO &k_bcn, - const LO &n, Rank1View x, - Rank2View f, - Rank1View wk); - - static void correction_detect(Rank1View bcmin, LO &ibcmin, - LO &iflg2, LO &nx); - -}; // end of cubic spline class - -template -class ExplicitCubicSplineInterpolator - : public CubicSplineInterpolator { -public: - using typename CubicSplineInterpolator::execution_space; - using member_type = typename Kokkos::TeamPolicy::member_type; - ExplicitCubicSplineInterpolator() = default; - ExplicitCubicSplineInterpolator(Rank1View x, const LO &nx, - Rank2View fspl, - const LO &ibcxmin, const T &bcxmin, - const LO &ibcxmax, const T &bcxmax, - Rank1View wk); - ExplicitCubicSplineInterpolator(Rank1View x, - Rank1View values, - const LO &ibcxmin, const T &bcxmin, - const LO &ibcxmax, const T &bcxmax); - ExplicitCubicSplineInterpolator(Rank1View x, - Rank1View values); - Rank2View fspl_; - void setup(Rank1View x, const LO &nx, - Rank2View fspl, const LO &ibcxmin, const T &bcxmin, - const LO &ibcxmax, const T &bcxmax, Rank1View wk); + void setup( + Rank1View x, const LO &nx, Rank1View values, + const LO &ibcxmin, const T &bcxmin, const LO &ibcxmax, const T &bcxmax); static KOKKOS_FUNCTION void solve_spline(Rank1View x, const LO &nx, Rank2View fspl, @@ -136,16 +116,9 @@ template class CompactCubicSplineInterpolator : public ExplicitCubicSplineInterpolator { public: - using typename CubicSplineInterpolator::execution_space; + using typename ExplicitCubicSplineInterpolator::execution_space; using member_type = typename Kokkos::TeamPolicy::member_type; - Rank2View fs2_; CompactCubicSplineInterpolator() = default; - CompactCubicSplineInterpolator(Rank1View x, const LO &nx, - Rank2View fspl, - Rank2View fspl4, - const LO &ibcxmin, const T &bcxmin, - const LO &ibcxmax, const T &bcxmax, - Rank1View wk); CompactCubicSplineInterpolator(Rank1View x, Rank1View values, const LO &ibcxmin, const T &bcxmin, @@ -153,9 +126,9 @@ class CompactCubicSplineInterpolator CompactCubicSplineInterpolator(Rank1View x, Rank1View values); void setup(Rank1View x, const LO &nx, - Rank2View fspl, Rank2View fspl4, + Rank1View values, const LO &ibcxmin, const T &bcxmin, const LO &ibcxmax, - const T &bcxmax, Rank1View wk); + const T &bcxmax); static KOKKOS_FUNCTION void solve_spline(Rank1View x, const LO &nx, Rank2View fspl, Rank2View fspl4, @@ -186,7 +159,7 @@ template class ExplicitBiCubicSplineInterpolator : public ExplicitCubicSplineInterpolator { public: - using typename CubicSplineInterpolator::execution_space; + using typename ExplicitCubicSplineInterpolator::execution_space; using member_type = typename Kokkos::TeamPolicy::member_type; Rank4View fspl_; @@ -195,23 +168,6 @@ class ExplicitBiCubicSplineInterpolator ExplicitBiCubicSplineInterpolator() = default; - ExplicitBiCubicSplineInterpolator( - Rank1View x, // size: inx - LO inx, Rank1View th, // size: inth - LO inth, Rank4View fspl, // [4, 4, inx, inth] - LO ibcxmin, - Rank1View bcxmin, // size: inth (used if ibcxmin = 1 or 2) - LO ibcxmax, - Rank1View bcxmax, // size: inth (used if ibcxmax = 1 or 2) - LO ibcthmin, - Rank1View - bcthmin, // size: inx (used if ibcthmin = 1 or 2) - LO ibcthmax, - Rank1View - bcthmax, // size: inx (used if ibcthmax = 1 or 2) - Rank1View wk // size: nwk - ); - ExplicitBiCubicSplineInterpolator( Rank1View x, // size: inx Rank1View th, // size: inth @@ -227,9 +183,26 @@ class ExplicitBiCubicSplineInterpolator ExplicitBiCubicSplineInterpolator(Rank1View x, // size: inx Rank1View th, // size: inth Rank1View values); + + static void correction_detect(Rank1View bcmin, LO &ibcmin, + LO &iflg2, LO &nx); - void initialize_fspl(Rank4View fspl, - Rank1View values); + void setup( + Rank1View x, // size: inx + Rank1View th, // size: inth + Rank1View values, LO ibcxmin, + Rank1View + bcxmin, // size: inth (used if ibcxmin = 1 or 2) + LO ibcxmax, + Rank1View + bcxmax, // size: inth (used if ibcxmax = 1 or 2) + LO ibcthmin, + Rank1View + bcthmin, // size: inx (used if ibcthmin = 1 or 2) + LO ibcthmax, + Rank1View + bcthmax // size: inx (used if ibcthmax = 1 or 2) + ); static void solve_spline( Rank1View x, // size: inx @@ -280,9 +253,9 @@ class ExplicitBiCubicSplineInterpolator template class CompactBiCubicSplineInterpolator - : public CompactCubicSplineInterpolator { + : public ExplicitBiCubicSplineInterpolator { public: - using typename CubicSplineInterpolator::execution_space; + using typename ExplicitCubicSplineInterpolator::execution_space; using member_type = typename Kokkos::TeamPolicy::member_type; Rank3View f_; Rank1View y_; @@ -290,15 +263,6 @@ class CompactBiCubicSplineInterpolator CompactBiCubicSplineInterpolator() = default; - CompactBiCubicSplineInterpolator(Rank1View x, LO nx, - Rank1View y, LO ny, - Rank3View f, LO ibcxmin, - Rank1View bcxmin, LO ibcxmax, - Rank1View bcxmax, LO ibcymin, - Rank1View bcymin, LO ibcymax, - Rank1View bcymax, - Rank1View wk); - CompactBiCubicSplineInterpolator(Rank1View x, Rank1View y, Rank1View values, LO ibcxmin, @@ -311,8 +275,13 @@ class CompactBiCubicSplineInterpolator Rank1View y, Rank1View values); - void initialize_fspl(Rank3View fspl, - Rank1View values); + void setup( + Rank1View x, Rank1View y, + Rank1View values, LO ibcxmin, + Rank1View bcxmin, LO ibcxmax, + Rank1View bcxmax, LO ibcymin, + Rank1View bcymin, LO ibcymax, + Rank1View bcymax); static void solve_spline(Rank1View x, LO nx, Rank1View y, LO ny, @@ -350,18 +319,18 @@ class CompactBiCubicSplineInterpolator template Kokkos::View -CubicSplineInterpolator::get_coefficients() { +ExplicitCubicSplineInterpolator::get_coefficients() { return coefficients_; } template -void CubicSplineInterpolator::set_coefficients( +void ExplicitCubicSplineInterpolator::set_coefficients( Kokkos::View coefficients) { coefficients_ = coefficients; } template -void CubicSplineInterpolator::correction_detect( +void ExplicitBiCubicSplineInterpolator::correction_detect( Rank1View bcmin, LO &ibcmin, LO &iflg2, LO &nx) { if (ibcmin == 1 || ibcmin == 2) { Kokkos::parallel_reduce( @@ -376,7 +345,7 @@ void CubicSplineInterpolator::correction_detect( } template -void CubicSplineInterpolator::sanity_check( +void ExplicitCubicSplineInterpolator::sanity_check( Rank1View x, const T &ztol) { LO inx = static_cast(x.extent(0)); @@ -396,14 +365,6 @@ void CubicSplineInterpolator::sanity_check( }); } -template -void CubicSplineInterpolator::initialize_fspl( - Rank2View fspl, Rank1View values) { - Kokkos::parallel_for( - "set_coefficients", Kokkos::RangePolicy(0, this->nx_), - KOKKOS_LAMBDA(const LO i) { fspl(0, i) = values(i); }); -} - template ExplicitCubicSplineInterpolator:: ExplicitCubicSplineInterpolator(Rank1View x, @@ -415,22 +376,12 @@ ExplicitCubicSplineInterpolator:: ibc_check(ibcxmin, "1d spline", "xmin", -1, 7); if (ibcxmin >= 0) ibc_check(ibcxmax, "1d spline", "xmax", 0, 7); - CubicSplineInterpolator::sanity_check(x, 1.0e-3); + ExplicitCubicSplineInterpolator::sanity_check(x, 1.0e-3); this->nx_ = x.extent(0); this->x_ = x; - Kokkos::View fspl_view("coefficients", 4 * this->nx_); - CubicSplineInterpolator::set_coefficients(fspl_view); - auto fspl = Rank2View(fspl_view.data(), 4, this->nx_); - CubicSplineInterpolator::initialize_fspl(fspl, values); - - Kokkos::View wk_view("working space", 10); - auto wk = Rank1View(wk_view.data(), 10); - - setup(x, this->nx_, fspl, ibcxmin, bcxmin, ibcxmax, bcxmax, wk); - - this->fspl_ = fspl; + setup(x, this->nx_, values, ibcxmin, bcxmin, ibcxmax, bcxmax); } template @@ -443,29 +394,19 @@ ExplicitCubicSplineInterpolator:: << std::endl; } -template -ExplicitCubicSplineInterpolator:: - ExplicitCubicSplineInterpolator(Rank1View x, const LO &nx, - Rank2View fspl, - const LO &ibcxmin, const T &bcxmin, - const LO &ibcxmax, const T &bcxmax, - Rank1View wk) { - PCMS_ALWAYS_ASSERT(x.extent(0) >= 2); - ibc_check(ibcxmin, "1d spline", "xmin", -1, 7); - if (ibcxmin >= 0) - ibc_check(ibcxmax, "1d spline", "xmax", 0, 7); - CubicSplineInterpolator::sanity_check(x, 1.0e-3); - this->nx_ = x.extent(0); - this->x_ = x; - setup(x, nx, fspl, ibcxmin, bcxmin, ibcxmax, bcxmax, wk); - this->fspl_ = fspl; -} - template void ExplicitCubicSplineInterpolator::setup( - Rank1View x, const LO &nx, Rank2View fspl, - const LO &ibcxmin, const T &bcxmin, const LO &ibcxmax, const T &bcxmax, - Rank1View wk) { + Rank1View x, const LO &nx, Rank1View values, + const LO &ibcxmin, const T &bcxmin, const LO &ibcxmax, const T &bcxmax) { + Kokkos::View fspl_view("coefficients", 4 * nx); + ExplicitCubicSplineInterpolator::set_coefficients(fspl_view); + auto fspl = Rank2View(fspl_view.data(), 4, nx); + Kokkos::parallel_for( + "set_coefficients", Kokkos::RangePolicy(0, this->nx_), + KOKKOS_LAMBDA(const LO i) { fspl(0, i) = values(i); }); + + Kokkos::View wk_view("working space", 10); + auto wk = Rank1View(wk_view.data(), 10); // TODO: pass member type to solve_spline Kokkos::parallel_for( "explicit cubic", Kokkos::TeamPolicy(1, Kokkos::AUTO), @@ -474,49 +415,22 @@ void ExplicitCubicSplineInterpolator::setup( solve_spline(x, nx, fspl, ibcxmin, bcxmin, ibcxmax, bcxmax, wk); }); }); -} - -template -CompactCubicSplineInterpolator::CompactCubicSplineInterpolator( - Rank1View x, const LO &nx, Rank2View fspl, - Rank2View fspl4, const LO &ibcxmin, const T &bcxmin, - const LO &ibcxmax, const T &bcxmax, Rank1View wk) { - this->nx_ = x.extent(0); - ibc_check(ibcxmin, "1d spline", "xmin", -1, 7); - if (ibcxmin >= 0) - ibc_check(ibcxmax, "1d spline", "xmax", 0, 7); - CubicSplineInterpolator::sanity_check(x, 1.0e-3); - this->x_ = x; - setup(x, nx, fspl, fspl4, ibcxmin, bcxmin, ibcxmax, bcxmax, wk); - this->fs2_ = fspl; + this->fspl_ = fspl; } template CompactCubicSplineInterpolator::CompactCubicSplineInterpolator( Rank1View x, Rank1View values, - const LO &ibcxmin, const T &bcxmin, const LO &ibcxmax, const T &bcxmax) { - PCMS_ALWAYS_ASSERT(x.extent(0) >= 2); + const LO &ibcxmin, const T &bcxmin, + const LO &ibcxmax, const T &bcxmax) { ibc_check(ibcxmin, "1d spline", "xmin", -1, 7); if (ibcxmin >= 0) ibc_check(ibcxmax, "1d spline", "xmax", 0, 7); - CubicSplineInterpolator::sanity_check(x, 1.0e-3); - this->nx_ = x.extent(0); + ExplicitCubicSplineInterpolator::sanity_check(x, 1.0e-3); this->x_ = x; + this->nx_ = x.extent(0); + setup(x, this->nx_, values, ibcxmin, bcxmin, ibcxmax, bcxmax); - Kokkos::View fspl_view("coefficients", 2 * this->nx_); - CubicSplineInterpolator::set_coefficients(fspl_view); - auto fspl = Rank2View(fspl_view.data(), 2, this->nx_); - CubicSplineInterpolator::initialize_fspl(fspl, values); - - Kokkos::View fspl4_view("explicit coefficients", - 4 * this->nx_); - auto fspl4 = Rank2View(fspl4_view.data(), 4, this->nx_); - Kokkos::View wk_view("working space", 10); - auto wk = Rank1View(wk_view.data(), 10); - - setup(x, this->nx_, fspl, fspl4, ibcxmin, bcxmin, ibcxmax, bcxmax, wk); - - this->fs2_ = fspl; } template @@ -530,9 +444,22 @@ CompactCubicSplineInterpolator::CompactCubicSplineInterpolator( template void CompactCubicSplineInterpolator::setup( - Rank1View x, const LO &nx, Rank2View fspl, - Rank2View fspl4, const LO &ibcxmin, const T &bcxmin, - const LO &ibcxmax, const T &bcxmax, Rank1View wk) { + Rank1View x, const LO &nx, Rank1View values, + const LO &ibcxmin, const T &bcxmin, + const LO &ibcxmax, const T &bcxmax) { + Kokkos::View fspl_view("coefficients", 2 * this->nx_); + ExplicitCubicSplineInterpolator::set_coefficients(fspl_view); + auto fspl = Rank2View(fspl_view.data(), 2, this->nx_); + Kokkos::parallel_for( + "set_coefficients", Kokkos::RangePolicy(0, this->nx_), + KOKKOS_LAMBDA(const LO i) { fspl(0, i) = values(i); }); + + Kokkos::View fspl4_view("explicit coefficients", + 4 * this->nx_); + auto fspl4 = Rank2View(fspl4_view.data(), 4, this->nx_); + Kokkos::View wk_view("working space", 10); + auto wk = Rank1View(wk_view.data(), 10); + Kokkos::parallel_for( "compact cubic", Kokkos::TeamPolicy(1, Kokkos::AUTO), KOKKOS_LAMBDA(const member_type &team_member) { @@ -541,39 +468,11 @@ void CompactCubicSplineInterpolator::setup( wk); }); }); + this->fspl_ = fspl; } template -KOKKOS_FUNCTION void -ExplicitCubicSplineInterpolator::solve_spline( - Rank1View x, const LO &nx, Rank2View fspl, - const LO &ibcxmin, const T &bcxmin, const LO &ibcxmax, const T &bcxmax, - Rank1View wk) { - - T half = 0.5; - T sixth = 0.166666666666666667; - - if (ibcxmin == 1) { - fspl(1, 0) = bcxmin; - } else if (ibcxmin == 2) { - fspl(2, 0) = bcxmin; - } - - if (ibcxmax == 1) { - fspl(1, nx - 1) = bcxmax; - } else if (ibcxmax == 2) { - fspl(2, nx - 1) = bcxmax; - } - CubicSplineInterpolator::v_spline(ibcxmin, ibcxmax, nx, x, - fspl, wk); - for (LO i = 0; i < nx; ++i) { - fspl(2, i) = half * fspl(2, i); - fspl(3, i) = sixth * fspl(3, i); - } -} - -template -KOKKOS_FUNCTION void CubicSplineInterpolator::v_spline( +KOKKOS_FUNCTION void v_spline( const LO &k_bc1, const LO &k_bcn, const LO &n, Rank1View x, Rank2View f, Rank1View wk) { LO i_bc1 = k_bc1; @@ -1041,9 +940,37 @@ KOKKOS_FUNCTION void CubicSplineInterpolator::v_spline( } } // v_spline +template +KOKKOS_FUNCTION void +ExplicitCubicSplineInterpolator::solve_spline( + Rank1View x, const LO &nx, Rank2View fspl, + const LO &ibcxmin, const T &bcxmin, const LO &ibcxmax, const T &bcxmax, + Rank1View wk) { + + T half = 0.5; + T sixth = 0.166666666666666667; + + if (ibcxmin == 1) { + fspl(1, 0) = bcxmin; + } else if (ibcxmin == 2) { + fspl(2, 0) = bcxmin; + } + + if (ibcxmax == 1) { + fspl(1, nx - 1) = bcxmax; + } else if (ibcxmax == 2) { + fspl(2, nx - 1) = bcxmax; + } + v_spline(ibcxmin, ibcxmax, nx, x, fspl, wk); + for (LO i = 0; i < nx; ++i) { + fspl(2, i) = half * fspl(2, i); + fspl(3, i) = sixth * fspl(3, i); + } +} + template KOKKOS_INLINE_FUNCTION void -CubicSplineInterpolator::range_check( +ExplicitCubicSplineInterpolator::range_check( T &xget, T &zxget, Rank1View x, const LO &nx, LO &ier) { if (xget < x[0] || xget > x[nx - 1]) { T zxtol = 4.0e-7 * std::max(std::abs(x[0]), std::abs(x[nx - 1])); @@ -1122,7 +1049,7 @@ ExplicitCubicSplineInterpolator::lookup( T zxget = xget; // Range check - CubicSplineInterpolator::range_check(xget, zxget, x, nx, ier); + ExplicitCubicSplineInterpolator::range_check(xget, zxget, x, nx, ier); LO ii = static_cast(nxm * (zxget - x[0]) / (x[nx - 1] - x[0])); i = std::min(nxm - 1, ii); @@ -1195,7 +1122,7 @@ void CompactCubicSplineInterpolator::evaluate( LO ier = 0; auto fval_view = Rank1View(fval.data_handle() + i * ivd, ivd); - eval(xvec(i), selector, fval_view, this->x_, this->nx_, this->fs2_, + eval(xvec(i), selector, fval_view, this->x_, this->nx_, this->fspl_, ier); }); } @@ -1279,7 +1206,7 @@ CompactCubicSplineInterpolator::lookup( T zxget = xget; - CubicSplineInterpolator::range_check(xget, zxget, x, nx, ier); + ExplicitCubicSplineInterpolator::range_check(xget, zxget, x, nx, ier); LO nxm = nx - 1; @@ -1323,10 +1250,9 @@ CompactCubicSplineInterpolator::eval( template ExplicitBiCubicSplineInterpolator:: ExplicitBiCubicSplineInterpolator( - Rank1View x, // size: inx - LO inx, Rank1View th, // size: inth - LO inth, Rank4View fspl, // [4, 4, inx, inth] - LO ibcxmin, + Rank1View x, // size: inx + Rank1View th, // size: inth + Rank1View values, LO ibcxmin, Rank1View bcxmin, // size: inth (used if ibcxmin = 1 or 2) LO ibcxmax, @@ -1337,11 +1263,10 @@ ExplicitBiCubicSplineInterpolator:: bcthmin, // size: inx (used if ibcthmin = 1 or 2) LO ibcthmax, Rank1View - bcthmax, // size: inx (used if ibcthmax = 1 or 2) - Rank1View wk // size: nwk + bcthmax // size: inx (used if ibcthmax = 1 or 2) ) { - PCMS_ALWAYS_ASSERT(inx >= 2); - PCMS_ALWAYS_ASSERT(inth >= 2); + PCMS_ALWAYS_ASSERT(x.extent(0) >= 2); + PCMS_ALWAYS_ASSERT(th.extent(0) >= 2); // Check boundary condition values ibc_check(ibcxmin, "2d spline", "xmin", -1, 7); @@ -1351,33 +1276,20 @@ ExplicitBiCubicSplineInterpolator:: if (ibcthmin >= 0) ibc_check(ibcthmax, "2d spline", "thmax", 0, 7); - CubicSplineInterpolator::sanity_check(x, 1.0e-3); - CubicSplineInterpolator::sanity_check(th, 1.0e-3); + ExplicitCubicSplineInterpolator::sanity_check(x, 1.0e-3); + ExplicitCubicSplineInterpolator::sanity_check(th, 1.0e-3); this->x_ = x; - this->nx_ = inx; + this->nx_ = x.extent(0); this->y_ = th; - this->ny_ = inth; - - solve_spline(x, inx, th, inth, fspl, ibcxmin, bcxmin, ibcxmax, bcxmax, - ibcthmin, bcthmin, ibcthmax, bcthmax, wk); - - fspl_ = fspl; -} + this->ny_ = th.extent(0); -template -void ExplicitBiCubicSplineInterpolator::initialize_fspl( - Rank4View fspl, Rank1View values) { - LO ny = this->ny_; - Kokkos::parallel_for( - Kokkos::MDRangePolicy>({0, 0}, {ny, this->nx_}), - KOKKOS_LAMBDA(const LO ith, const LO ix) { - fspl(0, 0, ix, ith) = values(ix * ny + ith); - }); + setup(x, th, values, ibcxmin, bcxmin, ibcxmax, + bcxmax, ibcthmin, bcthmin, ibcthmax, bcthmax); } template -ExplicitBiCubicSplineInterpolator:: - ExplicitBiCubicSplineInterpolator( +void ExplicitBiCubicSplineInterpolator:: + setup( Rank1View x, // size: inx Rank1View th, // size: inth Rank1View values, LO ibcxmin, @@ -1393,36 +1305,24 @@ ExplicitBiCubicSplineInterpolator:: Rank1View bcthmax // size: inx (used if ibcthmax = 1 or 2) ) { - PCMS_ALWAYS_ASSERT(x.extent(0) >= 2); - PCMS_ALWAYS_ASSERT(th.extent(0) >= 2); - - // Check boundary condition values - ibc_check(ibcxmin, "2d spline", "xmin", -1, 7); - if (ibcxmin >= 0) - ibc_check(ibcxmax, "2d spline", "xmax", 0, 7); - ibc_check(ibcthmin, "2d spline", "thmin", -1, 7); - if (ibcthmin >= 0) - ibc_check(ibcthmax, "2d spline", "thmax", 0, 7); - - CubicSplineInterpolator::sanity_check(x, 1.0e-3); - CubicSplineInterpolator::sanity_check(th, 1.0e-3); - this->x_ = x; - this->nx_ = x.extent(0); - this->y_ = th; - this->ny_ = th.extent(0); - + LO ny = this->ny_; + LO nx = this->nx_; Kokkos::View fspl_view("fspl view", - 4 * 4 * this->nx_ * this->ny_); - CubicSplineInterpolator::set_coefficients(fspl_view); + 4 * 4 * nx * ny); + ExplicitCubicSplineInterpolator::set_coefficients(fspl_view); auto fspl = - Rank4View(fspl_view.data(), 4, 4, this->nx_, this->ny_); - initialize_fspl(fspl, values); + Rank4View(fspl_view.data(), 4, 4, nx, ny); + Kokkos::parallel_for( + Kokkos::MDRangePolicy>({0, 0}, {ny, nx}), + KOKKOS_LAMBDA(const LO ith, const LO ix) { + fspl(0, 0, ix, ith) = values(ix * ny + ith); + }); - Kokkos::View wk_view("wk", 9 * this->nx_ * this->ny_); + Kokkos::View wk_view("wk", 9 * nx * ny); auto wk = - Rank1View(wk_view.data(), 9 * this->nx_ * this->ny_); + Rank1View(wk_view.data(), 9 * nx * ny); - solve_spline(x, this->nx_, th, this->ny_, fspl, ibcxmin, bcxmin, ibcxmax, + solve_spline(x, nx, th, ny, fspl, ibcxmin, bcxmin, ibcxmax, bcxmax, ibcthmin, bcthmin, ibcthmax, bcthmax, wk); this->fspl_ = fspl; @@ -1465,9 +1365,9 @@ void ExplicitBiCubicSplineInterpolator::solve_spline( auto fspl_l_th = Rank2View(wk.data_handle(), 4 * inx, inth); if (ibcthmin != -1) { - CubicSplineInterpolator::correction_detect( + ExplicitBiCubicSplineInterpolator::correction_detect( bcthmin, ibcthmin, iflg2, inx); - CubicSplineInterpolator::correction_detect( + ExplicitBiCubicSplineInterpolator::correction_detect( bcthmax, ibcthmax, iflg2, inx); } @@ -1499,7 +1399,7 @@ void ExplicitBiCubicSplineInterpolator::solve_spline( else if (ibcxmax == 2) fspl_x_view(2, inx - 1) = bcxmax[ith]; - CubicSplineInterpolator::v_spline( + v_spline( ibcxmin, ibcxmax, inx, x, fspl_x_view, wk_x_view); } @@ -1541,7 +1441,7 @@ void ExplicitBiCubicSplineInterpolator::solve_spline( ibcthmaxa = 0; } - CubicSplineInterpolator::v_spline( + v_spline( ibcthmina, ibcthmaxa, inth, th, fspl_th_view, wk_th_view); } @@ -1664,8 +1564,7 @@ void ExplicitBiCubicSplineInterpolator::solve_spline( auto fspl_s_th = Rank2View( fspl_l_th.data_handle() + iadr, 4, inth); - CubicSplineInterpolator::v_spline( - ibcthmin, ibcthmax, inth, th, fspl_s_th, wk_th); + v_spline(ibcthmin, ibcthmax, inth, th, fspl_s_th, wk_th); }); Kokkos::parallel_for( @@ -1704,8 +1603,7 @@ void ExplicitBiCubicSplineInterpolator::solve_spline( fspl_x_view(1, inx - 1) = 0.0; fspl_x_view(2, inx - 1) = 0.0; - CubicSplineInterpolator::v_spline( - ibcxmin, ibcxmax, inx, x, fspl_x_view, wk_x_view); + v_spline(ibcxmin, ibcxmax, inx, x, fspl_x_view, wk_x_view); } Kokkos::parallel_for( @@ -1816,8 +1714,8 @@ ExplicitBiCubicSplineInterpolator::lookup( T zxget = xget; T zyget = yget; - CubicSplineInterpolator::range_check(xget, zxget, x, nx, ier); - CubicSplineInterpolator::range_check(yget, zyget, y, ny, ier); + ExplicitCubicSplineInterpolator::range_check(xget, zxget, x, nx, ier); + ExplicitCubicSplineInterpolator::range_check(yget, zyget, y, ny, ier); if (ier != 0) return; @@ -2042,73 +1940,47 @@ ExplicitBiCubicSplineInterpolator::evalfn( template CompactBiCubicSplineInterpolator:: CompactBiCubicSplineInterpolator( - Rank1View x, LO nx, Rank1View y, LO ny, - Rank3View f, LO ibcxmin, + Rank1View x, Rank1View y, + Rank1View values, LO ibcxmin, Rank1View bcxmin, LO ibcxmax, Rank1View bcxmax, LO ibcymin, Rank1View bcymin, LO ibcymax, - Rank1View bcymax, Rank1View wk) { - // Check bc validity - PCMS_ALWAYS_ASSERT(x.extent(0) > 2); - PCMS_ALWAYS_ASSERT(y.extent(0) > 2); - ibc_check(ibcxmin, "2d spline", "xmin", -1, 7); - if (ibcxmin >= 0) - ibc_check(ibcxmax, "2d spline", "xmax", 0, 7); - ibc_check(ibcymin, "2d spline", "ymin", -1, 7); - if (ibcymin >= 0) - ibc_check(ibcymax, "2d spline", "ymax", 0, 7); - - CubicSplineInterpolator::sanity_check(x, 1.0e-3); - CubicSplineInterpolator::sanity_check(y, 1.0e-3); - this->x_ = x; // Store the x-coordinates - this->y_ = y; // Store the y-coordinates - this->nx_ = nx; // Store the number of x-coordinates - this->ny_ = ny; // Store the number of y-coordinates - solve_spline(x, nx, y, ny, f, ibcxmin, bcxmin, ibcxmax, bcxmax, ibcymin, - bcymin, ibcymax, bcymax, wk); - this->f_ = f; // Store the spline coefficients -} + Rank1View bcymax) { + this->x_ = x; // Store the x-coordinates + this->y_ = y; // Store the y-coordinates + this->nx_ = x.extent(0); // Store the number of x-coordinates + this->ny_ = y.extent(0); // Store the number of y-coordinates -template -void CompactBiCubicSplineInterpolator::initialize_fspl( - Rank3View fspl, Rank1View values) { - LO ny = this->ny_; - Kokkos::parallel_for( - Kokkos::MDRangePolicy>({0, 0}, {ny, this->nx_}), - KOKKOS_LAMBDA(const LO ith, const LO ix) { - fspl(0, ix, ith) = values(ix * ny + ith); - }); + setup(x, y, values, ibcxmin, bcxmin, ibcxmax, + bcxmax, ibcymin, bcymin, ibcymax, bcymax); } template -CompactBiCubicSplineInterpolator:: - CompactBiCubicSplineInterpolator( +void CompactBiCubicSplineInterpolator:: + setup( Rank1View x, Rank1View y, Rank1View values, LO ibcxmin, Rank1View bcxmin, LO ibcxmax, Rank1View bcxmax, LO ibcymin, Rank1View bcymin, LO ibcymax, Rank1View bcymax) { - this->x_ = x; // Store the x-coordinates - this->y_ = y; // Store the y-coordinates - this->nx_ = x.extent(0); // Store the number of x-coordinates - this->ny_ = y.extent(0); // Store the number of y-coordinates - + LO ny = this->ny_; + LO nx = this->nx_; Kokkos::View fspl_view("fspl view", - 4 * this->nx_ * this->ny_); - CubicSplineInterpolator::set_coefficients(fspl_view); + 4 * nx * ny); + ExplicitCubicSplineInterpolator::set_coefficients(fspl_view); auto fspl = - Rank3View(fspl_view.data(), 4, this->nx_, this->ny_); - // Kokkos::parallel_for( - // Kokkos::MDRangePolicy>({0, 0}, {this->ny_, this->nx_}), - // KOKKOS_LAMBDA(const int ith, const int ix) { - // fspl(0, ix, ith) = values(ix * this->ny_ + ith); - // }); - initialize_fspl(fspl, values); - - Kokkos::View wk_view("wk", 9 * this->nx_ * this->ny_); + Rank3View(fspl_view.data(), 4, nx, ny); + + Kokkos::parallel_for( + Kokkos::MDRangePolicy>({0, 0}, {ny, nx}), + KOKKOS_LAMBDA(const LO ith, const LO ix) { + fspl(0, ix, ith) = values(ix * ny + ith); + }); + + Kokkos::View wk_view("wk", 9 * nx * ny); auto wk = - Rank1View(wk_view.data(), 9 * this->nx_ * this->ny_); + Rank1View(wk_view.data(), 9 * nx * ny); solve_spline(x, this->nx_, y, this->ny_, fspl, ibcxmin, bcxmin, ibcxmax, bcxmax, ibcymin, bcymin, ibcymax, bcymax, wk); @@ -2137,9 +2009,9 @@ void CompactBiCubicSplineInterpolator::solve_spline( // Check if inhomogeneous y-boundary conditions exist if (ibcymin != -1) { - CubicSplineInterpolator::correction_detect(bcymin, ibcymin, + ExplicitBiCubicSplineInterpolator::correction_detect(bcymin, ibcymin, iflg2, nx); - CubicSplineInterpolator::correction_detect(bcymax, ibcymax, + ExplicitBiCubicSplineInterpolator::correction_detect(bcymax, ibcymax, iflg2, nx); } @@ -2345,8 +2217,8 @@ CompactBiCubicSplineInterpolator::lookup( T zxget = xget; T zyget = yget; - CubicSplineInterpolator::range_check(xget, zxget, x, nx, ier); - CubicSplineInterpolator::range_check(yget, zyget, y, ny, ier); + ExplicitCubicSplineInterpolator::range_check(xget, zxget, x, nx, ier); + ExplicitCubicSplineInterpolator::range_check(yget, zyget, y, ny, ier); LO nxm = nx - 1; // Number of LOervals in x LO nym = ny - 1; // Number of LOervals in y From 96b382019d1341b1c39ab2897edf929976e0f07d Mon Sep 17 00:00:00 2001 From: Sichao25 Date: Sat, 2 Aug 2025 15:51:06 -0400 Subject: [PATCH 06/18] modify members access --- src/pcms/interpolator/spline_interpolator.hpp | 727 +++++++++--------- 1 file changed, 366 insertions(+), 361 deletions(-) diff --git a/src/pcms/interpolator/spline_interpolator.hpp b/src/pcms/interpolator/spline_interpolator.hpp index 8cd7a1311..bd16d4cf2 100644 --- a/src/pcms/interpolator/spline_interpolator.hpp +++ b/src/pcms/interpolator/spline_interpolator.hpp @@ -52,13 +52,32 @@ T get_element_from_span(Rank1View span, LO index) { return element; } +template +void isUniformAscending(Rank1View x, const T &ztol) { + using execution_space = typename MemorySpace::execution_space; + LO inx = static_cast(x.extent(0)); + + if (inx <= 1) + return; + + T dxavg = (get_element_from_span(x, inx - 1) - get_element_from_span(x, 0)) / + (inx - 1); + T zeps = std::abs(ztol * dxavg); + + Kokkos::parallel_for( + Kokkos::RangePolicy(1, inx), KOKKOS_LAMBDA(const LO ix) { + T zdiffx = x(ix) - x(ix - 1); + assert(zdiffx > 0.0); + T zdiff = zdiffx - dxavg; + assert(std::abs(zdiff) <= zeps); + }); +} + // TODO: better documentation // TODO: add more checks/assetions for input parameters template -class ExplicitCubicSplineInterpolator{ -private: - Kokkos::View coefficients_; +class ExplicitCubicSplineInterpolator { public: using execution_space = typename MemorySpace::execution_space; using member_type = typename Kokkos::TeamPolicy::member_type; @@ -70,53 +89,60 @@ class ExplicitCubicSplineInterpolator{ const LO &ibcxmax, const T &bcxmax); ExplicitCubicSplineInterpolator(Rank1View x, Rank1View values); - + + void evaluate(Rank1View xvec, Rank2View fval); + + void evaluate(Kokkos::View selector, + Rank1View xvec, Rank2View fval); + + static KOKKOS_INLINE_FUNCTION void + eval(T xget, Kokkos::View iselect, + Rank1View fval, Rank1View x, + const LO &nx, Rank2View fspl, LO &ier); + void setup(Rank1View x, const LO &nx, + Rank1View values, const LO &ibcxmin, + const T &bcxmin, const LO &ibcxmax, const T &bcxmax); + +protected: Rank1View x_; LO nx_; Rank2View fspl_; Kokkos::View get_coefficients(); void set_coefficients(Kokkos::View coefficients); - static void sanity_check(Rank1View x, const T &ztol); - static KOKKOS_INLINE_FUNCTION void range_check(T &xget, T &zxget, - Rank1View x, - const LO &nx, LO &ier); + void sanity_check(Rank1View x, const LO &ibcxmin, + const T &bcxmin, const LO &ibcxmax, const T &bcxmax); + + static KOKKOS_INLINE_FUNCTION void + inGrid(T &xget, T &zxget, Rank1View x, const LO &nx, LO &ier); - void setup( - Rank1View x, const LO &nx, Rank1View values, - const LO &ibcxmin, const T &bcxmin, const LO &ibcxmax, const T &bcxmax); static KOKKOS_FUNCTION void solve_spline(Rank1View x, const LO &nx, Rank2View fspl, const LO &ibcxmin, const T &bcxmin, const LO &ibcxmax, const T &bcxmax, Rank1View wk); + +private: + Kokkos::View coefficients_; + static KOKKOS_INLINE_FUNCTION void evalfn(Kokkos::View selector, Rank1View fval, const LO &i, const T &dx, Rank2View fspl); - static KOKKOS_INLINE_FUNCTION void - eval(T xget, Kokkos::View iselect, - Rank1View fval, Rank1View x, - const LO &nx, Rank2View fspl, LO &ier); - static KOKKOS_INLINE_FUNCTION void lookup(T xget, Rank1View x, const LO &nx, LO &i, T &dx, LO &ier); - - void evaluate(Rank1View xvec, Rank2View fval); - - void evaluate(Kokkos::View selector, - Rank1View xvec, Rank2View fval); }; template class CompactCubicSplineInterpolator : public ExplicitCubicSplineInterpolator { public: - using typename ExplicitCubicSplineInterpolator::execution_space; + using + typename ExplicitCubicSplineInterpolator::execution_space; using member_type = typename Kokkos::TeamPolicy::member_type; CompactCubicSplineInterpolator() = default; CompactCubicSplineInterpolator(Rank1View x, @@ -126,107 +152,114 @@ class CompactCubicSplineInterpolator CompactCubicSplineInterpolator(Rank1View x, Rank1View values); void setup(Rank1View x, const LO &nx, - Rank1View values, - const LO &ibcxmin, const T &bcxmin, const LO &ibcxmax, - const T &bcxmax); + Rank1View values, const LO &ibcxmin, + const T &bcxmin, const LO &ibcxmax, const T &bcxmax); + void evaluate(Rank1View xvec, Rank2View fval); + + void evaluate(Kokkos::View selector, + Rank1View xvec, Rank2View fval); + static KOKKOS_INLINE_FUNCTION void + eval(T xget, Kokkos::View ict, + Rank1View fval, Rank1View x, + const LO &nx, Rank2View fs2, LO &ier); + static KOKKOS_FUNCTION void solve_spline(Rank1View x, const LO &nx, Rank2View fspl, Rank2View fspl4, const LO &ibcxmin, const T &bcxmin, const LO &ibcxmax, const T &bcxmax, Rank1View wk); +protected: static KOKKOS_INLINE_FUNCTION void evalfn(Kokkos::View selector, Rank1View fval, const LO &i, const T &xparam, const T &hx, const T &hxi, Rank2View fs2); - static KOKKOS_INLINE_FUNCTION void - eval(T xget, Kokkos::View ict, - Rank1View fval, Rank1View x, - const LO &nx, Rank2View fs2, LO &ier); - static KOKKOS_INLINE_FUNCTION void lookup(T xget, Rank1View x, const LO &nx, LO &i, T &xparam, T &hx, T &hxi, LO &ier); - - void evaluate(Rank1View xvec, Rank2View fval); - - void evaluate(Kokkos::View selector, - Rank1View xvec, Rank2View fval); }; template class ExplicitBiCubicSplineInterpolator : public ExplicitCubicSplineInterpolator { public: - using typename ExplicitCubicSplineInterpolator::execution_space; + using + typename ExplicitCubicSplineInterpolator::execution_space; using member_type = typename Kokkos::TeamPolicy::member_type; - Rank4View fspl_; - Rank1View y_; - LO ny_; - ExplicitBiCubicSplineInterpolator() = default; ExplicitBiCubicSplineInterpolator( - Rank1View x, // size: inx - Rank1View th, // size: inth + Rank1View x, // size: inx + Rank1View y, // size: iny Rank1View values, LO ibcxmin, - Rank1View bcxmin, // size: inth (used if ibcxmin = 1 or 2) + Rank1View bcxmin, // size: iny (used if ibcxmin = 1 or 2) LO ibcxmax, - Rank1View bcxmax, // size: inth (used if ibcxmax = 1 or 2) - LO ibcthmin, - Rank1View - bcthmin, // size: inx (used if ibcthmin = 1 or 2) - LO ibcthmax, Rank1View bcthmax); - - ExplicitBiCubicSplineInterpolator(Rank1View x, // size: inx - Rank1View th, // size: inth - Rank1View values); - - static void correction_detect(Rank1View bcmin, LO &ibcmin, - LO &iflg2, LO &nx); + Rank1View bcxmax, // size: iny (used if ibcxmax = 1 or 2) + LO ibcymin, + Rank1View bcymin, // size: inx (used if ibcymin = 1 or 2) + LO ibcymax, Rank1View bcymax); + ExplicitBiCubicSplineInterpolator(Rank1View x, // size: inx + Rank1View y, // size: iny + Rank1View values); void setup( - Rank1View x, // size: inx - Rank1View th, // size: inth - Rank1View values, LO ibcxmin, - Rank1View - bcxmin, // size: inth (used if ibcxmin = 1 or 2) - LO ibcxmax, - Rank1View - bcxmax, // size: inth (used if ibcxmax = 1 or 2) - LO ibcthmin, - Rank1View - bcthmin, // size: inx (used if ibcthmin = 1 or 2) - LO ibcthmax, - Rank1View - bcthmax // size: inx (used if ibcthmax = 1 or 2) - ); + Rank1View x, // size: inx + Rank1View y, // size: iny + Rank1View values, LO ibcxmin, + Rank1View bcxmin, // size: iny (used if ibcxmin = 1 or 2) + LO ibcxmax, + Rank1View bcxmax, // size: iny (used if ibcxmax = 1 or 2) + LO ibcymin, + Rank1View bcymin, // size: inx (used if ibcymin = 1 or 2) + LO ibcymax, + Rank1View bcymax // size: inx (used if ibcymax = 1 or 2) + ); static void solve_spline( - Rank1View x, // size: inx - LO inx, Rank1View th, // size: inth - LO inth, Rank4View fspl, // [4, 4, inx, inth] + Rank1View x, // size: inx + LO inx, Rank1View y, // size: iny + LO iny, Rank4View fspl, // [4, 4, inx, iny] LO ibcxmin, - Rank1View bcxmin, // size: inth (used if ibcxmin = 1 or 2) + Rank1View bcxmin, // size: iny (used if ibcxmin = 1 or 2) LO ibcxmax, - Rank1View bcxmax, // size: inth (used if ibcxmax = 1 or 2) - LO ibcthmin, - Rank1View - bcthmin, // size: inx (used if ibcthmin = 1 or 2) - LO ibcthmax, - Rank1View - bcthmax, // size: inx (used if ibcthmax = 1 or 2) - Rank1View wk // size: nwk + Rank1View bcxmax, // size: iny (used if ibcxmax = 1 or 2) + LO ibcymin, + Rank1View bcymin, // size: inx (used if ibcymin = 1 or 2) + LO ibcymax, + Rank1View bcymax, // size: inx (used if ibcymax = 1 or 2) + Rank1View wk // size: nwk ); + static void correction_detect(Rank1View bcmin, LO &ibcmin, + LO &iflg2, LO &nx); + static KOKKOS_INLINE_FUNCTION void eval(T xget, T yget, Kokkos::View iselect, Rank1View fval, Rank1View x, const LO &nx, Rank1View y, const LO &ny, Rank4View fspl, LO &ier); + void evaluate(Rank1View xvec, Rank1View yvec, + Rank2View fval); + + void evaluate(Kokkos::View iselect, + Rank1View xvec, Rank1View yvec, + Rank2View fval); + +protected: + Rank4View fspl_; + Rank1View y_; + LO ny_; + + void sanity_check(Rank1View x, Rank1View y, + LO ibcxmin, Rank1View bcxmin, LO ibcxmax, + Rank1View bcxmax, LO ibcymin, + Rank1View bcymin, LO ibcymax, + Rank1View bcymax); + +private: static KOKKOS_INLINE_FUNCTION void lookup(T xget, T yget, Rank1View x, const LO &nx, Rank1View y, const LO &ny, LO &i, LO &j, T &dx, T &dy, @@ -242,24 +275,15 @@ class ExplicitBiCubicSplineInterpolator const T &dy, // y displacements within cells Rank4View fspl // Spline coefficients: [4, 4, nx, ny] ); - - void evaluate(Rank1View xvec, Rank1View yvec, - Rank2View fval); - - void evaluate(Kokkos::View iselect, - Rank1View xvec, Rank1View yvec, - Rank2View fval); }; template class CompactBiCubicSplineInterpolator : public ExplicitBiCubicSplineInterpolator { public: - using typename ExplicitCubicSplineInterpolator::execution_space; + using + typename ExplicitCubicSplineInterpolator::execution_space; using member_type = typename Kokkos::TeamPolicy::member_type; - Rank3View f_; - Rank1View y_; - LO ny_; CompactBiCubicSplineInterpolator() = default; @@ -275,13 +299,12 @@ class CompactBiCubicSplineInterpolator Rank1View y, Rank1View values); - void setup( - Rank1View x, Rank1View y, - Rank1View values, LO ibcxmin, - Rank1View bcxmin, LO ibcxmax, - Rank1View bcxmax, LO ibcymin, - Rank1View bcymin, LO ibcymax, - Rank1View bcymax); + void setup(Rank1View x, Rank1View y, + Rank1View values, LO ibcxmin, + Rank1View bcxmin, LO ibcxmax, + Rank1View bcxmax, LO ibcymin, + Rank1View bcymin, LO ibcymax, + Rank1View bcymax); static void solve_spline(Rank1View x, LO nx, Rank1View y, LO ny, @@ -292,17 +315,6 @@ class CompactBiCubicSplineInterpolator Rank1View bcymax, Rank1View wk); - static KOKKOS_INLINE_FUNCTION void - lookup(T xget, T yget, Rank1View x, const LO &nx, - Rank1View y, const LO &ny, LO &i, LO &j, T &xparam, - T &yparam, T &hx, T &hxi, T &hy, T &hyi, LO &ier); - - static KOKKOS_INLINE_FUNCTION void - evalfn(Kokkos::View ict, LO ivec, LO ivecd, - Rank1View fval, const LO &i, const LO &j, - const T &xparam, const T &yparam, const T &hx, const T &hxi, - const T &hy, const T &hyi, Rank3View f); - static KOKKOS_INLINE_FUNCTION void eval(T xget, T yget, Kokkos::View ict, Rank1View fval, // output (size depends on ict) @@ -315,6 +327,21 @@ class CompactBiCubicSplineInterpolator void evaluate(Kokkos::View iselect, Rank1View xvec, Rank1View yvec, Rank2View fval); + +protected: + Rank3View fspl_; + +private: + static KOKKOS_INLINE_FUNCTION void + lookup(T xget, T yget, Rank1View x, const LO &nx, + Rank1View y, const LO &ny, LO &i, LO &j, T &xparam, + T &yparam, T &hx, T &hxi, T &hy, T &hyi, LO &ier); + + static KOKKOS_INLINE_FUNCTION void + evalfn(Kokkos::View ict, LO ivec, LO ivecd, + Rank1View fval, const LO &i, const LO &j, + const T &xparam, const T &yparam, const T &hx, const T &hxi, + const T &hy, const T &hyi, Rank3View f); }; template @@ -346,23 +373,17 @@ void ExplicitBiCubicSplineInterpolator::correction_detect( template void ExplicitCubicSplineInterpolator::sanity_check( - Rank1View x, const T &ztol) { - LO inx = static_cast(x.extent(0)); - - if (inx <= 1) - return; + Rank1View x, const LO &ibcxmin, const T &bcxmin, + const LO &ibcxmax, const T &bcxmax) { + PCMS_ALWAYS_ASSERT(x.extent(0) >= 2); - T dxavg = (get_element_from_span(x, inx - 1) - get_element_from_span(x, 0)) / - (inx - 1); - T zeps = std::abs(ztol * dxavg); + ibc_check(ibcxmin, "1d spline", "xmin", -1, 7); + if (ibcxmin >= 0) + ibc_check(ibcxmax, "1d spline", "xmax", 0, 7); + isUniformAscending(x, 1.0e-3); - Kokkos::parallel_for( - Kokkos::RangePolicy(1, inx), KOKKOS_LAMBDA(const LO ix) { - T zdiffx = x(ix) - x(ix - 1); - assert(zdiffx > 0.0); - T zdiff = zdiffx - dxavg; - assert(std::abs(zdiff) <= zeps); - }); + this->nx_ = x.extent(0); + this->x_ = x; } template @@ -371,16 +392,7 @@ ExplicitCubicSplineInterpolator:: Rank1View values, const LO &ibcxmin, const T &bcxmin, const LO &ibcxmax, const T &bcxmax) { - PCMS_ALWAYS_ASSERT(x.extent(0) >= 2); - - ibc_check(ibcxmin, "1d spline", "xmin", -1, 7); - if (ibcxmin >= 0) - ibc_check(ibcxmax, "1d spline", "xmax", 0, 7); - ExplicitCubicSplineInterpolator::sanity_check(x, 1.0e-3); - - this->nx_ = x.extent(0); - this->x_ = x; - + sanity_check(x, ibcxmin, bcxmin, ibcxmax, bcxmax); setup(x, this->nx_, values, ibcxmin, bcxmin, ibcxmax, bcxmax); } @@ -421,16 +433,10 @@ void ExplicitCubicSplineInterpolator::setup( template CompactCubicSplineInterpolator::CompactCubicSplineInterpolator( Rank1View x, Rank1View values, - const LO &ibcxmin, const T &bcxmin, - const LO &ibcxmax, const T &bcxmax) { - ibc_check(ibcxmin, "1d spline", "xmin", -1, 7); - if (ibcxmin >= 0) - ibc_check(ibcxmax, "1d spline", "xmax", 0, 7); - ExplicitCubicSplineInterpolator::sanity_check(x, 1.0e-3); - this->x_ = x; - this->nx_ = x.extent(0); + const LO &ibcxmin, const T &bcxmin, const LO &ibcxmax, const T &bcxmax) { + ExplicitCubicSplineInterpolator::sanity_check( + x, ibcxmin, bcxmin, ibcxmax, bcxmax); setup(x, this->nx_, values, ibcxmin, bcxmin, ibcxmax, bcxmax); - } template @@ -445,8 +451,7 @@ CompactCubicSplineInterpolator::CompactCubicSplineInterpolator( template void CompactCubicSplineInterpolator::setup( Rank1View x, const LO &nx, Rank1View values, - const LO &ibcxmin, const T &bcxmin, - const LO &ibcxmax, const T &bcxmax) { + const LO &ibcxmin, const T &bcxmin, const LO &ibcxmax, const T &bcxmax) { Kokkos::View fspl_view("coefficients", 2 * this->nx_); ExplicitCubicSplineInterpolator::set_coefficients(fspl_view); auto fspl = Rank2View(fspl_view.data(), 2, this->nx_); @@ -472,9 +477,10 @@ void CompactCubicSplineInterpolator::setup( } template -KOKKOS_FUNCTION void v_spline( - const LO &k_bc1, const LO &k_bcn, const LO &n, Rank1View x, - Rank2View f, Rank1View wk) { +KOKKOS_FUNCTION void v_spline(const LO &k_bc1, const LO &k_bcn, const LO &n, + Rank1View x, + Rank2View f, + Rank1View wk) { LO i_bc1 = k_bc1; LO i_bcn = k_bcn; LO iord1, iord2, imin, imax; @@ -970,7 +976,7 @@ ExplicitCubicSplineInterpolator::solve_spline( template KOKKOS_INLINE_FUNCTION void -ExplicitCubicSplineInterpolator::range_check( +ExplicitCubicSplineInterpolator::inGrid( T &xget, T &zxget, Rank1View x, const LO &nx, LO &ier) { if (xget < x[0] || xget > x[nx - 1]) { T zxtol = 4.0e-7 * std::max(std::abs(x[0]), std::abs(x[nx - 1])); @@ -1049,7 +1055,8 @@ ExplicitCubicSplineInterpolator::lookup( T zxget = xget; // Range check - ExplicitCubicSplineInterpolator::range_check(xget, zxget, x, nx, ier); + ExplicitCubicSplineInterpolator::inGrid(xget, zxget, x, nx, + ier); LO ii = static_cast(nxm * (zxget - x[0]) / (x[nx - 1] - x[0])); i = std::min(nxm - 1, ii); @@ -1206,7 +1213,8 @@ CompactCubicSplineInterpolator::lookup( T zxget = xget; - ExplicitCubicSplineInterpolator::range_check(xget, zxget, x, nx, ier); + ExplicitCubicSplineInterpolator::inGrid(xget, zxget, x, nx, + ier); LO nxm = nx - 1; @@ -1248,94 +1256,95 @@ CompactCubicSplineInterpolator::eval( } template -ExplicitBiCubicSplineInterpolator:: - ExplicitBiCubicSplineInterpolator( - Rank1View x, // size: inx - Rank1View th, // size: inth - Rank1View values, LO ibcxmin, - Rank1View - bcxmin, // size: inth (used if ibcxmin = 1 or 2) - LO ibcxmax, - Rank1View - bcxmax, // size: inth (used if ibcxmax = 1 or 2) - LO ibcthmin, - Rank1View - bcthmin, // size: inx (used if ibcthmin = 1 or 2) - LO ibcthmax, - Rank1View - bcthmax // size: inx (used if ibcthmax = 1 or 2) - ) { +void ExplicitBiCubicSplineInterpolator::sanity_check( + Rank1View x, Rank1View y, LO ibcxmin, + Rank1View bcxmin, LO ibcxmax, + Rank1View bcxmax, LO ibcymin, + Rank1View bcymin, LO ibcymax, + Rank1View bcymax) { PCMS_ALWAYS_ASSERT(x.extent(0) >= 2); - PCMS_ALWAYS_ASSERT(th.extent(0) >= 2); + PCMS_ALWAYS_ASSERT(y.extent(0) >= 2); // Check boundary condition values ibc_check(ibcxmin, "2d spline", "xmin", -1, 7); if (ibcxmin >= 0) ibc_check(ibcxmax, "2d spline", "xmax", 0, 7); - ibc_check(ibcthmin, "2d spline", "thmin", -1, 7); - if (ibcthmin >= 0) - ibc_check(ibcthmax, "2d spline", "thmax", 0, 7); + ibc_check(ibcymin, "2d spline", "ymin", -1, 7); + if (ibcymin >= 0) + ibc_check(ibcymax, "2d spline", "ymax", 0, 7); - ExplicitCubicSplineInterpolator::sanity_check(x, 1.0e-3); - ExplicitCubicSplineInterpolator::sanity_check(th, 1.0e-3); + isUniformAscending(x, 1.0e-3); + isUniformAscending(y, 1.0e-3); this->x_ = x; this->nx_ = x.extent(0); - this->y_ = th; - this->ny_ = th.extent(0); - - setup(x, th, values, ibcxmin, bcxmin, ibcxmax, - bcxmax, ibcthmin, bcthmin, ibcthmax, bcthmax); + this->y_ = y; + this->ny_ = y.extent(0); } template -void ExplicitBiCubicSplineInterpolator:: - setup( - Rank1View x, // size: inx - Rank1View th, // size: inth +ExplicitBiCubicSplineInterpolator:: + ExplicitBiCubicSplineInterpolator( + Rank1View x, // size: inx + Rank1View y, // size: iny Rank1View values, LO ibcxmin, Rank1View - bcxmin, // size: inth (used if ibcxmin = 1 or 2) + bcxmin, // size: iny (used if ibcxmin = 1 or 2) LO ibcxmax, Rank1View - bcxmax, // size: inth (used if ibcxmax = 1 or 2) - LO ibcthmin, + bcxmax, // size: iny (used if ibcxmax = 1 or 2) + LO ibcymin, Rank1View - bcthmin, // size: inx (used if ibcthmin = 1 or 2) - LO ibcthmax, - Rank1View - bcthmax // size: inx (used if ibcthmax = 1 or 2) + bcymin, // size: inx (used if ibcymin = 1 or 2) + LO ibcymax, + Rank1View bcymax // size: inx (used if ibcymax = 1 or 2) ) { + sanity_check(x, y, ibcxmin, bcxmin, ibcxmax, bcxmax, ibcymin, bcymin, ibcymax, + bcymax); + + setup(x, y, values, ibcxmin, bcxmin, ibcxmax, bcxmax, ibcymin, bcymin, + ibcymax, bcymax); +} + +template +void ExplicitBiCubicSplineInterpolator::setup( + Rank1View x, // size: inx + Rank1View y, // size: iny + Rank1View values, LO ibcxmin, + Rank1View bcxmin, // size: iny (used if ibcxmin = 1 or 2) + LO ibcxmax, + Rank1View bcxmax, // size: iny (used if ibcxmax = 1 or 2) + LO ibcymin, + Rank1View bcymin, // size: inx (used if ibcymin = 1 or 2) + LO ibcymax, + Rank1View bcymax // size: inx (used if ibcymax = 1 or 2) +) { LO ny = this->ny_; LO nx = this->nx_; - Kokkos::View fspl_view("fspl view", - 4 * 4 * nx * ny); + Kokkos::View fspl_view("fspl view", 4 * 4 * nx * ny); ExplicitCubicSplineInterpolator::set_coefficients(fspl_view); - auto fspl = - Rank4View(fspl_view.data(), 4, 4, nx, ny); + auto fspl = Rank4View(fspl_view.data(), 4, 4, nx, ny); Kokkos::parallel_for( Kokkos::MDRangePolicy>({0, 0}, {ny, nx}), - KOKKOS_LAMBDA(const LO ith, const LO ix) { - fspl(0, 0, ix, ith) = values(ix * ny + ith); + KOKKOS_LAMBDA(const LO iy, const LO ix) { + fspl(0, 0, ix, iy) = values(ix * ny + iy); }); Kokkos::View wk_view("wk", 9 * nx * ny); - auto wk = - Rank1View(wk_view.data(), 9 * nx * ny); + auto wk = Rank1View(wk_view.data(), 9 * nx * ny); - solve_spline(x, nx, th, ny, fspl, ibcxmin, bcxmin, ibcxmax, - bcxmax, ibcthmin, bcthmin, ibcthmax, bcthmax, wk); + solve_spline(x, nx, y, ny, fspl, ibcxmin, bcxmin, ibcxmax, bcxmax, ibcymin, + bcymin, ibcymax, bcymax, wk); this->fspl_ = fspl; } template ExplicitBiCubicSplineInterpolator:: - ExplicitBiCubicSplineInterpolator( - Rank1View x, // size: inx - Rank1View th, // size: inth - Rank1View values) + ExplicitBiCubicSplineInterpolator(Rank1View x, // size: inx + Rank1View y, // size: iny + Rank1View values) : ExplicitBiCubicSplineInterpolator( - x, th, values, 0, {}, 0, {}, 0, {}, 0, + x, y, values, 0, {}, 0, {}, 0, {}, 0, {}) { // Delegates to primary constructor std::cout << "Not a knot boundary condition is applied by default" << std::endl; @@ -1343,70 +1352,70 @@ ExplicitBiCubicSplineInterpolator:: template void ExplicitBiCubicSplineInterpolator::solve_spline( - Rank1View x, // size: inx - LO inx, Rank1View th, // size: inth - LO inth, Rank4View fspl, // [4, 4, inx, inth] + Rank1View x, // size: inx + LO inx, Rank1View y, // size: iny + LO iny, Rank4View fspl, // [4, 4, inx, iny] LO ibcxmin, - Rank1View bcxmin, // size: inth (used if ibcxmin = 1 or 2) + Rank1View bcxmin, // size: iny (used if ibcxmin = 1 or 2) LO ibcxmax, - Rank1View bcxmax, // size: inth (used if ibcxmax = 1 or 2) - LO ibcthmin, - Rank1View bcthmin, // size: inx (used if ibcthmin = 1 or 2) - LO ibcthmax, - Rank1View bcthmax, // size: inx (used if ibcthmax = 1 or 2) - Rank1View wk // size: nwk + Rank1View bcxmax, // size: iny (used if ibcxmax = 1 or 2) + LO ibcymin, + Rank1View bcymin, // size: inx (used if ibcymin = 1 or 2) + LO ibcymax, + Rank1View bcymax, // size: inx (used if ibcymax = 1 or 2) + Rank1View wk // size: nwk ) { LO iflg2 = 0; - auto fspl_l_x = Rank2View(wk.data_handle() + 4 * inx * inth, - 4 * inx, inth); - auto wk_l = Rank1View(wk.data_handle() + 2 * 4 * inx * inth, - inx * inth); - auto fspl_l_th = Rank2View(wk.data_handle(), 4 * inx, inth); + auto fspl_l_x = + Rank2View(wk.data_handle() + 4 * inx * iny, 4 * inx, iny); + auto wk_l = Rank1View(wk.data_handle() + 2 * 4 * inx * iny, + inx * iny); + auto fspl_l_y = Rank2View(wk.data_handle(), 4 * inx, iny); - if (ibcthmin != -1) { + if (ibcymin != -1) { ExplicitBiCubicSplineInterpolator::correction_detect( - bcthmin, ibcthmin, iflg2, inx); + bcymin, ibcymin, iflg2, inx); ExplicitBiCubicSplineInterpolator::correction_detect( - bcthmax, ibcthmax, iflg2, inx); + bcymax, ibcymax, iflg2, inx); } T xo2 = 0.5; T xo6 = 1.0 / 6.0; Kokkos::parallel_for( - Kokkos::TeamPolicy(inth, Kokkos::AUTO), + Kokkos::TeamPolicy(iny, Kokkos::AUTO), KOKKOS_LAMBDA(const member_type &team) { - const LO ith = team.league_rank(); + const LO iy = team.league_rank(); auto fspl_x_view = Rank2View( - fspl_l_x.data_handle() + 4 * inx * ith, 4, inx); + fspl_l_x.data_handle() + 4 * inx * iy, 4, inx); auto wk_x_view = - Rank1View(wk_l.data_handle() + ith * inx, inx); + Rank1View(wk_l.data_handle() + iy * inx, inx); Kokkos::parallel_for(Kokkos::TeamThreadRange(team, inx), [=](LO ix) { - fspl_x_view(0, ix) = fspl(0, 0, ix, ith); + fspl_x_view(0, ix) = fspl(0, 0, ix, iy); }); if (team.team_rank() == 0) { if (ibcxmin == 1) - fspl_x_view(1, 0) = bcxmin[ith]; + fspl_x_view(1, 0) = bcxmin[iy]; else if (ibcxmin == 2) - fspl_x_view(2, 0) = bcxmin[ith]; + fspl_x_view(2, 0) = bcxmin[iy]; if (ibcxmax == 1) - fspl_x_view(1, inx - 1) = bcxmax[ith]; + fspl_x_view(1, inx - 1) = bcxmax[iy]; else if (ibcxmax == 2) - fspl_x_view(2, inx - 1) = bcxmax[ith]; + fspl_x_view(2, inx - 1) = bcxmax[iy]; - v_spline( - ibcxmin, ibcxmax, inx, x, fspl_x_view, wk_x_view); + v_spline(ibcxmin, ibcxmax, inx, x, fspl_x_view, + wk_x_view); } Kokkos::parallel_for(Kokkos::TeamThreadRange(team, inx), [=](LO ix) { - fspl(1, 0, ix, ith) = fspl_x_view(1, ix); - fspl(2, 0, ix, ith) = fspl_x_view(2, ix) * xo2; - fspl(3, 0, ix, ith) = fspl_x_view(3, ix) * xo6; + fspl(1, 0, ix, iy) = fspl_x_view(1, ix); + fspl(2, 0, ix, iy) = fspl_x_view(2, ix) * xo2; + fspl(3, 0, ix, iy) = fspl_x_view(3, ix) * xo6; }); }); @@ -1415,66 +1424,65 @@ void ExplicitBiCubicSplineInterpolator::solve_spline( KOKKOS_LAMBDA(const member_type &team) { const LO ix = team.league_rank(); - auto fspl_th_view = Rank2View( - fspl_l_th.data_handle() + 4 * ix * inth, 4, inth); - auto wk_th_view = - Rank1View(wk_l.data_handle() + ix * inth, inth); + auto fspl_y_view = Rank2View( + fspl_l_y.data_handle() + 4 * ix * iny, 4, iny); + auto wk_y_view = + Rank1View(wk_l.data_handle() + ix * iny, iny); for (LO ic = 0; ic < 4; ++ic) { - Kokkos::parallel_for( - Kokkos::TeamThreadRange(team, inth), - [=](LO ith) { fspl_th_view(0, ith) = fspl(ic, 0, ix, ith); }); + Kokkos::parallel_for(Kokkos::TeamThreadRange(team, iny), [=](LO iy) { + fspl_y_view(0, iy) = fspl(ic, 0, ix, iy); + }); // Set linear BCs initially if (team.team_rank() == 0) { - fspl_th_view(1, 0) = 0.0; - fspl_th_view(2, 0) = 0.0; - fspl_th_view(1, inth - 1) = 0.0; - fspl_th_view(2, inth - 1) = 0.0; + fspl_y_view(1, 0) = 0.0; + fspl_y_view(2, 0) = 0.0; + fspl_y_view(1, iny - 1) = 0.0; + fspl_y_view(2, iny - 1) = 0.0; - LO ibcthmina = ibcthmin; - LO ibcthmaxa = ibcthmax; + LO ibcymina = ibcymin; + LO ibcymaxa = ibcymax; if (iflg2 == 1) { - if (ibcthmin == 1 || ibcthmin == 2) - ibcthmina = 0; - if (ibcthmax == 1 || ibcthmax == 2) - ibcthmaxa = 0; + if (ibcymin == 1 || ibcymin == 2) + ibcymina = 0; + if (ibcymax == 1 || ibcymax == 2) + ibcymaxa = 0; } - v_spline( - ibcthmina, ibcthmaxa, inth, th, fspl_th_view, wk_th_view); + v_spline(ibcymina, ibcymaxa, iny, y, fspl_y_view, + wk_y_view); } - Kokkos::parallel_for( - Kokkos::TeamThreadRange(team, inth), [=](LO ith) { - fspl(ic, 1, ix, ith) = fspl_th_view(1, ith); - fspl(ic, 2, ix, ith) = fspl_th_view(2, ith) * xo2; - fspl(ic, 3, ix, ith) = fspl_th_view(3, ith) * xo6; - }); + Kokkos::parallel_for(Kokkos::TeamThreadRange(team, iny), [=](LO iy) { + fspl(ic, 1, ix, iy) = fspl_y_view(1, iy); + fspl(ic, 2, ix, iy) = fspl_y_view(2, iy) * xo2; + fspl(ic, 3, ix, iy) = fspl_y_view(3, iy) * xo6; + }); } }); if (iflg2 == 1) { - LO iasc = 0; // Workspace base for correction splines - LO iinc = 4 * inth; // Spacing between correction splines + LO iasc = 0; // Workspace base for correction splines + LO iinc = 4 * iny; // Spacing between correction splines T zhxn = get_element_from_span(x, inx - 1) - get_element_from_span(x, inx - 2); - T zhth = get_element_from_span(th, inth - 1) - - get_element_from_span(th, inth - 2); + T zhy = + get_element_from_span(y, iny - 1) - get_element_from_span(y, iny - 2); LO jx = inx - 2; - LO jth = inth - 2; + LO jy = iny - 2; LO iselect1_arr[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; LO iselect2_arr[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - if (ibcthmin == 1) + if (ibcymin == 1) iselect1_arr[2] = 1; - if (ibcthmin == 2) + if (ibcymin == 2) iselect1_arr[4] = 1; - if (ibcthmax == 1) + if (ibcymax == 1) iselect2_arr[2] = 1; - if (ibcthmax == 2) + if (ibcymax == 2) iselect2_arr[4] = 1; Kokkos::View iselect1("iselect1", 10); Kokkos::parallel_for( @@ -1495,107 +1503,106 @@ void ExplicitBiCubicSplineInterpolator::solve_spline( auto zcur = Rank1View(zcur_shared.data_handle() + ix * 3, 3); T zdiff1 = 0.0, zdiff2 = 0.0; - auto wk_th = Rank1View(wk_l.data_handle(), inth); + auto wk_y = Rank1View(wk_l.data_handle(), iny); - if (ibcthmin == 1) { + if (ibcymin == 1) { zcur[0] = (ix < inx - 1) ? fspl(0, 1, ix, 0) : fspl(0, 1, jx, 0) + zhxn * (fspl(1, 1, jx, 0) + zhxn * (fspl(2, 1, jx, 0) + zhxn * fspl(3, 1, jx, 0))); - zdiff1 = bcthmin[ix] - zcur[0]; - } else if (ibcthmin == 2) { + zdiff1 = bcymin[ix] - zcur[0]; + } else if (ibcymin == 2) { zcur[0] = (ix < inx - 1) ? 2.0 * fspl(0, 2, ix, 0) : 2.0 * (fspl(0, 2, jx, 0) + zhxn * (fspl(1, 2, jx, 0) + zhxn * (fspl(2, 2, jx, 0) + zhxn * fspl(3, 2, jx, 0)))); - zdiff1 = bcthmin[ix] - zcur[0]; + zdiff1 = bcymin[ix] - zcur[0]; } // auto zcur = Rank1View(zcur_vec.data(), 3); - if (ibcthmax == 1) { + if (ibcymax == 1) { if (ix < inx - 1) { - zcur(0) = fspl(0, 1, ix, jth) + - zhth * (2.0 * fspl(0, 2, ix, jth) + - zhth * 3.0 * fspl(0, 3, ix, jth)); + zcur(0) = + fspl(0, 1, ix, jy) + zhy * (2.0 * fspl(0, 2, ix, jy) + + zhy * 3.0 * fspl(0, 3, ix, jy)); } else { // TODO: check if this is correct - eval(x[inx - 1], th[inth - 1], iselect2, zcur, x, inx, th, inth, - fspl, ier); + eval(x[inx - 1], y[iny - 1], iselect2, zcur, x, inx, y, iny, fspl, + ier); if (ier != 0) return; } - zdiff2 = bcthmax[ix] - zcur(0); - } else if (ibcthmax == 2) { + zdiff2 = bcymax[ix] - zcur(0); + } else if (ibcymax == 2) { if (ix < inx - 1) { zcur(0) = - 2.0 * fspl(0, 2, ix, jth) + 6.0 * zhth * fspl(0, 3, ix, jth); + 2.0 * fspl(0, 2, ix, jy) + 6.0 * zhy * fspl(0, 3, ix, jy); } else { // TODO: check if this is correct - eval(x[inx - 1], th[inth - 1], iselect2, zcur, x, inx, th, inth, - fspl, ier); + eval(x[inx - 1], y[iny - 1], iselect2, zcur, x, inx, y, iny, fspl, + ier); if (ier != 0) return; } - zdiff2 = bcthmax[ix] - zcur(0); + zdiff2 = bcymax[ix] - zcur(0); } LO iadr = iasc + ix * iinc; - for (LO ith = 0; ith < inth; ++ith) - fspl_l_th(ix * 4, ith) = 0.0; - - fspl_l_th(1 + ix * 4, 0) = 0.0; - fspl_l_th(2 + ix * 4, 0) = 0.0; - fspl_l_th(1 + ix * 4, inth - 1) = 0.0; - fspl_l_th(2 + ix * 4, inth - 1) = 0.0; - - if (ibcthmin == 1) - fspl_l_th(1 + ix * 4, 0) = zdiff1; - else if (ibcthmin == 2) - fspl_l_th(2 + ix * 4, 0) = zdiff1; - - if (ibcthmax == 1) - fspl_l_th(1 + ix * 4, inth - 1) = zdiff2; - else if (ibcthmax == 2) - fspl_l_th(2 + ix * 4, inth - 1) = zdiff2; - - auto fspl_s_th = Rank2View( - fspl_l_th.data_handle() + iadr, 4, inth); - v_spline(ibcthmin, ibcthmax, inth, th, fspl_s_th, wk_th); + for (LO iy = 0; iy < iny; ++iy) + fspl_l_y(ix * 4, iy) = 0.0; + + fspl_l_y(1 + ix * 4, 0) = 0.0; + fspl_l_y(2 + ix * 4, 0) = 0.0; + fspl_l_y(1 + ix * 4, iny - 1) = 0.0; + fspl_l_y(2 + ix * 4, iny - 1) = 0.0; + + if (ibcymin == 1) + fspl_l_y(1 + ix * 4, 0) = zdiff1; + else if (ibcymin == 2) + fspl_l_y(2 + ix * 4, 0) = zdiff1; + + if (ibcymax == 1) + fspl_l_y(1 + ix * 4, iny - 1) = zdiff2; + else if (ibcymax == 2) + fspl_l_y(2 + ix * 4, iny - 1) = zdiff2; + + auto fspl_s_y = + Rank2View(fspl_l_y.data_handle() + iadr, 4, iny); + v_spline(ibcymin, ibcymax, iny, y, fspl_s_y, wk_y); }); Kokkos::parallel_for( - Kokkos::MDRangePolicy>({0, 0}, {inx, inth - 1}), - KOKKOS_LAMBDA(const LO ix, const LO ith) { + Kokkos::MDRangePolicy>({0, 0}, {inx, iny - 1}), + KOKKOS_LAMBDA(const LO ix, const LO iy) { // Multiply local coefficients - fspl_l_th(2 + ix * 4, ith) *= xo2; - fspl_l_th(3 + ix * 4, ith) *= xo6; + fspl_l_y(2 + ix * 4, iy) *= xo2; + fspl_l_y(3 + ix * 4, iy) *= xo6; // Conditional accumulation LOo global fspl if (ix < inx - 1) { - fspl(0, 1, ix, ith) += fspl_l_th(1 + ix * 4, ith); - fspl(0, 2, ix, ith) += fspl_l_th(2 + ix * 4, ith); - fspl(0, 3, ix, ith) += fspl_l_th(3 + ix * 4, ith); + fspl(0, 1, ix, iy) += fspl_l_y(1 + ix * 4, iy); + fspl(0, 2, ix, iy) += fspl_l_y(2 + ix * 4, iy); + fspl(0, 3, ix, iy) += fspl_l_y(3 + ix * 4, iy); } }); Kokkos::parallel_for( - Kokkos::TeamPolicy(inth - 1, Kokkos::AUTO), + Kokkos::TeamPolicy(iny - 1, Kokkos::AUTO), KOKKOS_LAMBDA(const member_type &team) { - const LO ith = team.league_rank(); + const LO iy = team.league_rank(); auto fspl_x_view = Rank2View( - fspl_l_x.data_handle() + 4 * inx * ith, 4, inx); + fspl_l_x.data_handle() + 4 * inx * iy, 4, inx); auto wk_x_view = - Rank1View(wk_l.data_handle() + ith * inx, inx); + Rank1View(wk_l.data_handle() + iy * inx, inx); for (LO ic = 1; ic < 4; ++ic) { Kokkos::parallel_for( - Kokkos::TeamThreadRange(team, inx), [=](LO ix) { - fspl_x_view(0, ix) = fspl_l_th(ic + ix * 4, ith); - }); + Kokkos::TeamThreadRange(team, inx), + [=](LO ix) { fspl_x_view(0, ix) = fspl_l_y(ic + ix * 4, iy); }); if (team.team_rank() == 0) { fspl_x_view(1, 0) = 0.0; @@ -1608,9 +1615,9 @@ void ExplicitBiCubicSplineInterpolator::solve_spline( Kokkos::parallel_for( Kokkos::TeamThreadRange(team, inx - 1), [=](LO ix) { - fspl(1, ic, ix, ith) += fspl_x_view(1, ix); - fspl(2, ic, ix, ith) += fspl_x_view(2, ix) * xo2; - fspl(3, ic, ix, ith) += fspl_x_view(3, ix) * xo6; + fspl(1, ic, ix, iy) += fspl_x_view(1, ix); + fspl(2, ic, ix, iy) += fspl_x_view(2, ix) * xo2; + fspl(3, ic, ix, iy) += fspl_x_view(3, ix) * xo6; }); } }); @@ -1663,7 +1670,7 @@ void CompactBiCubicSplineInterpolator::evaluate( auto fval_view = Rank1View(fval.data_handle() + i * ivd, ivd); eval(xvec(i), yvec(i), iselect, fval_view, this->x_, this->nx_, - this->y_, this->ny_, this->f_, ier); + this->y_, this->ny_, this->fspl_, ier); }); } @@ -1714,8 +1721,10 @@ ExplicitBiCubicSplineInterpolator::lookup( T zxget = xget; T zyget = yget; - ExplicitCubicSplineInterpolator::range_check(xget, zxget, x, nx, ier); - ExplicitCubicSplineInterpolator::range_check(yget, zyget, y, ny, ier); + ExplicitCubicSplineInterpolator::inGrid(xget, zxget, x, nx, + ier); + ExplicitCubicSplineInterpolator::inGrid(yget, zyget, y, ny, + ier); if (ier != 0) return; @@ -1946,51 +1955,45 @@ CompactBiCubicSplineInterpolator:: Rank1View bcxmax, LO ibcymin, Rank1View bcymin, LO ibcymax, Rank1View bcymax) { - this->x_ = x; // Store the x-coordinates - this->y_ = y; // Store the y-coordinates - this->nx_ = x.extent(0); // Store the number of x-coordinates - this->ny_ = y.extent(0); // Store the number of y-coordinates + ExplicitBiCubicSplineInterpolator::sanity_check( + x, y, ibcxmin, bcxmin, ibcxmax, bcxmax, ibcymin, bcymin, ibcymax, bcymax); - setup(x, y, values, ibcxmin, bcxmin, ibcxmax, - bcxmax, ibcymin, bcymin, ibcymax, bcymax); + setup(x, y, values, ibcxmin, bcxmin, ibcxmax, bcxmax, ibcymin, bcymin, + ibcymax, bcymax); } template -void CompactBiCubicSplineInterpolator:: - setup( - Rank1View x, Rank1View y, - Rank1View values, LO ibcxmin, - Rank1View bcxmin, LO ibcxmax, - Rank1View bcxmax, LO ibcymin, - Rank1View bcymin, LO ibcymax, - Rank1View bcymax) { +void CompactBiCubicSplineInterpolator::setup( + Rank1View x, Rank1View y, + Rank1View values, LO ibcxmin, + Rank1View bcxmin, LO ibcxmax, + Rank1View bcxmax, LO ibcymin, + Rank1View bcymin, LO ibcymax, + Rank1View bcymax) { LO ny = this->ny_; LO nx = this->nx_; - Kokkos::View fspl_view("fspl view", - 4 * nx * ny); + Kokkos::View fspl_view("fspl view", 4 * nx * ny); ExplicitCubicSplineInterpolator::set_coefficients(fspl_view); - auto fspl = - Rank3View(fspl_view.data(), 4, nx, ny); + auto fspl = Rank3View(fspl_view.data(), 4, nx, ny); Kokkos::parallel_for( Kokkos::MDRangePolicy>({0, 0}, {ny, nx}), - KOKKOS_LAMBDA(const LO ith, const LO ix) { - fspl(0, ix, ith) = values(ix * ny + ith); + KOKKOS_LAMBDA(const LO iy, const LO ix) { + fspl(0, ix, iy) = values(ix * ny + iy); }); Kokkos::View wk_view("wk", 9 * nx * ny); - auto wk = - Rank1View(wk_view.data(), 9 * nx * ny); + auto wk = Rank1View(wk_view.data(), 9 * nx * ny); solve_spline(x, this->nx_, y, this->ny_, fspl, ibcxmin, bcxmin, ibcxmax, bcxmax, ibcymin, bcymin, ibcymax, bcymax, wk); - this->f_ = fspl; // Store the spline coefficients + this->fspl_ = fspl; // Store the spline coefficients } template CompactBiCubicSplineInterpolator:: CompactBiCubicSplineInterpolator(Rank1View x, // size: inx - Rank1View y, // size: inth + Rank1View y, // size: iny Rank1View values) : CompactBiCubicSplineInterpolator(x, y, values, 0, {}, 0, {}, 0, {}, 0, {}) { // Delegates to primary constructor @@ -2009,10 +2012,10 @@ void CompactBiCubicSplineInterpolator::solve_spline( // Check if inhomogeneous y-boundary conditions exist if (ibcymin != -1) { - ExplicitBiCubicSplineInterpolator::correction_detect(bcymin, ibcymin, - iflg2, nx); - ExplicitBiCubicSplineInterpolator::correction_detect(bcymax, ibcymax, - iflg2, nx); + ExplicitBiCubicSplineInterpolator::correction_detect( + bcymin, ibcymin, iflg2, nx); + ExplicitBiCubicSplineInterpolator::correction_detect( + bcymax, ibcymax, iflg2, nx); } auto fspl_l_x = Rank2View(wk.data_handle(), 2 * ny, nx); @@ -2217,8 +2220,10 @@ CompactBiCubicSplineInterpolator::lookup( T zxget = xget; T zyget = yget; - ExplicitCubicSplineInterpolator::range_check(xget, zxget, x, nx, ier); - ExplicitCubicSplineInterpolator::range_check(yget, zyget, y, ny, ier); + ExplicitCubicSplineInterpolator::inGrid(xget, zxget, x, nx, + ier); + ExplicitCubicSplineInterpolator::inGrid(yget, zyget, y, ny, + ier); LO nxm = nx - 1; // Number of LOervals in x LO nym = ny - 1; // Number of LOervals in y From 8da6887f9d4b1c1dedc1bffbebe2eb968d9b8f92 Mon Sep 17 00:00:00 2001 From: Sichao25 Date: Tue, 5 Aug 2025 14:07:11 -0400 Subject: [PATCH 07/18] add documentation --- src/pcms/interpolator/spline_interpolator.hpp | 467 ++++++++++++++++-- 1 file changed, 436 insertions(+), 31 deletions(-) diff --git a/src/pcms/interpolator/spline_interpolator.hpp b/src/pcms/interpolator/spline_interpolator.hpp index bd16d4cf2..04b9ced34 100644 --- a/src/pcms/interpolator/spline_interpolator.hpp +++ b/src/pcms/interpolator/spline_interpolator.hpp @@ -75,30 +75,109 @@ void isUniformAscending(Rank1View x, const T &ztol) { // TODO: better documentation // TODO: add more checks/assetions for input parameters - +/** \brief ExplicitCubicSplineInterpolator class + * + * \details This class provides methods for 1d explicit cubic spline interpolation and serves as a base + * class for higher dimensions and compact cubic spline interpolator implementations. + * + * The 1d explicit cubic spline are evaluated using the following formula: + * s(x)=C(1,i)+(x-x(i))*C(2,i)+(x-x(i))**2*C(3,i)+(x-x(i))**3*C(4,i) + * for x(i).le.x.le.x(i+1) + * where C(1,i), C(2,i), C(3,i), and C(4,i) are the coefficients of the cubic spline. + * + * Performance considerations: The memory cost of coeeficients are: + * - explicit -- 4**dimension*(N1*N2*...*Nn) + * - compact -- 2**dimension*(N1*N2*...*Nn) + * Explicit spline representation offers better performance in 1D cases. (Compact representations actually + * call the explicit spline setup functions.) Compact spline representation provides performance advantages + * in higher dimensions due to memory efficiency gains that outweigh the modest increase in computational + * cost. + */ template class ExplicitCubicSplineInterpolator { public: using execution_space = typename MemorySpace::execution_space; using member_type = typename Kokkos::TeamPolicy::member_type; ExplicitCubicSplineInterpolator() = default; - + + /** \brief Construct the interpolator object and set up the coefficients + * + * \param x input grid points + * \param values values of given grid points + * \param ibcxmin bounday condition flag at x(0) + * \param bcxmin bounday condition data at x(0) + * \param ibcxmax bounday condition flag at x(-1) + * \param bcxmax bounday condition data at x(-1) + * + * \details The boundary condition flags can take the following values: + * ibcxmin=-1 | ibcxmax=-1 -- periodic boundary condition, where + * s'(x(0))=s'(x(-1)) and s''(x(0))=s''(x(-1)). + * ibcxmin=0 | ibcxmax=0 -- not-a-knot boundary condition. + * ibcxmin=1 | ibcxmax=1 -- first derivative match at x(0) or x(-1). + * ibcxmin=2 | ibcxmax=2 -- second derivative match at x(0) or x(-1). + * ibcxmin=3 | ibcxmax=3 -- first derivative equal to zero at x(0) or x(-1). + * ibcxmin=4 | ibcxmax=4 -- second derivative equal to zero at x(0) or x(-1). + * ibcxmin=5 | ibcxmax=5 -- first derivative matches the first divided difference. + * ibcxmin=6 | ibcxmax=6 -- second derivative matches the second divided difference. + * ibcxmin=7 | ibcxmax=7 -- third derivative matches the third divided difference. + */ ExplicitCubicSplineInterpolator(Rank1View x, Rank1View values, const LO &ibcxmin, const T &bcxmin, const LO &ibcxmax, const T &bcxmax); + + /** \brief Construct the interpolator object and set up the coefficients with default boundary conditions + * + * \param x input grid points + * \param values values of given grid points + * + * \details The boundary condition flags are set to 0, which corresponds to not-a-knot boundary condition. + */ ExplicitCubicSplineInterpolator(Rank1View x, Rank1View values); - + + /** \brief Evaluate the function value of cubic spline at given points + * + * \param xvec input points where the spline is evaluated + * \param fval output values of the spline at given points + * + * \details The size of fval should match the size of xvec. + */ void evaluate(Rank1View xvec, Rank2View fval); - + + /** \brief Evaluate the cubic spline at given points with selector + * + * \param selector selector array indicating which derivatives to compute + * \param xvec input points where the spline is evaluated + * \param fval output values of the spline at given points + * + * \details The size of fval should match the size of xvec and the size of selector. + * The selector array can be used to specify which derivatives to compute. For example, + * if selector = {1, 1, 0}, then the function value and first derivative will be computed. + */ void evaluate(Kokkos::View selector, Rank1View xvec, Rank2View fval); + /** \brief Evaluate the cubic spline at a single point with selector + * + * \param xget input point where the spline is evaluated + * \param selector selector array indicating which derivatives to compute + * \param fval output values of the spline at given point + * \param x input grid points + * \param nx number of grid points + * \param fspl spline coefficients + * \param ier error flag, 0 if successful, non-zero otherwise + * + * \details A static function that can be used to evaluate the cubic spline at a single point. + * Note that this function does nothing when tje input point is out of the grid range (ier is set to non-zero). + */ static KOKKOS_INLINE_FUNCTION void eval(T xget, Kokkos::View iselect, Rank1View fval, Rank1View x, const LO &nx, Rank2View fspl, LO &ier); + + /** \brief Set up the internal working space and coefficients + */ void setup(Rank1View x, const LO &nx, Rank1View values, const LO &ibcxmin, const T &bcxmin, const LO &ibcxmax, const T &bcxmax); @@ -117,6 +196,8 @@ class ExplicitCubicSplineInterpolator { static KOKKOS_INLINE_FUNCTION void inGrid(T &xget, T &zxget, Rank1View x, const LO &nx, LO &ier); + /** \brief Solve the cubic spline coefficients + */ static KOKKOS_FUNCTION void solve_spline(Rank1View x, const LO &nx, Rank2View fspl, @@ -126,17 +207,49 @@ class ExplicitCubicSplineInterpolator { private: Kokkos::View coefficients_; - + + /** \brief Evaluate the point given location in the grid + * + * \param selector selector array indicating which derivatives to compute + * \param fval output values of the spline at given points + * \param i index of the grid point + * \param dx displacement from the grid point + * \param fspl spline coefficients + */ static KOKKOS_INLINE_FUNCTION void evalfn(Kokkos::View selector, Rank1View fval, const LO &i, const T &dx, Rank2View fspl); - + + /** \brief Lookup the grid point and compute the displacement + * + * \param xget input point where the spline is evaluated + * \param x input grid points + * \param nx number of grid points + * \param i index of the grid point + * \param dx displacement from the grid point + * \param ier error flag, 0 if successful, non-zero otherwise + */ static KOKKOS_INLINE_FUNCTION void lookup(T xget, Rank1View x, const LO &nx, LO &i, T &dx, LO &ier); }; +/** + * CompactCubicSplineInterpolator class + * This class provides methods for 1d compact cubic spline interpolation. + * It inherits from ExplicitCubicSplineInterpolator and implements the + * compact representation of cubic spline coefficients. + * + * The 1d compact cubic spline are evaluated using the following formula: + * If x(i).le.x.le.x(i+1), let + * h = (x(i+1)-x(i)) + * p = (x-x(i))/h + * q = 1-p + * s(x)= q*D(1,i) + p*D(1,i+1) + + * (h**2/6)*{[q**3-q]*D(2,i) + [p**3-p]*D(2,i+1)} + * where D(1,i) and D(2,i) are the coefficients of the compact cubic spline. + */ template class CompactCubicSplineInterpolator : public ExplicitCubicSplineInterpolator { @@ -145,24 +258,71 @@ class CompactCubicSplineInterpolator typename ExplicitCubicSplineInterpolator::execution_space; using member_type = typename Kokkos::TeamPolicy::member_type; CompactCubicSplineInterpolator() = default; + /** \brief Construct the interpolator object and set up the coefficients + * + * \param x input grid points + * \param values values of given grid points + * \param ibcxmin bounday condition flag at x(0) + * \param bcxmin bounday condition data at x(0) + * \param ibcxmax bounday condition flag at x(-1) + * \param bcxmax bounday condition data at x(-1) + * + * \details The boundary condition flags can take the same values as in ExplicitCubicSplineInterpolator. + */ CompactCubicSplineInterpolator(Rank1View x, Rank1View values, const LO &ibcxmin, const T &bcxmin, const LO &ibcxmax, const T &bcxmax); + + /** \brief Construct the interpolator object and set up the coefficients with default boundary conditions + * + * \param x input grid points + * \param values values of given grid points + */ CompactCubicSplineInterpolator(Rank1View x, Rank1View values); + + /** \brief Set up the internal working space and coefficients + */ void setup(Rank1View x, const LO &nx, Rank1View values, const LO &ibcxmin, const T &bcxmin, const LO &ibcxmax, const T &bcxmax); + + /** \brief Evaluate the function value of compact cubic spline at given points + * + * \param xvec input points where the spline is evaluated + * \param fval output values of the spline at given points + */ void evaluate(Rank1View xvec, Rank2View fval); + /** \brief Evaluate the compact cubic spline at given points with selector + * + * \param selector selector array indicating which derivatives to compute + * \param xvec input points where the spline is evaluated + * \param fval output values of the spline at given points + * + * \details The selector follows the same rules as in ExplicitCubicSplineInterpolator. + */ void evaluate(Kokkos::View selector, Rank1View xvec, Rank2View fval); + + /** \brief Evaluate the compact cubic spline at a single point with selector + * + * \param xget input point where the spline is evaluated + * \param ict selector array indicating which derivatives to compute + * \param fval output values of the spline at given point + * \param x input grid points + * \param nx number of grid points + * \param fs2 compact spline coefficients + * \param ier error flag, 0 if successful, non-zero otherwise + */ static KOKKOS_INLINE_FUNCTION void eval(T xget, Kokkos::View ict, Rank1View fval, Rank1View x, const LO &nx, Rank2View fs2, LO &ier); + /** \brief Solve the cubic spline coefficients + */ static KOKKOS_FUNCTION void solve_spline(Rank1View x, const LO &nx, Rank2View fspl, Rank2View fspl4, @@ -170,16 +330,48 @@ class CompactCubicSplineInterpolator const T &bcxmax, Rank1View wk); protected: + /** \brief Evaluate the point given location in the grid + * + * \param selector selector array indicating which derivatives to compute + * \param fval output values of the spline at given points + * \param i index of the grid point + * \param xparam displacement from the grid point + * \param hx step size in the x direction + * \param hxi inverse step size in the x direction + * \param fs2 compact spline coefficients + */ static KOKKOS_INLINE_FUNCTION void evalfn(Kokkos::View selector, Rank1View fval, const LO &i, const T &xparam, const T &hx, const T &hxi, Rank2View fs2); + /** \brief Lookup the grid point and compute the displacement + * + * \param xget input point where the spline is evaluated + * \param x input grid points + * \param nx number of grid points + * \param i index of the grid point + * \param xparam displacement from the grid point + * \param hx step size in the x direction + * \param hxi inverse step size in the x direction + * \param ier error flag, 0 if successful, non-zero otherwise + */ static KOKKOS_INLINE_FUNCTION void lookup(T xget, Rank1View x, const LO &nx, LO &i, T &xparam, T &hx, T &hxi, LO &ier); }; +/** \brief BiCubicSplineInterpolator class + * This class provides methods for 2D explicit bicubic spline interpolation. + * It inherits from ExplicitCubicSplineInterpolator and implements the bicubic representation of cubic spline coefficients. + * + * The 2D explicit bicubic spline are evaluated using the following formula: + * s(x,y)= C11 + dx*C21 + dx**2*C31 + dx**3*C41 + * +dy*(C12 + dx*C22 + dx**2*C32 + dx**3*C42) + * +dy**2*(C13 + dx*C23 + dx**2*C33 + dx**3*C43) + * +dy**3*(C14 + dx*C24 + dx**2*C34 + dx**3*C44) + * where Cij are the coefficients of the bicubic spline. + */ template class ExplicitBiCubicSplineInterpolator : public ExplicitCubicSplineInterpolator { @@ -190,33 +382,60 @@ class ExplicitBiCubicSplineInterpolator ExplicitBiCubicSplineInterpolator() = default; + /** \brief Construct the interpolator object and set up the coefficients + * + * \param x input grid points in x direction + * \param y input grid points in y direction + * \param values values of given grid points + * \param ibcxmin boundary condition flag at x(0) + * \param bcxmin boundary condition data at x(0) + * \param ibcxmax boundary condition flag at x(-1) + * \param bcxmax boundary condition data at x(-1) + * \param ibcymin boundary condition flag at y(0) + * \param bcymin boundary condition data at y(0) + * \param ibcymax boundary condition flag at y(-1) + * \param bcymax boundary condition data at y(-1) + * + * \details The boundary condition flags take the same values as in ExplicitCubicSplineInterpolator + * at each direction. + */ ExplicitBiCubicSplineInterpolator( - Rank1View x, // size: inx - Rank1View y, // size: iny + Rank1View x, + Rank1View y, Rank1View values, LO ibcxmin, - Rank1View bcxmin, // size: iny (used if ibcxmin = 1 or 2) + Rank1View bcxmin, LO ibcxmax, - Rank1View bcxmax, // size: iny (used if ibcxmax = 1 or 2) + Rank1View bcxmax, LO ibcymin, - Rank1View bcymin, // size: inx (used if ibcymin = 1 or 2) + Rank1View bcymin, LO ibcymax, Rank1View bcymax); - ExplicitBiCubicSplineInterpolator(Rank1View x, // size: inx - Rank1View y, // size: iny + /** \brief Construct the interpolator object and set up the coefficients with default boundary conditions + * + * \param x input grid points in x direction + * \param y input grid points in y direction + * \param values values of given grid points + */ + ExplicitBiCubicSplineInterpolator(Rank1View x, + Rank1View y, Rank1View values); + /** \brief Set up the internal working space and coefficients + */ void setup( - Rank1View x, // size: inx - Rank1View y, // size: iny + Rank1View x, + Rank1View y, Rank1View values, LO ibcxmin, - Rank1View bcxmin, // size: iny (used if ibcxmin = 1 or 2) + Rank1View bcxmin, LO ibcxmax, - Rank1View bcxmax, // size: iny (used if ibcxmax = 1 or 2) + Rank1View bcxmax, LO ibcymin, - Rank1View bcymin, // size: inx (used if ibcymin = 1 or 2) + Rank1View bcymin, LO ibcymax, - Rank1View bcymax // size: inx (used if ibcymax = 1 or 2) + Rank1View bcymax ); + /** \brief Solve the coefficients of the bicubic spline + */ static void solve_spline( Rank1View x, // size: inx LO inx, Rank1View y, // size: iny @@ -232,18 +451,63 @@ class ExplicitBiCubicSplineInterpolator Rank1View wk // size: nwk ); + /** \brief Detect if the boundary conditions are homogeneous + * + * \param bcmin boundary condition data + * \param ibcmin boundary condition flag + * \param iflg2 flag indicating if the boundary conditions are + * \param nx number of grid points in x direction + * + * \details A homogeneous boundary condition set A has the property that if + * s1(x,y) satisfies A, then (for any real number c) c*S1 also satisfies A, + * and, if both s1(x,y) and s2(x,y) satisfy A then so also does s1+s2. + */ static void correction_detect(Rank1View bcmin, LO &ibcmin, LO &iflg2, LO &nx); + /** \brief Evaluate the bicubic spline at a single point with selector + * + * \param xget input point in x direction where the spline is evaluated + * \param yget input point in y direction where the spline is evaluated + * \param iselect selector array indicating which derivatives to compute + * \param fval output values of the spline at given point + * \param x input grid points in x direction + * \param nx number of grid points in x direction + * \param y input grid points in y direction + * \param ny number of grid points in y direction + * \param fspl bicubic spline coefficients + * \param ier error flag, 0 if successful, non-zero otherwise + */ static KOKKOS_INLINE_FUNCTION void eval(T xget, T yget, Kokkos::View iselect, Rank1View fval, Rank1View x, const LO &nx, Rank1View y, const LO &ny, Rank4View fspl, LO &ier); + /** \brief Evaluate the bicubic spline at given points + * + * \param xvec input points in x direction where the spline is evaluated + * \param yvec input points in y direction where the spline is evaluated + * \param fval output values of the spline at given points + */ void evaluate(Rank1View xvec, Rank1View yvec, Rank2View fval); + /** \brief Evaluate the bicubic spline at given points with selector + * + * \param iselect selector array indicating which derivatives to compute + * \param xvec input points in x direction where the spline is evaluated + * \param yvec input points in y direction where the spline is evaluated + * \param fval output values of the spline at given points + * + * \details The selector follows the the following rules: + * iselect(1)=1 -- evaluate f + * iselect(2)=1 -- evaluate df/dx + * iselect(3)=1 -- evaluate df/dy + * iselect(4)=1 -- evaluate d2f/dx2 + * iselect(5)=1 -- evaluate d2f/dy2 + * iselect(6)=1 -- evaluate d2f/dxdy + */ void evaluate(Kokkos::View iselect, Rank1View xvec, Rank1View yvec, Rank2View fval); @@ -260,23 +524,67 @@ class ExplicitBiCubicSplineInterpolator Rank1View bcymax); private: + /** \brief Lookup the grid point and compute the displacement + * + * \param xget input point in x direction where the spline is evaluated + * \param yget input point in y direction where the spline is evaluated + * \param x input grid points in x direction + * \param nx number of grid points in x direction + * \param y input grid points in y direction + * \param ny number of grid points in y direction + * \param i index of the grid point in x direction + * \param j index of the grid point in y direction + * \param dx displacement from the grid point in x direction + * \param dy displacement from the grid point in y direction + * \param ier error flag, 0 if successful, non-zero otherwise + */ static KOKKOS_INLINE_FUNCTION void lookup(T xget, T yget, Rank1View x, const LO &nx, Rank1View y, const LO &ny, LO &i, LO &j, T &dx, T &dy, LO &ier); + /** \brief Evaluate the bicubic spline at given grid cell + * + * \param ict selector array indicating which derivatives to compute + * \param fval output values of the spline at given grid cell + * \param i index of the grid cell in x direction + * \param j index of the grid cell in y direction + * \param dx displacement from the grid cell in x direction + * \param dy displacement from the grid cell in y direction + * \param fspl bicubic spline coefficients + */ static KOKKOS_INLINE_FUNCTION void evalfn( - Kokkos::View - ict, // Selector array for which derivatives to compute - Rank1View fval, // Output array: size [ivd, *] (flattened) - const LO &i, // Grid cell indices in x direction - const LO &j, // Grid cell indices in y direction - const T &dx, // x displacements within cells - const T &dy, // y displacements within cells - Rank4View fspl // Spline coefficients: [4, 4, nx, ny] + Kokkos::View ict, + Rank1View fval, + const LO &i, + const LO &j, + const T &dx, + const T &dy, + Rank4View fspl ); }; +/** \brief CompactBiCubicSplineInterpolator class + * This class provides methods for 2D compact bicubic spline interpolation. + * It inherits from ExplicitBiCubicSplineInterpolator and implements the compact representation of bicubic spline coefficients. + * + * The 2D compact bicubic spline are evaluated using the following formula: + * for x(i).le.x.le.x(i+1) and y(j).le.y.le.y(j+1), let + * hx = x(i+1)-x(i) hy = y(j+1)-y(j) + * px = (x-x(i))/hx py = (y-y(j))/hy + * qx = 1-px qy = 1-py + * rx = (px**3-px) ry = (py**3-py) + * sx = (qx**3-qx) sy = (qy**3-qy) + * + * s(x,y) = qx*(qy*D(1,i,j)+py*D(1,i,j+1)) + + * px*(qy*D(1,i+1,j)+py*D(1,i+1,j+1)) + + * (hx**2/6)*{sx*(qy*D(2,i,j)+py*D(2,i,j+1)) + + * rx*(qy*D(2,i+1,j)+py*D(2,i+1,j+1))} + + * (hy**2/6)*{qx*(sy*D(3,i,j)+ry*D(3,i,j+1)) + + * px*(sy*D(3,i+1,j)+ry*D(3,i+1,j+1))} + + * (hx**2*hy**2/36)*{sx*(sy*D(4,i,j)+ry*D(4,i,j+1)) + + * rx*(sy*D(4,i+1,j)+ry*D(4,i+1,j+1))} + */ template class CompactBiCubicSplineInterpolator : public ExplicitBiCubicSplineInterpolator { @@ -287,6 +595,23 @@ class CompactBiCubicSplineInterpolator CompactBiCubicSplineInterpolator() = default; + /** \brief Construct the interpolator object and set up the coefficients + * + * \param x input grid points in x direction + * \param y input grid points in y direction + * \param values values of given grid points + * \param ibcxmin boundary condition flag at x(0) + * \param bcxmin boundary condition data at x(0) + * \param ibcxmax boundary condition flag at x(-1) + * \param bcxmax boundary condition data at x(-1) + * \param ibcymin boundary condition flag at y(0) + * \param bcymin boundary condition data at y(0) + * \param ibcymax boundary condition flag at y(-1) + * \param bcymax boundary condition data at y(-1) + * + * \details The boundary condition flags take the same values as in ExplicitCubicSplineInterpolator + * at each direction. + */ CompactBiCubicSplineInterpolator(Rank1View x, Rank1View y, Rank1View values, LO ibcxmin, @@ -295,10 +620,17 @@ class CompactBiCubicSplineInterpolator Rank1View bcymin, LO ibcymax, Rank1View bcymax); + /** \brief Construct the interpolator object and set up the coefficients with default boundary conditions + * \param x input grid points in x direction + * \param y input grid points in y direction + * \param values values of given grid points + */ CompactBiCubicSplineInterpolator(Rank1View x, Rank1View y, Rank1View values); + /** \brief Set up the internal working space and coefficients + */ void setup(Rank1View x, Rank1View y, Rank1View values, LO ibcxmin, Rank1View bcxmin, LO ibcxmax, @@ -306,6 +638,8 @@ class CompactBiCubicSplineInterpolator Rank1View bcymin, LO ibcymax, Rank1View bcymax); + /** \brief Solve the coefficients of the compact bicubic spline + */ static void solve_spline(Rank1View x, LO nx, Rank1View y, LO ny, Rank3View f, LO ibcxmin, @@ -315,15 +649,43 @@ class CompactBiCubicSplineInterpolator Rank1View bcymax, Rank1View wk); + /** \brief Evaluate the bicubic spline at a single point with selector + * + * \param xget input point in x direction where the spline is evaluated + * \param yget input point in y direction where the spline is evaluated + * \param ict selector array indicating which derivatives to compute + * \param fval output values of the spline at given point + * \param x input grid points in x direction + * \param nx number of grid points in x direction + * \param y input grid points in y direction + * \param ny number of grid points in y direction + * \param f bicubic spline coefficients + * \param ier error flag, 0 if successful, non-zero otherwise + */ static KOKKOS_INLINE_FUNCTION void eval(T xget, T yget, Kokkos::View ict, Rank1View fval, // output (size depends on ict) Rank1View x, const LO &nx, Rank1View y, const LO &ny, Rank3View f, LO &ier); + /** \brief Evaluate the bicubic spline at given points + * + * \param xvec input points in x direction where the spline is evaluated + * \param yvec input points in y direction where the spline is evaluated + * \param fval output values of the spline at given points + */ void evaluate(Rank1View xvec, Rank1View yvec, Rank2View fval); + /** \brief Evaluate the bicubic spline at given points with selector + * + * \param iselect selector array indicating which derivatives to compute + * \param xvec input points in x direction where the spline is evaluated + * \param yvec input points in y direction where the spline is evaluated + * \param fval output values of the spline at given points + * + * \details The selector follows the same rules as in ExplicitBiCubicSplineInterpolator. + */ void evaluate(Kokkos::View iselect, Rank1View xvec, Rank1View yvec, Rank2View fval); @@ -332,11 +694,43 @@ class CompactBiCubicSplineInterpolator Rank3View fspl_; private: + /** \brief Lookup the grid point and compute the displacement + * + * \param xget input point in x direction where the spline is evaluated + * \param yget input point in y direction where the spline is evaluated + * \param x input grid points in x direction + * \param nx number of grid points in x direction + * \param y input grid points in y direction + * \param ny number of grid points in y direction + * \param i index of the grid point in x direction + * \param j index of the grid point in y direction + * \param xparam displacement from the grid point in x direction + * \param hx step size in the x direction + * \param hxi inverse step size in the x direction + * \param yparam displacement from the grid point in y direction + * \param hy step size in the y direction + * \param hyi inverse step size in the y direction + * \param ier error flag, 0 if successful, non-zero otherwise + */ static KOKKOS_INLINE_FUNCTION void lookup(T xget, T yget, Rank1View x, const LO &nx, Rank1View y, const LO &ny, LO &i, LO &j, T &xparam, T &yparam, T &hx, T &hxi, T &hy, T &hyi, LO &ier); + /** \brief Evaluate the bicubic spline at given grid cell + * + * /param ict selector array indicating which derivatives to compute + * \param fval output values of the spline at given grid cell + * \param i index of the grid cell in x direction + * \param j index of the grid cell in y direction + * \param xparam displacement from the grid cell in x direction + * \param yparam displacement from the grid cell in y direction + * \param hx step size in the x direction + * \param hxi inverse step size in the x direction + * \param hy step size in the y direction + * \param hyi inverse step size in the y direction + * \param f bicubic spline coefficients + */ static KOKKOS_INLINE_FUNCTION void evalfn(Kokkos::View ict, LO ivec, LO ivecd, Rank1View fval, const LO &i, const LO &j, @@ -476,6 +870,17 @@ void CompactCubicSplineInterpolator::setup( this->fspl_ = fspl; } +/** \brief Solve for 1d spline coefficients. + * + * \param k_bc1 boundary condition flag at x(0) + * \param k_bcn boundary condition flag at x(-1) + * \param n number of grid points + * \param x input grid points + * \param f output coefficients of the cubic spline + * \param wk working space for the spline solver + * + * \details Originally developed by Wayne Houlberg in Fortran. + */ template KOKKOS_FUNCTION void v_spline(const LO &k_bc1, const LO &k_bcn, const LO &n, Rank1View x, @@ -1647,8 +2052,8 @@ template void ExplicitBiCubicSplineInterpolator::evaluate( Rank1View xvec, Rank1View yvec, Rank2View fval) { - LO ict_arr[10] = {1, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - Kokkos::View ict("select", 10); + LO ict_arr[6] = {1, 0, 0, 0, 0, 0}; + Kokkos::View ict("select", 6); Kokkos::parallel_for( Kokkos::RangePolicy(0, ict.size()), KOKKOS_LAMBDA(const LO i) { ict(i) = ict_arr[i]; }); @@ -1678,8 +2083,8 @@ template void CompactBiCubicSplineInterpolator::evaluate( Rank1View xvec, Rank1View yvec, Rank2View fval) { - LO ict_arr[10] = {1, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - Kokkos::View ict("select", 10); + LO ict_arr[6] = {1, 0, 0, 0, 0, 0}; + Kokkos::View ict("select", 6); Kokkos::parallel_for( Kokkos::RangePolicy(0, ict.size()), KOKKOS_LAMBDA(const LO i) { ict(i) = ict_arr[i]; }); From 3f23fa444878bb19781e1948cc771f165a2d5130 Mon Sep 17 00:00:00 2001 From: Sichao25 Date: Wed, 6 Aug 2025 13:38:17 -0400 Subject: [PATCH 08/18] remove duplicate declarations merged from develop --- src/pcms/arrays.h | 6 +++++ src/pcms/interpolator/spline_interpolator.hpp | 25 ------------------- 2 files changed, 6 insertions(+), 25 deletions(-) diff --git a/src/pcms/arrays.h b/src/pcms/arrays.h index f9884073f..3cc4a5c6f 100644 --- a/src/pcms/arrays.h +++ b/src/pcms/arrays.h @@ -41,6 +41,12 @@ using Rank1View = View<1, ElementType, MemorySpace>; template using Rank2View = View<2, ElementType, MemorySpace>; +template +using Rank3View = View<3, ElementType, MemorySpace>; + +template +using Rank4View = View<4, ElementType, MemorySpace>; + template using GlobalIDView = Rank1View; diff --git a/src/pcms/interpolator/spline_interpolator.hpp b/src/pcms/interpolator/spline_interpolator.hpp index 04b9ced34..51afade3b 100644 --- a/src/pcms/interpolator/spline_interpolator.hpp +++ b/src/pcms/interpolator/spline_interpolator.hpp @@ -11,31 +11,6 @@ namespace pcms { -// Todo: remove this once target PR is merged -// Declaration of customized Kokkos types copied from existing PR -template -struct memory_space_accessor : public Kokkos::default_accessor { - using memory_space = MemorySpace; -}; - -template -using View = Kokkos::mdspan< - ElementType, Kokkos::dextents, Kokkos::layout_right, - detail::memory_space_accessor, - MemorySpace>>; - -template -using Rank1View = View<1, ElementType, MemorySpace>; - -template -using Rank2View = View<2, ElementType, MemorySpace>; - -template -using Rank3View = View<3, ElementType, MemorySpace>; - -template -using Rank4View = View<4, ElementType, MemorySpace>; - void ibc_check(LO ibc, const std::string &slbl, const std::string &xlbl, LO imin, LO imax) { From a392ad75aea2b16d1623524c9a402ac890e0feb7 Mon Sep 17 00:00:00 2001 From: Sichao25 Date: Wed, 20 Aug 2025 22:23:27 -0400 Subject: [PATCH 09/18] reorganize member function --- src/pcms/interpolator/spline_interpolator.hpp | 3388 ++++++++--------- test/test_spline_interpolator.cpp | 22 +- 2 files changed, 1708 insertions(+), 1702 deletions(-) diff --git a/src/pcms/interpolator/spline_interpolator.hpp b/src/pcms/interpolator/spline_interpolator.hpp index 51afade3b..8b1995cf5 100644 --- a/src/pcms/interpolator/spline_interpolator.hpp +++ b/src/pcms/interpolator/spline_interpolator.hpp @@ -11,6 +11,8 @@ namespace pcms { +namespace detail { + void ibc_check(LO ibc, const std::string &slbl, const std::string &xlbl, LO imin, LO imax) { @@ -48,686 +50,44 @@ void isUniformAscending(Rank1View x, const T &ztol) { }); } -// TODO: better documentation -// TODO: add more checks/assetions for input parameters -/** \brief ExplicitCubicSplineInterpolator class - * - * \details This class provides methods for 1d explicit cubic spline interpolation and serves as a base - * class for higher dimensions and compact cubic spline interpolator implementations. - * - * The 1d explicit cubic spline are evaluated using the following formula: - * s(x)=C(1,i)+(x-x(i))*C(2,i)+(x-x(i))**2*C(3,i)+(x-x(i))**3*C(4,i) - * for x(i).le.x.le.x(i+1) - * where C(1,i), C(2,i), C(3,i), and C(4,i) are the coefficients of the cubic spline. - * - * Performance considerations: The memory cost of coeeficients are: - * - explicit -- 4**dimension*(N1*N2*...*Nn) - * - compact -- 2**dimension*(N1*N2*...*Nn) - * Explicit spline representation offers better performance in 1D cases. (Compact representations actually - * call the explicit spline setup functions.) Compact spline representation provides performance advantages - * in higher dimensions due to memory efficiency gains that outweigh the modest increase in computational - * cost. - */ -template -class ExplicitCubicSplineInterpolator { -public: - using execution_space = typename MemorySpace::execution_space; - using member_type = typename Kokkos::TeamPolicy::member_type; - ExplicitCubicSplineInterpolator() = default; - - /** \brief Construct the interpolator object and set up the coefficients - * - * \param x input grid points - * \param values values of given grid points - * \param ibcxmin bounday condition flag at x(0) - * \param bcxmin bounday condition data at x(0) - * \param ibcxmax bounday condition flag at x(-1) - * \param bcxmax bounday condition data at x(-1) - * - * \details The boundary condition flags can take the following values: - * ibcxmin=-1 | ibcxmax=-1 -- periodic boundary condition, where - * s'(x(0))=s'(x(-1)) and s''(x(0))=s''(x(-1)). - * ibcxmin=0 | ibcxmax=0 -- not-a-knot boundary condition. - * ibcxmin=1 | ibcxmax=1 -- first derivative match at x(0) or x(-1). - * ibcxmin=2 | ibcxmax=2 -- second derivative match at x(0) or x(-1). - * ibcxmin=3 | ibcxmax=3 -- first derivative equal to zero at x(0) or x(-1). - * ibcxmin=4 | ibcxmax=4 -- second derivative equal to zero at x(0) or x(-1). - * ibcxmin=5 | ibcxmax=5 -- first derivative matches the first divided difference. - * ibcxmin=6 | ibcxmax=6 -- second derivative matches the second divided difference. - * ibcxmin=7 | ibcxmax=7 -- third derivative matches the third divided difference. - */ - ExplicitCubicSplineInterpolator(Rank1View x, - Rank1View values, - const LO &ibcxmin, const T &bcxmin, - const LO &ibcxmax, const T &bcxmax); - - /** \brief Construct the interpolator object and set up the coefficients with default boundary conditions - * - * \param x input grid points - * \param values values of given grid points - * - * \details The boundary condition flags are set to 0, which corresponds to not-a-knot boundary condition. - */ - ExplicitCubicSplineInterpolator(Rank1View x, - Rank1View values); - - /** \brief Evaluate the function value of cubic spline at given points - * - * \param xvec input points where the spline is evaluated - * \param fval output values of the spline at given points - * - * \details The size of fval should match the size of xvec. - */ - void evaluate(Rank1View xvec, Rank2View fval); - - /** \brief Evaluate the cubic spline at given points with selector - * - * \param selector selector array indicating which derivatives to compute - * \param xvec input points where the spline is evaluated - * \param fval output values of the spline at given points - * - * \details The size of fval should match the size of xvec and the size of selector. - * The selector array can be used to specify which derivatives to compute. For example, - * if selector = {1, 1, 0}, then the function value and first derivative will be computed. - */ - void evaluate(Kokkos::View selector, - Rank1View xvec, Rank2View fval); - - /** \brief Evaluate the cubic spline at a single point with selector - * - * \param xget input point where the spline is evaluated - * \param selector selector array indicating which derivatives to compute - * \param fval output values of the spline at given point - * \param x input grid points - * \param nx number of grid points - * \param fspl spline coefficients - * \param ier error flag, 0 if successful, non-zero otherwise - * - * \details A static function that can be used to evaluate the cubic spline at a single point. - * Note that this function does nothing when tje input point is out of the grid range (ier is set to non-zero). - */ - static KOKKOS_INLINE_FUNCTION void - eval(T xget, Kokkos::View iselect, - Rank1View fval, Rank1View x, - const LO &nx, Rank2View fspl, LO &ier); - - /** \brief Set up the internal working space and coefficients - */ - void setup(Rank1View x, const LO &nx, - Rank1View values, const LO &ibcxmin, - const T &bcxmin, const LO &ibcxmax, const T &bcxmax); - -protected: - Rank1View x_; - LO nx_; - Rank2View fspl_; - - Kokkos::View get_coefficients(); - void set_coefficients(Kokkos::View coefficients); - - void sanity_check(Rank1View x, const LO &ibcxmin, - const T &bcxmin, const LO &ibcxmax, const T &bcxmax); - - static KOKKOS_INLINE_FUNCTION void - inGrid(T &xget, T &zxget, Rank1View x, const LO &nx, LO &ier); - - /** \brief Solve the cubic spline coefficients - */ - static KOKKOS_FUNCTION void solve_spline(Rank1View x, - const LO &nx, - Rank2View fspl, - const LO &ibcxmin, const T &bcxmin, - const LO &ibcxmax, const T &bcxmax, - Rank1View wk); - -private: - Kokkos::View coefficients_; - - /** \brief Evaluate the point given location in the grid - * - * \param selector selector array indicating which derivatives to compute - * \param fval output values of the spline at given points - * \param i index of the grid point - * \param dx displacement from the grid point - * \param fspl spline coefficients - */ - static KOKKOS_INLINE_FUNCTION void - evalfn(Kokkos::View selector, - Rank1View fval, const LO &i, const T &dx, - Rank2View fspl); - - /** \brief Lookup the grid point and compute the displacement - * - * \param xget input point where the spline is evaluated - * \param x input grid points - * \param nx number of grid points - * \param i index of the grid point - * \param dx displacement from the grid point - * \param ier error flag, 0 if successful, non-zero otherwise - */ - static KOKKOS_INLINE_FUNCTION void lookup(T xget, Rank1View x, - const LO &nx, LO &i, T &dx, - LO &ier); -}; - -/** - * CompactCubicSplineInterpolator class - * This class provides methods for 1d compact cubic spline interpolation. - * It inherits from ExplicitCubicSplineInterpolator and implements the - * compact representation of cubic spline coefficients. - * - * The 1d compact cubic spline are evaluated using the following formula: - * If x(i).le.x.le.x(i+1), let - * h = (x(i+1)-x(i)) - * p = (x-x(i))/h - * q = 1-p - * s(x)= q*D(1,i) + p*D(1,i+1) + - * (h**2/6)*{[q**3-q]*D(2,i) + [p**3-p]*D(2,i+1)} - * where D(1,i) and D(2,i) are the coefficients of the compact cubic spline. - */ -template -class CompactCubicSplineInterpolator - : public ExplicitCubicSplineInterpolator { -public: - using - typename ExplicitCubicSplineInterpolator::execution_space; - using member_type = typename Kokkos::TeamPolicy::member_type; - CompactCubicSplineInterpolator() = default; - /** \brief Construct the interpolator object and set up the coefficients - * - * \param x input grid points - * \param values values of given grid points - * \param ibcxmin bounday condition flag at x(0) - * \param bcxmin bounday condition data at x(0) - * \param ibcxmax bounday condition flag at x(-1) - * \param bcxmax bounday condition data at x(-1) - * - * \details The boundary condition flags can take the same values as in ExplicitCubicSplineInterpolator. - */ - CompactCubicSplineInterpolator(Rank1View x, - Rank1View values, - const LO &ibcxmin, const T &bcxmin, - const LO &ibcxmax, const T &bcxmax); - - /** \brief Construct the interpolator object and set up the coefficients with default boundary conditions - * - * \param x input grid points - * \param values values of given grid points - */ - CompactCubicSplineInterpolator(Rank1View x, - Rank1View values); - - /** \brief Set up the internal working space and coefficients - */ - void setup(Rank1View x, const LO &nx, - Rank1View values, const LO &ibcxmin, - const T &bcxmin, const LO &ibcxmax, const T &bcxmax); - - /** \brief Evaluate the function value of compact cubic spline at given points - * - * \param xvec input points where the spline is evaluated - * \param fval output values of the spline at given points - */ - void evaluate(Rank1View xvec, Rank2View fval); - - /** \brief Evaluate the compact cubic spline at given points with selector - * - * \param selector selector array indicating which derivatives to compute - * \param xvec input points where the spline is evaluated - * \param fval output values of the spline at given points - * - * \details The selector follows the same rules as in ExplicitCubicSplineInterpolator. - */ - void evaluate(Kokkos::View selector, - Rank1View xvec, Rank2View fval); - - /** \brief Evaluate the compact cubic spline at a single point with selector - * - * \param xget input point where the spline is evaluated - * \param ict selector array indicating which derivatives to compute - * \param fval output values of the spline at given point - * \param x input grid points - * \param nx number of grid points - * \param fs2 compact spline coefficients - * \param ier error flag, 0 if successful, non-zero otherwise - */ - static KOKKOS_INLINE_FUNCTION void - eval(T xget, Kokkos::View ict, - Rank1View fval, Rank1View x, - const LO &nx, Rank2View fs2, LO &ier); - - /** \brief Solve the cubic spline coefficients - */ - static KOKKOS_FUNCTION void - solve_spline(Rank1View x, const LO &nx, - Rank2View fspl, Rank2View fspl4, - const LO &ibcxmin, const T &bcxmin, const LO &ibcxmax, - const T &bcxmax, Rank1View wk); - -protected: - /** \brief Evaluate the point given location in the grid - * - * \param selector selector array indicating which derivatives to compute - * \param fval output values of the spline at given points - * \param i index of the grid point - * \param xparam displacement from the grid point - * \param hx step size in the x direction - * \param hxi inverse step size in the x direction - * \param fs2 compact spline coefficients - */ - static KOKKOS_INLINE_FUNCTION void - evalfn(Kokkos::View selector, - Rank1View fval, const LO &i, const T &xparam, - const T &hx, const T &hxi, Rank2View fs2); - - /** \brief Lookup the grid point and compute the displacement - * - * \param xget input point where the spline is evaluated - * \param x input grid points - * \param nx number of grid points - * \param i index of the grid point - * \param xparam displacement from the grid point - * \param hx step size in the x direction - * \param hxi inverse step size in the x direction - * \param ier error flag, 0 if successful, non-zero otherwise - */ - static KOKKOS_INLINE_FUNCTION void lookup(T xget, Rank1View x, - const LO &nx, LO &i, T &xparam, - T &hx, T &hxi, LO &ier); -}; - -/** \brief BiCubicSplineInterpolator class - * This class provides methods for 2D explicit bicubic spline interpolation. - * It inherits from ExplicitCubicSplineInterpolator and implements the bicubic representation of cubic spline coefficients. - * - * The 2D explicit bicubic spline are evaluated using the following formula: - * s(x,y)= C11 + dx*C21 + dx**2*C31 + dx**3*C41 - * +dy*(C12 + dx*C22 + dx**2*C32 + dx**3*C42) - * +dy**2*(C13 + dx*C23 + dx**2*C33 + dx**3*C43) - * +dy**3*(C14 + dx*C24 + dx**2*C34 + dx**3*C44) - * where Cij are the coefficients of the bicubic spline. - */ template -class ExplicitBiCubicSplineInterpolator - : public ExplicitCubicSplineInterpolator { -public: - using - typename ExplicitCubicSplineInterpolator::execution_space; - using member_type = typename Kokkos::TeamPolicy::member_type; - - ExplicitBiCubicSplineInterpolator() = default; - - /** \brief Construct the interpolator object and set up the coefficients - * - * \param x input grid points in x direction - * \param y input grid points in y direction - * \param values values of given grid points - * \param ibcxmin boundary condition flag at x(0) - * \param bcxmin boundary condition data at x(0) - * \param ibcxmax boundary condition flag at x(-1) - * \param bcxmax boundary condition data at x(-1) - * \param ibcymin boundary condition flag at y(0) - * \param bcymin boundary condition data at y(0) - * \param ibcymax boundary condition flag at y(-1) - * \param bcymax boundary condition data at y(-1) - * - * \details The boundary condition flags take the same values as in ExplicitCubicSplineInterpolator - * at each direction. - */ - ExplicitBiCubicSplineInterpolator( - Rank1View x, - Rank1View y, - Rank1View values, LO ibcxmin, - Rank1View bcxmin, - LO ibcxmax, - Rank1View bcxmax, - LO ibcymin, - Rank1View bcymin, - LO ibcymax, Rank1View bcymax); - - /** \brief Construct the interpolator object and set up the coefficients with default boundary conditions - * - * \param x input grid points in x direction - * \param y input grid points in y direction - * \param values values of given grid points - */ - ExplicitBiCubicSplineInterpolator(Rank1View x, - Rank1View y, - Rank1View values); - /** \brief Set up the internal working space and coefficients - */ - void setup( - Rank1View x, - Rank1View y, - Rank1View values, LO ibcxmin, - Rank1View bcxmin, - LO ibcxmax, - Rank1View bcxmax, - LO ibcymin, - Rank1View bcymin, - LO ibcymax, - Rank1View bcymax - ); - - /** \brief Solve the coefficients of the bicubic spline - */ - static void solve_spline( - Rank1View x, // size: inx - LO inx, Rank1View y, // size: iny - LO iny, Rank4View fspl, // [4, 4, inx, iny] - LO ibcxmin, - Rank1View bcxmin, // size: iny (used if ibcxmin = 1 or 2) - LO ibcxmax, - Rank1View bcxmax, // size: iny (used if ibcxmax = 1 or 2) - LO ibcymin, - Rank1View bcymin, // size: inx (used if ibcymin = 1 or 2) - LO ibcymax, - Rank1View bcymax, // size: inx (used if ibcymax = 1 or 2) - Rank1View wk // size: nwk - ); - - /** \brief Detect if the boundary conditions are homogeneous - * - * \param bcmin boundary condition data - * \param ibcmin boundary condition flag - * \param iflg2 flag indicating if the boundary conditions are - * \param nx number of grid points in x direction - * - * \details A homogeneous boundary condition set A has the property that if - * s1(x,y) satisfies A, then (for any real number c) c*S1 also satisfies A, - * and, if both s1(x,y) and s2(x,y) satisfy A then so also does s1+s2. - */ - static void correction_detect(Rank1View bcmin, LO &ibcmin, - LO &iflg2, LO &nx); - - /** \brief Evaluate the bicubic spline at a single point with selector - * - * \param xget input point in x direction where the spline is evaluated - * \param yget input point in y direction where the spline is evaluated - * \param iselect selector array indicating which derivatives to compute - * \param fval output values of the spline at given point - * \param x input grid points in x direction - * \param nx number of grid points in x direction - * \param y input grid points in y direction - * \param ny number of grid points in y direction - * \param fspl bicubic spline coefficients - * \param ier error flag, 0 if successful, non-zero otherwise - */ - static KOKKOS_INLINE_FUNCTION void - eval(T xget, T yget, Kokkos::View iselect, - Rank1View fval, Rank1View x, - const LO &nx, Rank1View y, const LO &ny, - Rank4View fspl, LO &ier); - - /** \brief Evaluate the bicubic spline at given points - * - * \param xvec input points in x direction where the spline is evaluated - * \param yvec input points in y direction where the spline is evaluated - * \param fval output values of the spline at given points - */ - void evaluate(Rank1View xvec, Rank1View yvec, - Rank2View fval); - - /** \brief Evaluate the bicubic spline at given points with selector - * - * \param iselect selector array indicating which derivatives to compute - * \param xvec input points in x direction where the spline is evaluated - * \param yvec input points in y direction where the spline is evaluated - * \param fval output values of the spline at given points - * - * \details The selector follows the the following rules: - * iselect(1)=1 -- evaluate f - * iselect(2)=1 -- evaluate df/dx - * iselect(3)=1 -- evaluate df/dy - * iselect(4)=1 -- evaluate d2f/dx2 - * iselect(5)=1 -- evaluate d2f/dy2 - * iselect(6)=1 -- evaluate d2f/dxdy - */ - void evaluate(Kokkos::View iselect, - Rank1View xvec, Rank1View yvec, - Rank2View fval); - -protected: - Rank4View fspl_; - Rank1View y_; - LO ny_; +KOKKOS_INLINE_FUNCTION void +inGrid(T &xget, T &zxget, Rank1View x, const LO &nx, LO &ier) { + if (xget < x[0] || xget > x[nx - 1]) { + T zxtol = 4.0e-7 * std::max(std::abs(x[0]), std::abs(x[nx - 1])); - void sanity_check(Rank1View x, Rank1View y, - LO ibcxmin, Rank1View bcxmin, LO ibcxmax, - Rank1View bcxmax, LO ibcymin, - Rank1View bcymin, LO ibcymax, - Rank1View bcymax); + if (xget < x[0] - zxtol || xget > x[nx - 1] + zxtol) { + ier = 1; // Error code for out of range + printf("lookup: xget=%.6f out of range %.6f to %.6f\n", xget, x[0], + x[nx - 1]); -private: - /** \brief Lookup the grid point and compute the displacement - * - * \param xget input point in x direction where the spline is evaluated - * \param yget input point in y direction where the spline is evaluated - * \param x input grid points in x direction - * \param nx number of grid points in x direction - * \param y input grid points in y direction - * \param ny number of grid points in y direction - * \param i index of the grid point in x direction - * \param j index of the grid point in y direction - * \param dx displacement from the grid point in x direction - * \param dy displacement from the grid point in y direction - * \param ier error flag, 0 if successful, non-zero otherwise - */ - static KOKKOS_INLINE_FUNCTION void - lookup(T xget, T yget, Rank1View x, const LO &nx, - Rank1View y, const LO &ny, LO &i, LO &j, T &dx, T &dy, - LO &ier); - - /** \brief Evaluate the bicubic spline at given grid cell - * - * \param ict selector array indicating which derivatives to compute - * \param fval output values of the spline at given grid cell - * \param i index of the grid cell in x direction - * \param j index of the grid cell in y direction - * \param dx displacement from the grid cell in x direction - * \param dy displacement from the grid cell in y direction - * \param fspl bicubic spline coefficients - */ - static KOKKOS_INLINE_FUNCTION void evalfn( - Kokkos::View ict, - Rank1View fval, - const LO &i, - const LO &j, - const T &dx, - const T &dy, - Rank4View fspl - ); -}; + return; + } else { + printf("lookup: xget=%.6f beyond range %.6f to %.6f (fixup applied)\n", + xget, x[0], x[nx - 1]); + zxget = (xget < x[0]) ? x[0] : x[nx - 1]; + } + } +} -/** \brief CompactBiCubicSplineInterpolator class - * This class provides methods for 2D compact bicubic spline interpolation. - * It inherits from ExplicitBiCubicSplineInterpolator and implements the compact representation of bicubic spline coefficients. +/** \brief Detect if the boundary conditions are homogeneous * - * The 2D compact bicubic spline are evaluated using the following formula: - * for x(i).le.x.le.x(i+1) and y(j).le.y.le.y(j+1), let - * hx = x(i+1)-x(i) hy = y(j+1)-y(j) - * px = (x-x(i))/hx py = (y-y(j))/hy - * qx = 1-px qy = 1-py - * rx = (px**3-px) ry = (py**3-py) - * sx = (qx**3-qx) sy = (qy**3-qy) + * \param bcmin boundary condition data + * \param ibcmin boundary condition flag + * \param iflg2 flag indicating if the boundary conditions are + * \param nx number of grid points in x direction * - * s(x,y) = qx*(qy*D(1,i,j)+py*D(1,i,j+1)) + - * px*(qy*D(1,i+1,j)+py*D(1,i+1,j+1)) + - * (hx**2/6)*{sx*(qy*D(2,i,j)+py*D(2,i,j+1)) + - * rx*(qy*D(2,i+1,j)+py*D(2,i+1,j+1))} + - * (hy**2/6)*{qx*(sy*D(3,i,j)+ry*D(3,i,j+1)) + - * px*(sy*D(3,i+1,j)+ry*D(3,i+1,j+1))} + - * (hx**2*hy**2/36)*{sx*(sy*D(4,i,j)+ry*D(4,i,j+1)) + - * rx*(sy*D(4,i+1,j)+ry*D(4,i+1,j+1))} + * \details Check if given derivatives at the boundary are all zero to identify + * homogeneous boundary conditions. A homogeneous boundary condition set A has + * the property that if s1(x,y) satisfies A, then (for any real number c) c*S1 + * also satisfies A, and, if both s1(x,y) and s2(x,y) satisfy A then so also + * does s1+s2. A non-homogeneous boundary condition need extra correction steps + * during spline setup. */ template -class CompactBiCubicSplineInterpolator - : public ExplicitBiCubicSplineInterpolator { -public: - using - typename ExplicitCubicSplineInterpolator::execution_space; - using member_type = typename Kokkos::TeamPolicy::member_type; - - CompactBiCubicSplineInterpolator() = default; - - /** \brief Construct the interpolator object and set up the coefficients - * - * \param x input grid points in x direction - * \param y input grid points in y direction - * \param values values of given grid points - * \param ibcxmin boundary condition flag at x(0) - * \param bcxmin boundary condition data at x(0) - * \param ibcxmax boundary condition flag at x(-1) - * \param bcxmax boundary condition data at x(-1) - * \param ibcymin boundary condition flag at y(0) - * \param bcymin boundary condition data at y(0) - * \param ibcymax boundary condition flag at y(-1) - * \param bcymax boundary condition data at y(-1) - * - * \details The boundary condition flags take the same values as in ExplicitCubicSplineInterpolator - * at each direction. - */ - CompactBiCubicSplineInterpolator(Rank1View x, - Rank1View y, - Rank1View values, LO ibcxmin, - Rank1View bcxmin, LO ibcxmax, - Rank1View bcxmax, LO ibcymin, - Rank1View bcymin, LO ibcymax, - Rank1View bcymax); - - /** \brief Construct the interpolator object and set up the coefficients with default boundary conditions - * \param x input grid points in x direction - * \param y input grid points in y direction - * \param values values of given grid points - */ - CompactBiCubicSplineInterpolator(Rank1View x, - Rank1View y, - Rank1View values); - - /** \brief Set up the internal working space and coefficients - */ - void setup(Rank1View x, Rank1View y, - Rank1View values, LO ibcxmin, - Rank1View bcxmin, LO ibcxmax, - Rank1View bcxmax, LO ibcymin, - Rank1View bcymin, LO ibcymax, - Rank1View bcymax); - - /** \brief Solve the coefficients of the compact bicubic spline - */ - static void solve_spline(Rank1View x, LO nx, - Rank1View y, LO ny, - Rank3View f, LO ibcxmin, - Rank1View bcxmin, LO ibcxmax, - Rank1View bcxmax, LO ibcymin, - Rank1View bcymin, LO ibcymax, - Rank1View bcymax, - Rank1View wk); - - /** \brief Evaluate the bicubic spline at a single point with selector - * - * \param xget input point in x direction where the spline is evaluated - * \param yget input point in y direction where the spline is evaluated - * \param ict selector array indicating which derivatives to compute - * \param fval output values of the spline at given point - * \param x input grid points in x direction - * \param nx number of grid points in x direction - * \param y input grid points in y direction - * \param ny number of grid points in y direction - * \param f bicubic spline coefficients - * \param ier error flag, 0 if successful, non-zero otherwise - */ - static KOKKOS_INLINE_FUNCTION void - eval(T xget, T yget, Kokkos::View ict, - Rank1View fval, // output (size depends on ict) - Rank1View x, const LO &nx, Rank1View y, - const LO &ny, Rank3View f, LO &ier); - - /** \brief Evaluate the bicubic spline at given points - * - * \param xvec input points in x direction where the spline is evaluated - * \param yvec input points in y direction where the spline is evaluated - * \param fval output values of the spline at given points - */ - void evaluate(Rank1View xvec, Rank1View yvec, - Rank2View fval); - - /** \brief Evaluate the bicubic spline at given points with selector - * - * \param iselect selector array indicating which derivatives to compute - * \param xvec input points in x direction where the spline is evaluated - * \param yvec input points in y direction where the spline is evaluated - * \param fval output values of the spline at given points - * - * \details The selector follows the same rules as in ExplicitBiCubicSplineInterpolator. - */ - void evaluate(Kokkos::View iselect, - Rank1View xvec, Rank1View yvec, - Rank2View fval); - -protected: - Rank3View fspl_; - -private: - /** \brief Lookup the grid point and compute the displacement - * - * \param xget input point in x direction where the spline is evaluated - * \param yget input point in y direction where the spline is evaluated - * \param x input grid points in x direction - * \param nx number of grid points in x direction - * \param y input grid points in y direction - * \param ny number of grid points in y direction - * \param i index of the grid point in x direction - * \param j index of the grid point in y direction - * \param xparam displacement from the grid point in x direction - * \param hx step size in the x direction - * \param hxi inverse step size in the x direction - * \param yparam displacement from the grid point in y direction - * \param hy step size in the y direction - * \param hyi inverse step size in the y direction - * \param ier error flag, 0 if successful, non-zero otherwise - */ - static KOKKOS_INLINE_FUNCTION void - lookup(T xget, T yget, Rank1View x, const LO &nx, - Rank1View y, const LO &ny, LO &i, LO &j, T &xparam, - T &yparam, T &hx, T &hxi, T &hy, T &hyi, LO &ier); - - /** \brief Evaluate the bicubic spline at given grid cell - * - * /param ict selector array indicating which derivatives to compute - * \param fval output values of the spline at given grid cell - * \param i index of the grid cell in x direction - * \param j index of the grid cell in y direction - * \param xparam displacement from the grid cell in x direction - * \param yparam displacement from the grid cell in y direction - * \param hx step size in the x direction - * \param hxi inverse step size in the x direction - * \param hy step size in the y direction - * \param hyi inverse step size in the y direction - * \param f bicubic spline coefficients - */ - static KOKKOS_INLINE_FUNCTION void - evalfn(Kokkos::View ict, LO ivec, LO ivecd, - Rank1View fval, const LO &i, const LO &j, - const T &xparam, const T &yparam, const T &hx, const T &hxi, - const T &hy, const T &hyi, Rank3View f); -}; - -template -Kokkos::View -ExplicitCubicSplineInterpolator::get_coefficients() { - return coefficients_; -} - -template -void ExplicitCubicSplineInterpolator::set_coefficients( - Kokkos::View coefficients) { - coefficients_ = coefficients; -} - -template -void ExplicitBiCubicSplineInterpolator::correction_detect( - Rank1View bcmin, LO &ibcmin, LO &iflg2, LO &nx) { +void correction_detect(Rank1View bcmin, LO &ibcmin, LO &iflg2, + LO &nx) { + using execution_space = typename MemorySpace::execution_space; if (ibcmin == 1 || ibcmin == 2) { Kokkos::parallel_reduce( "check_nonzero", Kokkos::RangePolicy(0, nx), @@ -740,113 +100,8 @@ void ExplicitBiCubicSplineInterpolator::correction_detect( } } -template -void ExplicitCubicSplineInterpolator::sanity_check( - Rank1View x, const LO &ibcxmin, const T &bcxmin, - const LO &ibcxmax, const T &bcxmax) { - PCMS_ALWAYS_ASSERT(x.extent(0) >= 2); - - ibc_check(ibcxmin, "1d spline", "xmin", -1, 7); - if (ibcxmin >= 0) - ibc_check(ibcxmax, "1d spline", "xmax", 0, 7); - isUniformAscending(x, 1.0e-3); - - this->nx_ = x.extent(0); - this->x_ = x; -} - -template -ExplicitCubicSplineInterpolator:: - ExplicitCubicSplineInterpolator(Rank1View x, - Rank1View values, - const LO &ibcxmin, const T &bcxmin, - const LO &ibcxmax, const T &bcxmax) { - sanity_check(x, ibcxmin, bcxmin, ibcxmax, bcxmax); - setup(x, this->nx_, values, ibcxmin, bcxmin, ibcxmax, bcxmax); -} - -template -ExplicitCubicSplineInterpolator:: - ExplicitCubicSplineInterpolator(Rank1View x, - Rank1View values) - : ExplicitCubicSplineInterpolator(x, values, 0, 0, 0, - 0) { // Delegates to primary constructor - std::cout << "Not a knot boundary condition is applied by default" - << std::endl; -} - -template -void ExplicitCubicSplineInterpolator::setup( - Rank1View x, const LO &nx, Rank1View values, - const LO &ibcxmin, const T &bcxmin, const LO &ibcxmax, const T &bcxmax) { - Kokkos::View fspl_view("coefficients", 4 * nx); - ExplicitCubicSplineInterpolator::set_coefficients(fspl_view); - auto fspl = Rank2View(fspl_view.data(), 4, nx); - Kokkos::parallel_for( - "set_coefficients", Kokkos::RangePolicy(0, this->nx_), - KOKKOS_LAMBDA(const LO i) { fspl(0, i) = values(i); }); - - Kokkos::View wk_view("working space", 10); - auto wk = Rank1View(wk_view.data(), 10); - // TODO: pass member type to solve_spline - Kokkos::parallel_for( - "explicit cubic", Kokkos::TeamPolicy(1, Kokkos::AUTO), - KOKKOS_LAMBDA(const member_type &team_member) { - Kokkos::single(Kokkos::PerTeam(team_member), [=]() { - solve_spline(x, nx, fspl, ibcxmin, bcxmin, ibcxmax, bcxmax, wk); - }); - }); - this->fspl_ = fspl; -} - -template -CompactCubicSplineInterpolator::CompactCubicSplineInterpolator( - Rank1View x, Rank1View values, - const LO &ibcxmin, const T &bcxmin, const LO &ibcxmax, const T &bcxmax) { - ExplicitCubicSplineInterpolator::sanity_check( - x, ibcxmin, bcxmin, ibcxmax, bcxmax); - setup(x, this->nx_, values, ibcxmin, bcxmin, ibcxmax, bcxmax); -} - -template -CompactCubicSplineInterpolator::CompactCubicSplineInterpolator( - Rank1View x, Rank1View fx) - : CompactCubicSplineInterpolator(x, fx, 0, 0, 0, - 0) { // Delegates to primary constructor - std::cout << "Not a knot boundary condition is applied by default" - << std::endl; -} - -template -void CompactCubicSplineInterpolator::setup( - Rank1View x, const LO &nx, Rank1View values, - const LO &ibcxmin, const T &bcxmin, const LO &ibcxmax, const T &bcxmax) { - Kokkos::View fspl_view("coefficients", 2 * this->nx_); - ExplicitCubicSplineInterpolator::set_coefficients(fspl_view); - auto fspl = Rank2View(fspl_view.data(), 2, this->nx_); - Kokkos::parallel_for( - "set_coefficients", Kokkos::RangePolicy(0, this->nx_), - KOKKOS_LAMBDA(const LO i) { fspl(0, i) = values(i); }); - - Kokkos::View fspl4_view("explicit coefficients", - 4 * this->nx_); - auto fspl4 = Rank2View(fspl4_view.data(), 4, this->nx_); - Kokkos::View wk_view("working space", 10); - auto wk = Rank1View(wk_view.data(), 10); - - Kokkos::parallel_for( - "compact cubic", Kokkos::TeamPolicy(1, Kokkos::AUTO), - KOKKOS_LAMBDA(const member_type &team_member) { - Kokkos::single(Kokkos::PerTeam(team_member), [=]() { - solve_spline(x, nx, fspl, fspl4, ibcxmin, bcxmin, ibcxmax, bcxmax, - wk); - }); - }); - this->fspl_ = fspl; -} - /** \brief Solve for 1d spline coefficients. - * + * * \param k_bc1 boundary condition flag at x(0) * \param k_bcn boundary condition flag at x(-1) * \param n number of grid points @@ -854,7 +109,11 @@ void CompactCubicSplineInterpolator::setup( * \param f output coefficients of the cubic spline * \param wk working space for the spline solver * - * \details Originally developed by Wayne Houlberg in Fortran. + * \details Reference: + * [1] G. E. Forsythe, M. A. Malcolm, and C. B. Moler, Computer Methods for + * Mathematical Computations. Prentice-Hall, 1977, p. 76. [2] G. Engeln-Müllges + * and F. Uhlig, Numerical Algorithms with Fortran. Berlin: Springer-Verlag, + * 1996, p. 251. [3] W. A. Houlberg and D. McCune, March 2000. */ template KOKKOS_FUNCTION void v_spline(const LO &k_bc1, const LO &k_bcn, const LO &n, @@ -1328,10 +587,10 @@ KOKKOS_FUNCTION void v_spline(const LO &k_bc1, const LO &k_bcn, const LO &n, template KOKKOS_FUNCTION void -ExplicitCubicSplineInterpolator::solve_spline( - Rank1View x, const LO &nx, Rank2View fspl, - const LO &ibcxmin, const T &bcxmin, const LO &ibcxmax, const T &bcxmax, - Rank1View wk) { +solve_cubic_spline_explicit(Rank1View x, const LO &nx, + Rank2View fspl, const LO &ibcxmin, + const T &bcxmin, const LO &ibcxmax, const T &bcxmax, + Rank1View wk) { T half = 0.5; T sixth = 0.166666666666666667; @@ -1354,32 +613,19 @@ ExplicitCubicSplineInterpolator::solve_spline( } } +/** \brief Evaluate the point given location in the grid + * + * \param selector selector array indicating which derivatives to compute + * \param fval output values of the spline at given points + * \param i index of the grid point + * \param dx displacement from the grid point + * \param fspl spline coefficients + */ template KOKKOS_INLINE_FUNCTION void -ExplicitCubicSplineInterpolator::inGrid( - T &xget, T &zxget, Rank1View x, const LO &nx, LO &ier) { - if (xget < x[0] || xget > x[nx - 1]) { - T zxtol = 4.0e-7 * std::max(std::abs(x[0]), std::abs(x[nx - 1])); - - if (xget < x[0] - zxtol || xget > x[nx - 1] + zxtol) { - ier = 1; // Error code for out of range - printf("lookup: xget=%.6f out of range %.6f to %.6f\n", xget, x[0], - x[nx - 1]); - - return; - } else { - printf("lookup: xget=%.6f beyond range %.6f to %.6f (fixup applied)\n", - xget, x[0], x[nx - 1]); - zxget = (xget < x[0]) ? x[0] : x[nx - 1]; - } - } -} - -template -KOKKOS_INLINE_FUNCTION void -ExplicitCubicSplineInterpolator::evalfn( - Kokkos::View selector, Rank1View fval, - const LO &i, const T &dx, Rank2View fspl) { +cubic_evalfn_explicit(Kokkos::View selector, + Rank1View fval, const LO &i, const T &dx, + Rank2View fspl) { LO iaval = 0; @@ -1410,33 +656,24 @@ ExplicitCubicSplineInterpolator::evalfn( } } // end evalfn +/** \brief Lookup the grid point and compute the displacement + * + * \param xget input point where the spline is evaluated + * \param x input grid points + * \param nx number of grid points + * \param i index of the grid point + * \param dx displacement from the grid point + * \param ier error flag, 0 if successful, non-zero otherwise + */ template KOKKOS_INLINE_FUNCTION void -ExplicitCubicSplineInterpolator::eval( - T xget, Kokkos::View iselect, - Rank1View fval, Rank1View x, const LO &nx, - Rank2View fspl, LO &ier) { - LO ia = 0; - T dxa = 0.0; - lookup(xget, x, nx, ia, dxa, ier); - if (ier != 0) { - printf("error in evaluation, ier = %d\n", ier); - return; - } - - evalfn(iselect, fval, ia, dxa, fspl); -} - -template -KOKKOS_INLINE_FUNCTION void -ExplicitCubicSplineInterpolator::lookup( - T xget, Rank1View x, const LO &nx, LO &i, T &dx, LO &ier) { - LO nxm = nx - 1; - T zxget = xget; +cubic_lookup_explicit(T xget, Rank1View x, const LO &nx, LO &i, + T &dx, LO &ier) { + LO nxm = nx - 1; + T zxget = xget; // Range check - ExplicitCubicSplineInterpolator::inGrid(xget, zxget, x, nx, - ier); + inGrid(xget, zxget, x, nx, ier); LO ii = static_cast(nxm * (zxget - x[0]) / (x[nx - 1] - x[0])); i = std::min(nxm - 1, ii); @@ -1450,10 +687,39 @@ ExplicitCubicSplineInterpolator::lookup( dx = zxget - x[i]; } +/** \brief Evaluate the cubic spline at a single point with selector + * + * \param xget input point where the spline is evaluated + * \param selector selector array indicating which derivatives to compute + * \param fval output values of the spline at given point + * \param x input grid points + * \param nx number of grid points + * \param fspl spline coefficients + * \param ier error flag, 0 if successful, non-zero otherwise + * + * \details A static function that can be used to evaluate the cubic spline at a + * single point. Note that this function does nothing when tje input point is + * out of the grid range (ier is set to non-zero). + */ +template +KOKKOS_INLINE_FUNCTION void +cubic_eval_explicit(T xget, Kokkos::View iselect, + Rank1View fval, Rank1View x, + const LO &nx, Rank2View fspl, LO &ier) { + LO ia = 0; + T dxa = 0.0; + cubic_lookup_explicit(xget, x, nx, ia, dxa, ier); + if (ier != 0) { + printf("error in evaluation, ier = %d\n", ier); + return; + } + + cubic_evalfn_explicit(iselect, fval, ia, dxa, fspl); +} + // TODO: take member type as parameter for further optimization template -KOKKOS_FUNCTION void -CompactCubicSplineInterpolator::solve_spline( +KOKKOS_FUNCTION void solve_cubic_spline_compact( Rank1View x, const LO &nx, Rank2View fspl, Rank2View fspl4, const LO &ibcxmin, const T &bcxmin, const LO &ibcxmax, const T &bcxmax, Rank1View wk) { @@ -1464,8 +730,8 @@ CompactCubicSplineInterpolator::solve_spline( } // Call traditional spline generator - ExplicitCubicSplineInterpolator::solve_spline( - x, nx, fspl4, ibcxmin, bcxmin, ibcxmax, bcxmax, wk); + solve_cubic_spline_explicit(x, nx, fspl4, ibcxmin, bcxmin, ibcxmax, bcxmax, + wk); for (LO i = 0; i < nx - 1; ++i) { fspl(1, i) = 2.0 * fspl4(2, i); @@ -1475,59 +741,22 @@ CompactCubicSplineInterpolator::solve_spline( 2.0 * fspl4(2, nx - 2) + (x[nx - 1] - x[nx - 2]) * 6.0 * fspl4(3, nx - 2); } -template -void ExplicitCubicSplineInterpolator::evaluate( - const Kokkos::View selector, - Rank1View xvec, Rank2View fval) { - LO ivd = fval.extent(1); - Kokkos::parallel_for( - Kokkos::RangePolicy(0, xvec.extent(0)), - KOKKOS_CLASS_LAMBDA(const LO i) { - LO ier = 0; - auto fval_view = - Rank1View(fval.data_handle() + i * ivd, ivd); - eval(xvec(i), selector, fval_view, this->x_, this->nx_, this->fspl_, - ier); - }); -} - -template -void ExplicitCubicSplineInterpolator::evaluate( - Rank1View xvec, Rank2View fval) { - std::array ict_arr = {1, 0, 0}; - evaluate(Kokkos::View(ict_arr.data(), 3), xvec, fval); -}; - -template -void CompactCubicSplineInterpolator::evaluate( - Kokkos::View selector, Rank1View xvec, - Rank2View fval) { - LO ivd = fval.extent(1); - Kokkos::parallel_for( - Kokkos::RangePolicy(0, xvec.extent(0)), - KOKKOS_CLASS_LAMBDA(const LO i) { - LO ier = 0; - auto fval_view = - Rank1View(fval.data_handle() + i * ivd, ivd); - eval(xvec(i), selector, fval_view, this->x_, this->nx_, this->fspl_, - ier); - }); -} - -// TODO: evluation functions are exactly the same, so put them in base class? -template -void CompactCubicSplineInterpolator::evaluate( - Rank1View xvec, Rank2View fval) { - std::array ict_arr = {1, 0, 0}; - evaluate(Kokkos::View(ict_arr.data(), 3), xvec, fval); -}; - +/** \brief Evaluate the point given location in the grid + * + * \param selector selector array indicating which derivatives to compute + * \param fval output values of the spline at given points + * \param i index of the grid point + * \param xparam displacement from the grid point + * \param hx step size in the x direction + * \param hxi inverse step size in the x direction + * \param fs2 compact spline coefficients + */ template KOKKOS_INLINE_FUNCTION void -CompactCubicSplineInterpolator::evalfn( - Kokkos::View selector, Rank1View fval, - const LO &i, const T &xparam, const T &hx, const T &hxi, - Rank2View fs2) { +cubic_evalfn_compact(Kokkos::View selector, + Rank1View fval, const LO &i, + const T &xparam, const T &hx, const T &hxi, + Rank2View fs2) { const T sixth = 1.0 / 6.0; LO iadr = 0; @@ -1584,17 +813,26 @@ CompactCubicSplineInterpolator::evalfn( } } +/** \brief Lookup the grid point and compute the displacement + * + * \param xget input point where the spline is evaluated + * \param x input grid points + * \param nx number of grid points + * \param i index of the grid point + * \param xparam displacement from the grid point + * \param hx step size in the x direction + * \param hxi inverse step size in the x direction + * \param ier error flag, 0 if successful, non-zero otherwise + */ template KOKKOS_INLINE_FUNCTION void -CompactCubicSplineInterpolator::lookup( - T xget, Rank1View x, const LO &nx, LO &i, T &xparam, T &hx, - T &hxi, LO &ier) { +cubic_lookup_compact(T xget, Rank1View x, const LO &nx, LO &i, + T &xparam, T &hx, T &hxi, LO &ier) { ier = 0; T zxget = xget; - ExplicitCubicSplineInterpolator::inGrid(xget, zxget, x, nx, - ier); + inGrid(xget, zxget, x, nx, ier); LO nxm = nx - 1; @@ -1612,13 +850,22 @@ CompactCubicSplineInterpolator::lookup( xparam = (zxget - x[i]) * hxi; } +/** \brief Evaluate the compact cubic spline at a single point with selector + * + * \param xget input point where the spline is evaluated + * \param ict selector array indicating which derivatives to compute + * \param fval output values of the spline at given point + * \param x input grid points + * \param nx number of grid points + * \param fs2 compact spline coefficients + * \param ier error flag, 0 if successful, non-zero otherwise + */ template KOKKOS_INLINE_FUNCTION void -CompactCubicSplineInterpolator::eval( - T xget, Kokkos::View ict, Rank1View fval, - Rank1View x, - const LO &nx, // size of x - Rank2View fs2, LO &ier) { +cubic_eval_compact(T xget, Kokkos::View ict, + Rank1View fval, Rank1View x, + const LO &nx, // size of x + Rank2View fspl, LO &ier) { // Initialize output zone info LO i = 0; @@ -1627,157 +874,349 @@ CompactCubicSplineInterpolator::eval( T hxi = 0.0; // Find the interval containing xget - lookup(xget, x, nx, i, xparam, hx, hxi, ier); + cubic_lookup_compact(xget, x, nx, i, xparam, hx, hxi, ier); if (ier != 0) return; // Evaluate spline at the points - evalfn(ict, fval, i, xparam, hx, hxi, fs2); -} - -template -void ExplicitBiCubicSplineInterpolator::sanity_check( - Rank1View x, Rank1View y, LO ibcxmin, - Rank1View bcxmin, LO ibcxmax, - Rank1View bcxmax, LO ibcymin, - Rank1View bcymin, LO ibcymax, - Rank1View bcymax) { - PCMS_ALWAYS_ASSERT(x.extent(0) >= 2); - PCMS_ALWAYS_ASSERT(y.extent(0) >= 2); - - // Check boundary condition values - ibc_check(ibcxmin, "2d spline", "xmin", -1, 7); - if (ibcxmin >= 0) - ibc_check(ibcxmax, "2d spline", "xmax", 0, 7); - ibc_check(ibcymin, "2d spline", "ymin", -1, 7); - if (ibcymin >= 0) - ibc_check(ibcymax, "2d spline", "ymax", 0, 7); - - isUniformAscending(x, 1.0e-3); - isUniformAscending(y, 1.0e-3); - this->x_ = x; - this->nx_ = x.extent(0); - this->y_ = y; - this->ny_ = y.extent(0); + cubic_evalfn_compact(ict, fval, i, xparam, hx, hxi, fspl); } +/** \brief Lookup the grid point and compute the displacement + * + * \param xget input point in x direction where the spline is evaluated + * \param yget input point in y direction where the spline is evaluated + * \param x input grid points in x direction + * \param nx number of grid points in x direction + * \param y input grid points in y direction + * \param ny number of grid points in y direction + * \param i index of the grid point in x direction + * \param j index of the grid point in y direction + * \param dx displacement from the grid point in x direction + * \param dy displacement from the grid point in y direction + * \param ier error flag, 0 if successful, non-zero otherwise + */ template -ExplicitBiCubicSplineInterpolator:: - ExplicitBiCubicSplineInterpolator( - Rank1View x, // size: inx - Rank1View y, // size: iny - Rank1View values, LO ibcxmin, - Rank1View - bcxmin, // size: iny (used if ibcxmin = 1 or 2) - LO ibcxmax, - Rank1View - bcxmax, // size: iny (used if ibcxmax = 1 or 2) - LO ibcymin, - Rank1View - bcymin, // size: inx (used if ibcymin = 1 or 2) - LO ibcymax, - Rank1View bcymax // size: inx (used if ibcymax = 1 or 2) - ) { - sanity_check(x, y, ibcxmin, bcxmin, ibcxmax, bcxmax, ibcymin, bcymin, ibcymax, - bcymax); +KOKKOS_INLINE_FUNCTION void +bicubic_lookup_explicit(T xget, T yget, Rank1View x, + const LO &nx, Rank1View y, const LO &ny, + LO &i, LO &j, T &dx, T &dy, LO &ier) { + LO nxm = nx - 1; + LO nym = ny - 1; + LO ii, jj; - setup(x, y, values, ibcxmin, bcxmin, ibcxmax, bcxmax, ibcymin, bcymin, - ibcymax, bcymax); -} + ier = 0; + T zxget = xget; + T zyget = yget; -template -void ExplicitBiCubicSplineInterpolator::setup( - Rank1View x, // size: inx - Rank1View y, // size: iny - Rank1View values, LO ibcxmin, - Rank1View bcxmin, // size: iny (used if ibcxmin = 1 or 2) - LO ibcxmax, - Rank1View bcxmax, // size: iny (used if ibcxmax = 1 or 2) - LO ibcymin, - Rank1View bcymin, // size: inx (used if ibcymin = 1 or 2) - LO ibcymax, - Rank1View bcymax // size: inx (used if ibcymax = 1 or 2) -) { - LO ny = this->ny_; - LO nx = this->nx_; - Kokkos::View fspl_view("fspl view", 4 * 4 * nx * ny); - ExplicitCubicSplineInterpolator::set_coefficients(fspl_view); - auto fspl = Rank4View(fspl_view.data(), 4, 4, nx, ny); - Kokkos::parallel_for( - Kokkos::MDRangePolicy>({0, 0}, {ny, nx}), - KOKKOS_LAMBDA(const LO iy, const LO ix) { - fspl(0, 0, ix, iy) = values(ix * ny + iy); - }); + inGrid(xget, zxget, x, nx, ier); + inGrid(yget, zyget, y, ny, ier); - Kokkos::View wk_view("wk", 9 * nx * ny); - auto wk = Rank1View(wk_view.data(), 9 * nx * ny); + if (ier != 0) + return; - solve_spline(x, nx, y, ny, fspl, ibcxmin, bcxmin, ibcxmax, bcxmax, ibcymin, - bcymin, ibcymax, bcymax, wk); + ii = static_cast(nxm * (zxget - x[0]) / (x[nx - 1] - x[0])); + i = std::min(nxm - 2, ii); + if (zxget < x[i]) { + i--; + } else if (zxget > x[i + 1]) { + i++; + } - this->fspl_ = fspl; -} + jj = static_cast(nym * (zyget - y[0]) / (y[ny - 1] - y[0])); + j = std::min(nym - 2, jj); + if (zyget < y[j]) { + j--; + } else if (zyget > y[j + 1]) { + j++; + } -template -ExplicitBiCubicSplineInterpolator:: - ExplicitBiCubicSplineInterpolator(Rank1View x, // size: inx - Rank1View y, // size: iny - Rank1View values) - : ExplicitBiCubicSplineInterpolator( - x, y, values, 0, {}, 0, {}, 0, {}, 0, - {}) { // Delegates to primary constructor - std::cout << "Not a knot boundary condition is applied by default" - << std::endl; + dx = zxget - x[i]; + dy = zyget - y[j]; } +/** \brief Evaluate the bicubic spline at given grid cell + * + * \param ict selector array indicating which derivatives to compute + * \param fval output values of the spline at given grid cell + * \param i index of the grid cell in x direction + * \param j index of the grid cell in y direction + * \param dx displacement from the grid cell in x direction + * \param dy displacement from the grid cell in y direction + * \param fspl bicubic spline coefficients + */ template -void ExplicitBiCubicSplineInterpolator::solve_spline( - Rank1View x, // size: inx - LO inx, Rank1View y, // size: iny - LO iny, Rank4View fspl, // [4, 4, inx, iny] - LO ibcxmin, - Rank1View bcxmin, // size: iny (used if ibcxmin = 1 or 2) - LO ibcxmax, - Rank1View bcxmax, // size: iny (used if ibcxmax = 1 or 2) - LO ibcymin, - Rank1View bcymin, // size: inx (used if ibcymin = 1 or 2) - LO ibcymax, - Rank1View bcymax, // size: inx (used if ibcymax = 1 or 2) - Rank1View wk // size: nwk +KOKKOS_INLINE_FUNCTION void bicubic_evalfn_explicit( + Kokkos::View + ict, // Selector array for which derivatives to compute + Rank1View fval, // Output array: size [ivd, *] (flattened) + const LO &i, // Grid cell indices in x direction + const LO &j, // Grid cell indices in y direction + const T &dx, // x displacements within cells + const T &dy, // y displacements within cells + Rank4View fspl // Spline coefficients ) { - LO iflg2 = 0; - - auto fspl_l_x = - Rank2View(wk.data_handle() + 4 * inx * iny, 4 * inx, iny); - auto wk_l = Rank1View(wk.data_handle() + 2 * 4 * inx * iny, - inx * iny); - auto fspl_l_y = Rank2View(wk.data_handle(), 4 * inx, iny); + LO iaval = 0; // Index for fval + if (ict[0] <= 2) { + if ((ict[0] > 0) || (ict[0] == -1)) { + // Evaluate f + iaval++; + fval(iaval - 1) = + fspl(0, 0, i, j) + + dy * (fspl(0, 1, i, j) + + dy * (fspl(0, 2, i, j) + dy * fspl(0, 3, i, j))) + + dx * (fspl(1, 0, i, j) + + dy * (fspl(1, 1, i, j) + + dy * (fspl(1, 2, i, j) + dy * fspl(1, 3, i, j))) + + dx * (fspl(2, 0, i, j) + + dy * (fspl(2, 1, i, j) + + dy * (fspl(2, 2, i, j) + dy * fspl(2, 3, i, j))) + + dx * (fspl(3, 0, i, j) + + dy * (fspl(3, 1, i, j) + + dy * (fspl(3, 2, i, j) + + dy * fspl(3, 3, i, j)))))); + } - if (ibcymin != -1) { - ExplicitBiCubicSplineInterpolator::correction_detect( - bcymin, ibcymin, iflg2, inx); - ExplicitBiCubicSplineInterpolator::correction_detect( - bcymax, ibcymax, iflg2, inx); - } + if ((ict[1] > 0) && (ict[0] != -1)) { + // Evaluate df/dx + iaval++; + fval(iaval - 1) = + fspl(1, 0, i, j) + + dy * (fspl(1, 1, i, j) + + dy * (fspl(1, 2, i, j) + dy * fspl(1, 3, i, j))) + + 2.0 * dx * + (fspl(2, 0, i, j) + + dy * (fspl(2, 1, i, j) + + dy * (fspl(2, 2, i, j) + dy * fspl(2, 3, i, j))) + + 1.5 * dx * + (fspl(3, 0, i, j) + + dy * (fspl(3, 1, i, j) + + dy * (fspl(3, 2, i, j) + dy * fspl(3, 3, i, j))))); + } - T xo2 = 0.5; - T xo6 = 1.0 / 6.0; + if ((ict[2] > 0) && (ict[0] != -1)) { + // Evaluate df/dy + iaval++; + fval(iaval - 1) = + fspl(0, 1, i, j) + + dy * (2.0 * fspl(0, 2, i, j) + dy * 3.0 * fspl(0, 3, i, j)) + + dx * (fspl(1, 1, i, j) + + dy * (2.0 * fspl(1, 2, i, j) + dy * 3.0 * fspl(1, 3, i, j)) + + dx * (fspl(2, 1, i, j) + + dy * (2.0 * fspl(2, 2, i, j) + + dy * 3.0 * fspl(2, 3, i, j)) + + dx * (fspl(3, 1, i, j) + + dy * (2.0 * fspl(3, 2, i, j) + + dy * 3.0 * fspl(3, 3, i, j))))); + } - Kokkos::parallel_for( - Kokkos::TeamPolicy(iny, Kokkos::AUTO), - KOKKOS_LAMBDA(const member_type &team) { - const LO iy = team.league_rank(); + if ((ict[3] > 0) || (ict[0] == -1)) { + // Evaluate d2f/dx2 + iaval++; + fval(iaval - 1) = + 2.0 * (fspl(2, 0, i, j) + + dy * (fspl(2, 1, i, j) + + dy * (fspl(2, 2, i, j) + dy * fspl(2, 3, i, j)))) + + 6.0 * dx * + (fspl(3, 0, i, j) + + dy * (fspl(3, 1, i, j) + + dy * (fspl(3, 2, i, j) + dy * fspl(3, 3, i, j)))); + } - auto fspl_x_view = Rank2View( - fspl_l_x.data_handle() + 4 * inx * iy, 4, inx); - auto wk_x_view = - Rank1View(wk_l.data_handle() + iy * inx, inx); + if ((ict[4] > 0) || (ict[0] == -1)) { + // Evaluate d2f/dy2 + iaval++; + fval(iaval - 1) = + 2.0 * fspl(0, 2, i, j) + 6.0 * dy * fspl(0, 3, i, j) + + dx * (2.0 * fspl(1, 2, i, j) + 6.0 * dy * fspl(1, 3, i, j) + + dx * (2.0 * fspl(2, 2, i, j) + 6.0 * dy * fspl(2, 3, i, j) + + dx * (2.0 * fspl(3, 2, i, j) + + 6.0 * dy * fspl(3, 3, i, j)))); + } - Kokkos::parallel_for(Kokkos::TeamThreadRange(team, inx), [=](LO ix) { - fspl_x_view(0, ix) = fspl(0, 0, ix, iy); - }); + if ((ict[5] > 0) && (ict[0] != -1)) { + // Evaluate d2f/dxdy + iaval++; + fval(iaval - 1) = + fspl(1, 1, i, j) + + dy * (2.0 * fspl(1, 2, i, j) + dy * 3.0 * fspl(1, 3, i, j)) + + 2.0 * dx * + (fspl(2, 1, i, j) + + dy * (2.0 * fspl(2, 2, i, j) + dy * 3.0 * fspl(2, 3, i, j)) + + 1.5 * dx * + (fspl(3, 1, i, j) + dy * (2.0 * fspl(3, 2, i, j) + + dy * 3.0 * fspl(3, 3, i, j)))); + } - if (team.team_rank() == 0) { + if (ict[0] == -1) { + // Evaluate d4f/dx2dy2 + iaval++; + fval(iaval - 1) = + 4.0 * fspl(2, 2, i, j) + 12.0 * dy * fspl(2, 3, i, j) + + dx * (12.0 * fspl(3, 2, i, j) + 36.0 * dy * fspl(3, 3, i, j)); + } + } else if (ict[0] == 3) { + if (ict[1] == 1) { + // d³f/dx³ (not continuous) + iaval++; + fval(iaval - 1) = + 6.0 * (fspl(3, 0, i, j) + + dy * (fspl(3, 1, i, j) + + dy * (fspl(3, 2, i, j) + dy * fspl(3, 3, i, j)))); + } + + if (ict[2] == 1) { + // d³f/dx²dy + iaval++; + fval(iaval - 1) = + 2.0 * (fspl(2, 1, i, j) + + dy * (2.0 * fspl(2, 2, i, j) + dy * 3.0 * fspl(2, 3, i, j))) + + 6.0 * dx * + (fspl(3, 1, i, j) + + dy * (2.0 * fspl(3, 2, i, j) + dy * 3.0 * fspl(3, 3, i, j))); + } + + if (ict[3] == 1) { + // d³f/dxdy² + iaval++; + fval(iaval - 1) = + 2.0 * fspl(1, 2, i, j) + 6.0 * dy * fspl(1, 3, i, j) + + 2.0 * dx * + (2.0 * fspl(2, 2, i, j) + 6.0 * dy * fspl(2, 3, i, j) + + 1.5 * dx * + (2.0 * fspl(3, 2, i, j) + 6.0 * dy * fspl(3, 3, i, j))); + } + + if (ict[4] == 1) { + // d³f/dy³ (not continuous) + iaval++; + fval(iaval - 1) = + 6.0 * (fspl(0, 3, i, j) + + dx * (fspl(1, 3, i, j) + + dx * (fspl(2, 3, i, j) + dx * fspl(3, 3, i, j)))); + } + + } else if (ict[0] == 4) { + if (ict[1] == 1) { + // d⁴f/dx³dy + iaval++; + fval(iaval - 1) = + 6.0 * (fspl(3, 1, i, j) + + dy * 2.0 * (fspl(3, 2, i, j) + dy * 1.5 * fspl(3, 3, i, j))); + } + + if (ict[2] == 1) { + // d⁴f/dx²dy² + iaval++; + fval(iaval - 1) = + 4.0 * fspl(2, 2, i, j) + 12.0 * dy * fspl(2, 3, i, j) + + dx * (12.0 * fspl(3, 2, i, j) + 36.0 * dy * fspl(3, 3, i, j)); + } + + if (ict[3] == 1) { + // d⁴f/dxdy³ (not continuous) + iaval++; + fval(iaval - 1) = + 6.0 * (fspl(1, 3, i, j) + + 2.0 * dx * (fspl(2, 3, i, j) + 1.5 * dx * fspl(3, 3, i, j))); + } + + } else if (ict[0] == 5) { + if (ict[1] == 1) { + // d⁵f/dx³dy² (not continuous) + iaval++; + fval(iaval - 1) = 12.0 * (fspl(3, 2, i, j) + dy * 3.0 * fspl(3, 3, i, j)); + } + + if (ict[2] == 1) { + // d⁵f/dx²dy³ (not continuous) + iaval++; + fval(iaval - 1) = 12.0 * (fspl(2, 3, i, j) + dx * 3.0 * fspl(3, 3, i, j)); + } + + } else if (ict[0] == 6) { + // d⁶f/dx³dy³ (not continuous) + iaval++; + fval(iaval - 1) = 36.0 * fspl(3, 3, i, j); + } +} // end evalfn + +/** \brief Evaluate the bicubic spline at a single point with selector + * + * \param xget input point in x direction where the spline is evaluated + * \param yget input point in y direction where the spline is evaluated + * \param iselect selector array indicating which derivatives to compute + * \param fval output values of the spline at given point + * \param x input grid points in x direction + * \param nx number of grid points in x direction + * \param y input grid points in y direction + * \param ny number of grid points in y direction + * \param fspl bicubic spline coefficients + * \param ier error flag, 0 if successful, non-zero otherwise + */ +template +KOKKOS_INLINE_FUNCTION void +bicubic_eval_explicit(T xget, T yget, Kokkos::View iselect, + Rank1View fval, + Rank1View x, const LO &nx, + Rank1View y, const LO &ny, + Rank4View fspl, LO &ier) { + LO i = 0; + LO j = 0; + T dx = 0.0; + T dy = 0.0; + + // Range finding + bicubic_lookup_explicit(xget, yget, x, nx, y, ny, i, j, dx, dy, ier); + if (ier != 0) + return; + + // Evaluate spline function + bicubic_evalfn_explicit(iselect, fval, i, j, dx, dy, fspl); +} + +template +void solve_bicubic_spline_explicit(Rank1View x, LO inx, + Rank1View y, LO iny, + Rank4View fspl, LO ibcxmin, + Rank1View bcxmin, LO ibcxmax, + Rank1View bcxmax, LO ibcymin, + Rank1View bcymin, LO ibcymax, + Rank1View bcymax, + Rank1View wk) { + using execution_space = typename MemorySpace::execution_space; + using member_type = typename Kokkos::TeamPolicy::member_type; + LO iflg2 = 0; + + auto fspl_l_x = + Rank2View(wk.data_handle() + 4 * inx * iny, 4 * inx, iny); + auto wk_l = Rank1View(wk.data_handle() + 2 * 4 * inx * iny, + inx * iny); + auto fspl_l_y = Rank2View(wk.data_handle(), 4 * inx, iny); + + if (ibcymin != -1) { + correction_detect(bcymin, ibcymin, iflg2, inx); + correction_detect(bcymax, ibcymax, iflg2, inx); + } + + T xo2 = 0.5; + T xo6 = 1.0 / 6.0; + + Kokkos::parallel_for( + Kokkos::TeamPolicy(iny, Kokkos::AUTO), + KOKKOS_LAMBDA(const member_type &team) { + const LO iy = team.league_rank(); + + auto fspl_x_view = Rank2View( + fspl_l_x.data_handle() + 4 * inx * iy, 4, inx); + auto wk_x_view = + Rank1View(wk_l.data_handle() + iy * inx, inx); + + Kokkos::parallel_for(Kokkos::TeamThreadRange(team, inx), [=](LO ix) { + fspl_x_view(0, ix) = fspl(0, 0, ix, iy); + }); + + if (team.team_rank() == 0) { if (ibcxmin == 1) fspl_x_view(1, 0) = bcxmin[iy]; else if (ibcxmin == 2) @@ -1910,9 +1349,8 @@ void ExplicitBiCubicSplineInterpolator::solve_spline( fspl(0, 1, ix, jy) + zhy * (2.0 * fspl(0, 2, ix, jy) + zhy * 3.0 * fspl(0, 3, ix, jy)); } else { - // TODO: check if this is correct - eval(x[inx - 1], y[iny - 1], iselect2, zcur, x, inx, y, iny, fspl, - ier); + bicubic_eval_explicit(x[inx - 1], y[iny - 1], iselect2, zcur, x, + inx, y, iny, fspl, ier); if (ier != 0) return; } @@ -1922,9 +1360,8 @@ void ExplicitBiCubicSplineInterpolator::solve_spline( zcur(0) = 2.0 * fspl(0, 2, ix, jy) + 6.0 * zhy * fspl(0, 3, ix, jy); } else { - // TODO: check if this is correct - eval(x[inx - 1], y[iny - 1], iselect2, zcur, x, inx, y, iny, fspl, - ier); + bicubic_eval_explicit(x[inx - 1], y[iny - 1], iselect2, zcur, x, + inx, y, iny, fspl, ier); if (ier != 0) return; } @@ -2004,398 +1441,437 @@ void ExplicitBiCubicSplineInterpolator::solve_spline( } } +/** \brief Lookup the grid point and compute the displacement + * + * \param xget input point in x direction where the spline is evaluated + * \param yget input point in y direction where the spline is evaluated + * \param x input grid points in x direction + * \param nx number of grid points in x direction + * \param y input grid points in y direction + * \param ny number of grid points in y direction + * \param i index of the grid point in x direction + * \param j index of the grid point in y direction + * \param xparam displacement from the grid point in x direction + * \param hx step size in the x direction + * \param hxi inverse step size in the x direction + * \param yparam displacement from the grid point in y direction + * \param hy step size in the y direction + * \param hyi inverse step size in the y direction + * \param ier error flag, 0 if successful, non-zero otherwise + */ template -void ExplicitBiCubicSplineInterpolator::evaluate( - Kokkos::View iselect, Rank1View xvec, - Rank1View yvec, Rank2View fval) { - PCMS_ALWAYS_ASSERT(xvec.extent(0) == yvec.extent(0) && - xvec.extent(0) == fval.extent(0)); - - LO ivd = fval.extent(1); - Kokkos::parallel_for( - Kokkos::RangePolicy(0, xvec.extent(0)), - KOKKOS_CLASS_LAMBDA(const LO i) { - LO ier = 0; - auto fval_view = - Rank1View(fval.data_handle() + i * ivd, ivd); - eval(xvec(i), yvec(i), iselect, fval_view, this->x_, this->nx_, - this->y_, this->ny_, this->fspl_, ier); - }); -} +KOKKOS_INLINE_FUNCTION void +bicubic_lookup_compact(T xget, T yget, Rank1View x, + const LO &nx, Rank1View y, const LO &ny, + LO &i, LO &j, T &xparam, T &yparam, T &hx, T &hxi, T &hy, + T &hyi, LO &ier) { + ier = 0; -template -void ExplicitBiCubicSplineInterpolator::evaluate( - Rank1View xvec, Rank1View yvec, - Rank2View fval) { - LO ict_arr[6] = {1, 0, 0, 0, 0, 0}; - Kokkos::View ict("select", 6); - Kokkos::parallel_for( - Kokkos::RangePolicy(0, ict.size()), - KOKKOS_LAMBDA(const LO i) { ict(i) = ict_arr[i]; }); - evaluate(ict, xvec, yvec, fval); -} + T zxget = xget; + T zyget = yget; -template -void CompactBiCubicSplineInterpolator::evaluate( - Kokkos::View iselect, Rank1View xvec, - Rank1View yvec, Rank2View fval) { + inGrid(xget, zxget, x, nx, ier); + inGrid(yget, zyget, y, ny, ier); - PCMS_ALWAYS_ASSERT(xvec.extent(0) == yvec.extent(0) && - xvec.extent(0) == fval.extent(0)); - LO ivd = fval.extent(1); - Kokkos::parallel_for( - Kokkos::RangePolicy(0, xvec.extent(0)), - KOKKOS_CLASS_LAMBDA(const LO i) { - LO ier = 0; - auto fval_view = - Rank1View(fval.data_handle() + i * ivd, ivd); - eval(xvec(i), yvec(i), iselect, fval_view, this->x_, this->nx_, - this->y_, this->ny_, this->fspl_, ier); - }); -} + LO nxm = nx - 1; // Number of LOervals in x + LO nym = ny - 1; // Number of LOervals in y + // Determine zone index i + LO ii = static_cast(nxm * (zxget - x[0]) / (x[nx - 1] - x[0])); + i = std::min(nxm - 1, ii); + if (zxget < x[i]) + --i; + else if (zxget > x[i + 1]) + ++i; -template -void CompactBiCubicSplineInterpolator::evaluate( - Rank1View xvec, Rank1View yvec, - Rank2View fval) { - LO ict_arr[6] = {1, 0, 0, 0, 0, 0}; - Kokkos::View ict("select", 6); - Kokkos::parallel_for( - Kokkos::RangePolicy(0, ict.size()), - KOKKOS_LAMBDA(const LO i) { ict(i) = ict_arr[i]; }); - evaluate(ict, xvec, yvec, fval); -} + // Determine zone index j + ii = static_cast(nym * (zyget - y[0]) / (y[ny - 1] - y[0])); + j = std::min(nym - 1, ii); + if (zyget < y[j]) + --j; + else if (zyget > y[j + 1]) + ++j; -template -KOKKOS_INLINE_FUNCTION void -ExplicitBiCubicSplineInterpolator::eval( - T xget, T yget, Kokkos::View iselect, - Rank1View fval, Rank1View x, const LO &nx, - Rank1View y, const LO &ny, Rank4View fspl, - LO &ier) { - LO i = 0; - LO j = 0; - T dx = 0.0; - T dy = 0.0; + hx = x[i + 1] - x[i]; + hy = y[j + 1] - y[j]; - // Range finding - lookup(xget, yget, x, nx, y, ny, i, j, dx, dy, ier); - if (ier != 0) - return; + hxi = 1.0 / hx; + hyi = 1.0 / hy; - // Evaluate spline function - evalfn(iselect, fval, i, j, dx, dy, fspl); + xparam = (zxget - x[i]) * hxi; + yparam = (zyget - y[j]) * hyi; } +/** \brief Evaluate the bicubic spline at given grid cell + * + * /param ict selector array indicating which derivatives to compute + * \param fval output values of the spline at given grid cell + * \param i index of the grid cell in x direction + * \param j index of the grid cell in y direction + * \param xparam displacement from the grid cell in x direction + * \param yparam displacement from the grid cell in y direction + * \param hx step size in the x direction + * \param hxi inverse step size in the x direction + * \param hy step size in the y direction + * \param hyi inverse step size in the y direction + * \param f bicubic spline coefficients + */ template KOKKOS_INLINE_FUNCTION void -ExplicitBiCubicSplineInterpolator::lookup( - T xget, T yget, Rank1View x, const LO &nx, - Rank1View y, const LO &ny, LO &i, LO &j, T &dx, T &dy, - LO &ier) { - LO nxm = nx - 1; - LO nym = ny - 1; - LO ii, jj; - - ier = 0; - T zxget = xget; - T zyget = yget; - - ExplicitCubicSplineInterpolator::inGrid(xget, zxget, x, nx, - ier); - ExplicitCubicSplineInterpolator::inGrid(yget, zyget, y, ny, - ier); - - if (ier != 0) - return; +bicubic_evalfn_compact(Kokkos::View ict, LO ivec, LO ivecd, + Rank1View fval, const LO &i, const LO &j, + const T &xparam, const T &yparam, const T &hx, + const T &hxi, const T &hy, const T &hyi, + Rank3View f) { + constexpr T sixth = 1.0 / 6.0; + const T z36th = sixth * sixth; + LO iadr = 0; - ii = static_cast(nxm * (zxget - x[0]) / (x[nx - 1] - x[0])); - i = std::min(nxm - 2, ii); - if (zxget < x[i]) { - i--; - } else if (zxget > x[i + 1]) { - i++; - } - - jj = static_cast(nym * (zyget - y[0]) / (y[ny - 1] - y[0])); - j = std::min(nym - 2, jj); - if (zyget < y[j]) { - j--; - } else if (zyget > y[j + 1]) { - j++; - } + // ict[0] = 1 or 2 → f, df/dx, df/dy, d²f/dx², d²f/dy², d²f/dxdy + if (ict[0] <= 2) { + // f (function value) + if (ict[0] == 1) { + iadr++; + T xp = xparam, xpi = 1.0 - xp; + T xp2 = xp * xp, xpi2 = xpi * xpi; + T cx = xp * (xp2 - 1.0); + T cxi = xpi * (xpi2 - 1.0); + T hx2 = hx * hx; - dx = zxget - x[i]; - dy = zyget - y[j]; -} + T yp = yparam, ypi = 1.0 - yp; + T yp2 = yp * yp, ypi2 = ypi * ypi; + T cy = yp * (yp2 - 1.0); + T cyi = ypi * (ypi2 - 1.0); + T hy2 = hy * hy; -template -KOKKOS_INLINE_FUNCTION void -ExplicitBiCubicSplineInterpolator::evalfn( - Kokkos::View - ict, // Selector array for which derivatives to compute - Rank1View fval, // Output array: size [ivd, *] (flattened) - const LO &i, // Grid cell indices in x direction - const LO &j, // Grid cell indices in y direction - const T &dx, // x displacements within cells - const T &dy, // y displacements within cells - Rank4View fspl // Spline coefficients -) { - LO iaval = 0; // Index for fval - if (ict[0] <= 2) { - if ((ict[0] > 0) || (ict[0] == -1)) { - // Evaluate f - iaval++; - fval(iaval - 1) = - fspl(0, 0, i, j) + - dy * (fspl(0, 1, i, j) + - dy * (fspl(0, 2, i, j) + dy * fspl(0, 3, i, j))) + - dx * (fspl(1, 0, i, j) + - dy * (fspl(1, 1, i, j) + - dy * (fspl(1, 2, i, j) + dy * fspl(1, 3, i, j))) + - dx * (fspl(2, 0, i, j) + - dy * (fspl(2, 1, i, j) + - dy * (fspl(2, 2, i, j) + dy * fspl(2, 3, i, j))) + - dx * (fspl(3, 0, i, j) + - dy * (fspl(3, 1, i, j) + - dy * (fspl(3, 2, i, j) + - dy * fspl(3, 3, i, j)))))); + T sum = xpi * (ypi * f(0, i, j) + yp * f(0, i, j + 1)) + + xp * (ypi * f(0, i + 1, j) + yp * f(0, i + 1, j + 1)); + sum += sixth * hx2 * + (cxi * (ypi * f(1, i, j) + yp * f(1, i, j + 1)) + + cx * (ypi * f(1, i + 1, j) + yp * f(1, i + 1, j + 1))); + sum += sixth * hy2 * + (xpi * (cyi * f(2, i, j) + cy * f(2, i, j + 1)) + + xp * (cyi * f(2, i + 1, j) + cy * f(2, i + 1, j + 1))); + sum += z36th * hx2 * hy2 * + (cxi * (cyi * f(3, i, j) + cy * f(3, i, j + 1)) + + cx * (cyi * f(3, i + 1, j) + cy * f(3, i + 1, j + 1))); + fval(iadr - 1) = sum; } - if ((ict[1] > 0) && (ict[0] != -1)) { - // Evaluate df/dx - iaval++; - fval(iaval - 1) = - fspl(1, 0, i, j) + - dy * (fspl(1, 1, i, j) + - dy * (fspl(1, 2, i, j) + dy * fspl(1, 3, i, j))) + - 2.0 * dx * - (fspl(2, 0, i, j) + - dy * (fspl(2, 1, i, j) + - dy * (fspl(2, 2, i, j) + dy * fspl(2, 3, i, j))) + - 1.5 * dx * - (fspl(3, 0, i, j) + - dy * (fspl(3, 1, i, j) + - dy * (fspl(3, 2, i, j) + dy * fspl(3, 3, i, j))))); - } + // df/dx + if (ict[1] == 1) { + iadr++; + T xp = xparam, xpi = 1.0 - xp; + T xp2 = xp * xp, xpi2 = xpi * xpi; + T cxd = 3.0 * xp2 - 1.0; + T cxdi = -3.0 * xpi2 + 1.0; + T yp = yparam, ypi = 1.0 - yp; + T yp2 = yp * yp, ypi2 = ypi * ypi; + T cy = yp * (yp2 - 1.0); + T cyi = ypi * (ypi2 - 1.0); + T hy2 = hy * hy; - if ((ict[2] > 0) && (ict[0] != -1)) { - // Evaluate df/dy - iaval++; - fval(iaval - 1) = - fspl(0, 1, i, j) + - dy * (2.0 * fspl(0, 2, i, j) + dy * 3.0 * fspl(0, 3, i, j)) + - dx * (fspl(1, 1, i, j) + - dy * (2.0 * fspl(1, 2, i, j) + dy * 3.0 * fspl(1, 3, i, j)) + - dx * (fspl(2, 1, i, j) + - dy * (2.0 * fspl(2, 2, i, j) + - dy * 3.0 * fspl(2, 3, i, j)) + - dx * (fspl(3, 1, i, j) + - dy * (2.0 * fspl(3, 2, i, j) + - dy * 3.0 * fspl(3, 3, i, j))))); + T sum = hxi * (-(ypi * f(0, i, j) + yp * f(0, i, j + 1)) + + (ypi * f(0, i + 1, j) + yp * f(0, i + 1, j + 1))); + sum += sixth * hx * + (cxdi * (ypi * f(1, i, j) + yp * f(1, i, j + 1)) + + cxd * (ypi * f(1, i + 1, j) + yp * f(1, i + 1, j + 1))); + sum += sixth * hxi * hy2 * + (-(cyi * f(2, i, j) + cy * f(2, i, j + 1)) + + (cyi * f(2, i + 1, j) + cy * f(2, i + 1, j + 1))); + sum += z36th * hx * hy2 * + (cxdi * (cyi * f(3, i, j) + cy * f(3, i, j + 1)) + + cxd * (cyi * f(3, i + 1, j) + cy * f(3, i + 1, j + 1))); + fval(iadr - 1) = sum; } - if ((ict[3] > 0) || (ict[0] == -1)) { - // Evaluate d2f/dx2 - iaval++; - fval(iaval - 1) = - 2.0 * (fspl(2, 0, i, j) + - dy * (fspl(2, 1, i, j) + - dy * (fspl(2, 2, i, j) + dy * fspl(2, 3, i, j)))) + - 6.0 * dx * - (fspl(3, 0, i, j) + - dy * (fspl(3, 1, i, j) + - dy * (fspl(3, 2, i, j) + dy * fspl(3, 3, i, j)))); + // df/dy + if (ict[2] == 1) { + iadr++; + T xp = xparam, xpi = 1.0 - xp; + T xp2 = xp * xp, xpi2 = xpi * xpi; + T cx = xp * (xp2 - 1.0); + T cxi = xpi * (xpi2 - 1.0); + T hx2 = hx * hx; + T yp = yparam, ypi = 1.0 - yp; + T yp2 = yp * yp, ypi2 = ypi * ypi; + T cyd = 3.0 * yp2 - 1.0; + T cydi = -3.0 * ypi2 + 1.0; + + T sum = hyi * (xpi * (-f(0, i, j) + f(0, i, j + 1)) + + xp * (-f(0, i + 1, j) + f(0, i + 1, j + 1))); + sum += sixth * hx2 * hyi * + (cxi * (-f(1, i, j) + f(1, i, j + 1)) + + cx * (-f(1, i + 1, j) + f(1, i + 1, j + 1))); + sum += sixth * hy * + (xpi * (cydi * f(2, i, j) + cyd * f(2, i, j + 1)) + + xp * (cydi * f(2, i + 1, j) + cyd * f(2, i + 1, j + 1))); + sum += z36th * hx2 * hy * + (cxi * (cydi * f(3, i, j) + cyd * f(3, i, j + 1)) + + cx * (cydi * f(3, i + 1, j) + cyd * f(3, i + 1, j + 1))); + fval(iadr - 1) = sum; } - if ((ict[4] > 0) || (ict[0] == -1)) { - // Evaluate d2f/dy2 - iaval++; - fval(iaval - 1) = - 2.0 * fspl(0, 2, i, j) + 6.0 * dy * fspl(0, 3, i, j) + - dx * (2.0 * fspl(1, 2, i, j) + 6.0 * dy * fspl(1, 3, i, j) + - dx * (2.0 * fspl(2, 2, i, j) + 6.0 * dy * fspl(2, 3, i, j) + - dx * (2.0 * fspl(3, 2, i, j) + - 6.0 * dy * fspl(3, 3, i, j)))); + // d2f/dx2 + if (ict[3] == 1) { + iadr++; + T xp = xparam, xpi = 1.0 - xp; + T yp = yparam, ypi = 1.0 - yp; + T yp2 = yp * yp, ypi2 = ypi * ypi; + T cy = yp * (yp2 - 1.0); + T cyi = ypi * (ypi2 - 1.0); + T hy2 = hy * hy; + + T sum = xpi * (ypi * f(1, i, j) + yp * f(1, i, j + 1)) + + xp * (ypi * f(1, i + 1, j) + yp * f(1, i + 1, j + 1)); + sum += sixth * hy2 * + (xpi * (cyi * f(3, i, j) + cy * f(3, i, j + 1)) + + xp * (cyi * f(3, i + 1, j) + cy * f(3, i + 1, j + 1))); + fval(iadr - 1) = sum; } - if ((ict[5] > 0) && (ict[0] != -1)) { - // Evaluate d2f/dxdy - iaval++; - fval(iaval - 1) = - fspl(1, 1, i, j) + - dy * (2.0 * fspl(1, 2, i, j) + dy * 3.0 * fspl(1, 3, i, j)) + - 2.0 * dx * - (fspl(2, 1, i, j) + - dy * (2.0 * fspl(2, 2, i, j) + dy * 3.0 * fspl(2, 3, i, j)) + - 1.5 * dx * - (fspl(3, 1, i, j) + dy * (2.0 * fspl(3, 2, i, j) + - dy * 3.0 * fspl(3, 3, i, j)))); + // d2f/dy2 + if (ict[4] == 1) { + iadr++; + T xp = xparam, xpi = 1.0 - xp; + T xp2 = xp * xp, xpi2 = xpi * xpi; + T cx = xp * (xp2 - 1.0); + T cxi = xpi * (xpi2 - 1.0); + T hx2 = hx * hx; + T yp = yparam, ypi = 1.0 - yp; + + T sum = xpi * (ypi * f(2, i, j) + yp * f(2, i, j + 1)) + + xp * (ypi * f(2, i + 1, j) + yp * f(2, i + 1, j + 1)); + sum += sixth * hx2 * + (cxi * (ypi * f(3, i, j) + yp * f(3, i, j + 1)) + + cx * (ypi * f(3, i + 1, j) + yp * f(3, i + 1, j + 1))); + fval(iadr - 1) = sum; } - if (ict[0] == -1) { - // Evaluate d4f/dx2dy2 - iaval++; - fval(iaval - 1) = - 4.0 * fspl(2, 2, i, j) + 12.0 * dy * fspl(2, 3, i, j) + - dx * (12.0 * fspl(3, 2, i, j) + 36.0 * dy * fspl(3, 3, i, j)); + // d2f/dxdy + if (ict[5] == 1) { + iadr++; + T xp = xparam, xpi = 1.0 - xp; + T xp2 = xp * xp, xpi2 = xpi * xpi; + T cxd = 3.0 * xp2 - 1.0; + T cxdi = -3.0 * xpi2 + 1.0; + T yp = yparam, ypi = 1.0 - yp; + T yp2 = yp * yp, ypi2 = ypi * ypi; + T cyd = 3.0 * yp2 - 1.0; + T cydi = -3.0 * ypi2 + 1.0; + + T sum = + hxi * hyi * + (f(0, i, j) - f(0, i, j + 1) - f(0, i + 1, j) + f(0, i + 1, j + 1)); + sum += sixth * hx * hyi * + (cxdi * (-f(1, i, j) + f(1, i, j + 1)) + + cxd * (-f(1, i + 1, j) + f(1, i + 1, j + 1))); + sum += sixth * hxi * hy * + (-(cydi * f(2, i, j) + cyd * f(2, i, j + 1)) + + (cydi * f(2, i + 1, j) + cyd * f(2, i + 1, j + 1))); + sum += z36th * hx * hy * + (cxdi * (cydi * f(3, i, j) + cyd * f(3, i, j + 1)) + + cxd * (cydi * f(3, i + 1, j) + cyd * f(3, i + 1, j + 1))); + fval(iadr - 1) = sum; } - } else if (ict[0] == 3) { + } + + // ict[0] = 3 → 3rd‑order derivative combinations + else if (ict[0] == 3) { + // d3f/dx3 if (ict[1] == 1) { - // d³f/dx³ (not continuous) - iaval++; - fval(iaval - 1) = - 6.0 * (fspl(3, 0, i, j) + - dy * (fspl(3, 1, i, j) + - dy * (fspl(3, 2, i, j) + dy * fspl(3, 3, i, j)))); + iadr++; + T yp = yparam, ypi = 1.0 - yp; + T yp2 = yp * yp, ypi2 = ypi * ypi; + T cy = yp * (yp2 - 1.0); + T cyi = ypi * (ypi2 - 1.0); + T hy2 = hy * hy; + T sum = hxi * (-(ypi * f(1, i, j) + yp * f(1, i, j + 1)) + + (ypi * f(1, i + 1, j) + yp * f(1, i + 1, j + 1))); + sum += sixth * hy2 * hxi * + (-(cyi * f(3, i, j) + cy * f(3, i, j + 1)) + + (cyi * f(3, i + 1, j) + cy * f(3, i + 1, j + 1))); + fval(iadr - 1) = sum; } + // d3f/dx2dy if (ict[2] == 1) { - // d³f/dx²dy - iaval++; - fval(iaval - 1) = - 2.0 * (fspl(2, 1, i, j) + - dy * (2.0 * fspl(2, 2, i, j) + dy * 3.0 * fspl(2, 3, i, j))) + - 6.0 * dx * - (fspl(3, 1, i, j) + - dy * (2.0 * fspl(3, 2, i, j) + dy * 3.0 * fspl(3, 3, i, j))); + iadr++; + T xp = xparam, xpi = 1.0 - xp; + T yp = yparam, ypi = 1.0 - yp; + T yp2 = yp * yp, ypi2 = ypi * ypi; + T cyd = 3.0 * yp2 - 1.0; + T cydi = -3.0 * ypi2 + 1.0; + T sum = hyi * (xpi * (-f(1, i, j) + f(1, i, j + 1)) + + xp * (-f(1, i + 1, j) + f(1, i + 1, j + 1))); + sum += sixth * hy * + (xpi * (cydi * f(3, i, j) + cyd * f(3, i, j + 1)) + + xp * (cydi * f(3, i + 1, j) + cyd * f(3, i + 1, j + 1))); + fval(iadr - 1) = sum; } + // d3f/dxdy2 if (ict[3] == 1) { - // d³f/dxdy² - iaval++; - fval(iaval - 1) = - 2.0 * fspl(1, 2, i, j) + 6.0 * dy * fspl(1, 3, i, j) + - 2.0 * dx * - (2.0 * fspl(2, 2, i, j) + 6.0 * dy * fspl(2, 3, i, j) + - 1.5 * dx * - (2.0 * fspl(3, 2, i, j) + 6.0 * dy * fspl(3, 3, i, j))); + iadr++; + T xp = xparam, xpi = 1.0 - xp; + T xp2 = xp * xp, xpi2 = xpi * xpi; + T cxd = 3.0 * xp2 - 1.0; + T cxdi = -3.0 * xpi2 + 1.0; + T yp = yparam, ypi = 1.0 - yp; + T sum = hxi * (-(ypi * f(2, i, j) + yp * f(2, i, j + 1)) + + (ypi * f(2, i + 1, j) + yp * f(2, i + 1, j + 1))); + sum += sixth * hx * + (cxdi * (ypi * f(3, i, j) + yp * f(3, i, j + 1)) + + cxd * (ypi * f(3, i + 1, j) + yp * f(3, i + 1, j + 1))); + fval(iadr - 1) = sum; } + // d3f/dy3 if (ict[4] == 1) { - // d³f/dy³ (not continuous) - iaval++; - fval(iaval - 1) = - 6.0 * (fspl(0, 3, i, j) + - dx * (fspl(1, 3, i, j) + - dx * (fspl(2, 3, i, j) + dx * fspl(3, 3, i, j)))); + iadr++; + T xp = xparam, xpi = 1.0 - xp; + T xp2 = xp * xp, xpi2 = xpi * xpi; + T cx = xp * (xp2 - 1.0); + T cxi = xpi * (xpi2 - 1.0); + T hx2 = hx * hx; + T sum = hyi * (xpi * (-f(2, i, j) + f(2, i, j + 1)) + + xp * (-f(2, i + 1, j) + f(2, i + 1, j + 1))); + sum += sixth * hx2 * hyi * + (cxi * (-f(3, i, j) + f(3, i, j + 1)) + + cx * (-f(3, i + 1, j) + f(3, i + 1, j + 1))); + fval(iadr - 1) = sum; } + } - } else if (ict[0] == 4) { + // ict[0] = 4 → 4th‑order derivative combinations + else if (ict[0] == 4) { + // d4f/dx3dy if (ict[1] == 1) { - // d⁴f/dx³dy - iaval++; - fval(iaval - 1) = - 6.0 * (fspl(3, 1, i, j) + - dy * 2.0 * (fspl(3, 2, i, j) + dy * 1.5 * fspl(3, 3, i, j))); + iadr++; + T yp = yparam, ypi = 1.0 - yp; + T yp2 = yp * yp, ypi2 = ypi * ypi; + T cyd = 3.0 * yp2 - 1.0; + T cydi = -3.0 * ypi2 + 1.0; + T sum = + hxi * hyi * + (f(1, i, j) - f(1, i, j + 1) - f(1, i + 1, j) + f(1, i + 1, j + 1)); + sum += sixth * hy * hxi * + (-(cydi * f(3, i, j) + cyd * f(3, i, j + 1)) + + (cydi * f(3, i + 1, j) + cyd * f(3, i + 1, j + 1))); + fval(iadr - 1) = sum; } + // d4f/dx2dy2 if (ict[2] == 1) { - // d⁴f/dx²dy² - iaval++; - fval(iaval - 1) = - 4.0 * fspl(2, 2, i, j) + 12.0 * dy * fspl(2, 3, i, j) + - dx * (12.0 * fspl(3, 2, i, j) + 36.0 * dy * fspl(3, 3, i, j)); + iadr++; + T xp = xparam, xpi = 1.0 - xp; + T yp = yparam, ypi = 1.0 - yp; + T sum = xpi * (ypi * f(3, i, j) + yp * f(3, i, j + 1)) + + xp * (ypi * f(3, i + 1, j) + yp * f(3, i + 1, j + 1)); + fval(iadr - 1) = sum; } + // d4f/dxdy3 if (ict[3] == 1) { - // d⁴f/dxdy³ (not continuous) - iaval++; - fval(iaval - 1) = - 6.0 * (fspl(1, 3, i, j) + - 2.0 * dx * (fspl(2, 3, i, j) + 1.5 * dx * fspl(3, 3, i, j))); + iadr++; + T xp = xparam, xpi = 1.0 - xp; + T xp2 = xp * xp, xpi2 = xpi * xpi; + T cxd = 3.0 * xp2 - 1.0; + T cxdi = -3.0 * xpi2 + 1.0; + T sum = + hxi * hyi * + (f(2, i, j) - f(2, i, j + 1) - f(2, i + 1, j) + f(2, i + 1, j + 1)); + sum += sixth * hx * hyi * + (cxdi * (-f(3, i, j) + f(3, i, j + 1)) + + cxd * (-f(3, i + 1, j) + f(3, i + 1, j + 1))); + fval(iadr - 1) = sum; } + } - } else if (ict[0] == 5) { + // ict[0] = 5 → 5th‑order derivative combinations + else if (ict[0] == 5) { + // d5f/dx3dy2 if (ict[1] == 1) { - // d⁵f/dx³dy² (not continuous) - iaval++; - fval(iaval - 1) = 12.0 * (fspl(3, 2, i, j) + dy * 3.0 * fspl(3, 3, i, j)); + iadr++; + T yp = yparam, ypi = 1.0 - yp; + T sum = hxi * (-(ypi * f(3, i, j) + yp * f(3, i, j + 1)) + + (ypi * f(3, i + 1, j) + yp * f(3, i + 1, j + 1))); + fval(iadr - 1) = sum; } + // d5f/dx2dy3 if (ict[2] == 1) { - // d⁵f/dx²dy³ (not continuous) - iaval++; - fval(iaval - 1) = 12.0 * (fspl(2, 3, i, j) + dx * 3.0 * fspl(3, 3, i, j)); + iadr++; + T xp = xparam, xpi = 1.0 - xp; + T sum = hyi * (xpi * (-f(3, i, j) + f(3, i, j + 1)) + + xp * (-f(3, i + 1, j) + f(3, i + 1, j + 1))); + fval(iadr - 1) = sum; } - - } else if (ict[0] == 6) { - // d⁶f/dx³dy³ (not continuous) - iaval++; - fval(iaval - 1) = 36.0 * fspl(3, 3, i, j); } -} // end evalfn -template -CompactBiCubicSplineInterpolator:: - CompactBiCubicSplineInterpolator( - Rank1View x, Rank1View y, - Rank1View values, LO ibcxmin, - Rank1View bcxmin, LO ibcxmax, - Rank1View bcxmax, LO ibcymin, - Rank1View bcymin, LO ibcymax, - Rank1View bcymax) { - ExplicitBiCubicSplineInterpolator::sanity_check( - x, y, ibcxmin, bcxmin, ibcxmax, bcxmax, ibcymin, bcymin, ibcymax, bcymax); - - setup(x, y, values, ibcxmin, bcxmin, ibcxmax, bcxmax, ibcymin, bcymin, - ibcymax, bcymax); + // ict[0] = 6 → 6th‑order derivative (dx³dy³) + else if (ict[0] == 6) { + iadr++; + T sum = hxi * hyi * + (f(3, i, j) - f(3, i, j + 1) - f(3, i + 1, j) + f(3, i + 1, j + 1)); + fval(iadr - 1) = sum; + } } +/** \brief Evaluate the bicubic spline at a single point with selector + * + * \param xget input point in x direction where the spline is evaluated + * \param yget input point in y direction where the spline is evaluated + * \param ict selector array indicating which derivatives to compute + * \param fval output values of the spline at given point + * \param x input grid points in x direction + * \param nx number of grid points in x direction + * \param y input grid points in y direction + * \param ny number of grid points in y direction + * \param f bicubic spline coefficients + * \param ier error flag, 0 if successful, non-zero otherwise + */ template -void CompactBiCubicSplineInterpolator::setup( - Rank1View x, Rank1View y, - Rank1View values, LO ibcxmin, - Rank1View bcxmin, LO ibcxmax, - Rank1View bcxmax, LO ibcymin, - Rank1View bcymin, LO ibcymax, - Rank1View bcymax) { - LO ny = this->ny_; - LO nx = this->nx_; - Kokkos::View fspl_view("fspl view", 4 * nx * ny); - ExplicitCubicSplineInterpolator::set_coefficients(fspl_view); - auto fspl = Rank3View(fspl_view.data(), 4, nx, ny); - - Kokkos::parallel_for( - Kokkos::MDRangePolicy>({0, 0}, {ny, nx}), - KOKKOS_LAMBDA(const LO iy, const LO ix) { - fspl(0, ix, iy) = values(ix * ny + iy); - }); +KOKKOS_INLINE_FUNCTION void bicubic_eval_compact( + T xget, T yget, Kokkos::View ict, + Rank1View fval, // output (size depends on ict) + Rank1View x, const LO &nx, Rank1View y, + const LO &ny, Rank3View f, // input (size depends on ict) + LO &ier) { + // Local variables + LO i = 0, j = 0; + T xparam = 0.0, yparam = 0.0; + T hx = 0.0, hy = 0.0; + T hxi = 0.0, hyi = 0.0; - Kokkos::View wk_view("wk", 9 * nx * ny); - auto wk = Rank1View(wk_view.data(), 9 * nx * ny); + // Call herm2xy to locate cell and compute params + bicubic_lookup_compact(xget, yget, x, nx, y, ny, i, j, xparam, yparam, hx, + hxi, hy, hyi, ier); - solve_spline(x, this->nx_, y, this->ny_, fspl, ibcxmin, bcxmin, ibcxmax, - bcxmax, ibcymin, bcymin, ibcymax, bcymax, wk); - this->fspl_ = fspl; // Store the spline coefficients -} + if (ier != 0) + return; -template -CompactBiCubicSplineInterpolator:: - CompactBiCubicSplineInterpolator(Rank1View x, // size: inx - Rank1View y, // size: iny - Rank1View values) - : CompactBiCubicSplineInterpolator(x, y, values, 0, {}, 0, {}, 0, {}, 0, - {}) { // Delegates to primary constructor - std::cout << "Not a knot boundary condition is applied by default" - << std::endl; + // Call evalfn with scalar-vector LOerface + bicubic_evalfn_compact(ict, 1, 1, fval, i, j, xparam, yparam, hx, hxi, hy, + hyi, f); } template -void CompactBiCubicSplineInterpolator::solve_spline( - Rank1View x, LO nx, Rank1View y, LO ny, - Rank3View f, LO ibcxmin, Rank1View bcxmin, - LO ibcxmax, Rank1View bcxmax, LO ibcymin, - Rank1View bcymin, LO ibcymax, - Rank1View bcymax, Rank1View wk) { +void solve_bicubic_spline_compact(Rank1View x, LO nx, + Rank1View y, LO ny, + Rank3View f, LO ibcxmin, + Rank1View bcxmin, LO ibcxmax, + Rank1View bcxmax, LO ibcymin, + Rank1View bcymin, LO ibcymax, + Rank1View bcymax, + Rank1View wk) { + using execution_space = typename MemorySpace::execution_space; + using member_type = typename Kokkos::TeamPolicy::member_type; LO iflg2 = 0; // Check if inhomogeneous y-boundary conditions exist if (ibcymin != -1) { - ExplicitBiCubicSplineInterpolator::correction_detect( - bcymin, ibcymin, iflg2, nx); - ExplicitBiCubicSplineInterpolator::correction_detect( - bcymax, ibcymax, iflg2, nx); + correction_detect(bcymin, ibcymin, iflg2, nx); + correction_detect(bcymax, ibcymax, iflg2, nx); } auto fspl_l_x = Rank2View(wk.data_handle(), 2 * ny, nx); @@ -2426,9 +1902,8 @@ void CompactBiCubicSplineInterpolator::solve_spline( if (ibcxmax == 1 || ibcxmax == 2) zbcmax = bcxmax[iy]; - CompactCubicSplineInterpolator::solve_spline( - x, nx, fwk_x_view, fwk4_x_view, ibcxmin, zbcmin, ibcxmax, zbcmax, - wk_x_view); + solve_cubic_spline_compact(x, nx, fwk_x_view, fwk4_x_view, ibcxmin, + zbcmin, ibcxmax, zbcmax, wk_x_view); } Kokkos::parallel_for(Kokkos::TeamThreadRange(team, nx), @@ -2459,9 +1934,8 @@ void CompactBiCubicSplineInterpolator::solve_spline( ibcmax = 0; } - CompactCubicSplineInterpolator::solve_spline( - y, ny, fwk_y_view, fwk4_y_view, ibcmin, 0.0, ibcmax, 0.0, - wk_y_view); + solve_cubic_spline_compact(y, ny, fwk_y_view, fwk4_y_view, ibcmin, + 0.0, ibcmax, 0.0, wk_y_view); } Kokkos::parallel_for(Kokkos::TeamThreadRange(team, ny), [=](LO iy) { f(2, ix, iy) = fwk_y_view(1, iy); }); @@ -2491,16 +1965,15 @@ void CompactBiCubicSplineInterpolator::solve_spline( ibcmax = 0; } - CompactCubicSplineInterpolator::solve_spline( - y, ny, fwk_y_view, fwk4_y_view, ibcmin, 0.0, ibcmax, 0.0, - wk_y_view); + solve_cubic_spline_compact(y, ny, fwk_y_view, fwk4_y_view, ibcmin, + 0.0, ibcmax, 0.0, wk_y_view); } Kokkos::parallel_for(Kokkos::TeamThreadRange(team, ny), [=](LO iy) { f(3, ix, iy) = fwk_y_view(1, iy); }); }); - LO zbcmin = 0.0; - LO zbcmax = 0.0; + T zbcmin = 0.0; + T zbcmax = 0.0; // Correct for inhomogeneous boundary conditions if needed if (iflg2 == 1) { @@ -2545,9 +2018,8 @@ void CompactBiCubicSplineInterpolator::solve_spline( Kokkos::parallel_for(Kokkos::TeamThreadRange(team, ny), [=](LO iy) { fwk_y_view(0, iy) = 0.0; }); if (team.team_rank() == 0) { - CompactCubicSplineInterpolator::solve_spline( - y, ny, fwk_y_view, fwk4_y_view, ibcymin, zdiff1, ibcymax, - zdiff2, wk_y_view); + solve_cubic_spline_compact(y, ny, fwk_y_view, fwk4_y_view, ibcymin, + zdiff1, ibcymax, zdiff2, wk_y_view); } Kokkos::parallel_for(Kokkos::TeamThreadRange(team, ny), [=](LO iy) { fcorr(0, ix, iy) = fwk_y_view(1, iy); @@ -2570,9 +2042,8 @@ void CompactBiCubicSplineInterpolator::solve_spline( }); if (team.team_rank() == 0) { - CompactCubicSplineInterpolator::solve_spline( - x, nx, fwk_x_view, fwk4_x_view, ibcxmin, zbcmin, ibcxmax, - zbcmax, wk_x_view); + solve_cubic_spline_compact(x, nx, fwk_x_view, fwk4_x_view, ibcxmin, + zbcmin, ibcxmax, zbcmax, wk_x_view); } Kokkos::parallel_for(Kokkos::TeamThreadRange(team, nx), [=](LO ix) { @@ -2589,374 +2060,899 @@ void CompactBiCubicSplineInterpolator::solve_spline( } } +} // namespace detail + +/** \brief Boundary condition options for spline interpolation + * + * This enum defines the various boundary conditions that can be applied + * during spline interpolation. The boundary condition flags can take the + * following values: PERIODIC | ibcxmin=-1 | ibcxmax=-1 -- periodic boundary + * condition, where s'(x(0))=s'(x(-1)) and s''(x(0))=s''(x(-1)). NOT_A_KNOT | + * ibcxmin=0 | ibcxmax=0 -- not-a-knot boundary condition. + * FIRST_DERIVATIVE_MATCH | ibcxmin=1 | ibcxmax=1 -- first derivative match at + * x(0) or x(-1). SECOND_DERIVATIVE_MATCH | ibcxmin=2 | ibcxmax=2 -- second + * derivative match at x(0) or x(-1). FIRST_DERIVATIVE_ZERO | ibcxmin=3 | + * ibcxmax=3 -- first derivative equal to zero at x(0) or x(-1). + * SECOND_DERIVATIVE_ZERO | ibcxmin=4 | ibcxmax=4 -- second derivative equal + * to zero at x(0) or x(-1). FIRST_DIV_DIFF_MATCH | ibcxmin=5 | ibcxmax=5 -- + * first derivative matches the first divided difference. SECOND_DIV_DIFF_MATCH + * | ibcxmin=6 | ibcxmax=6 -- second derivative matches the second divided + * difference. THIRD_DIV_DIFF_MATCH | ibcxmin=7 | ibcxmax=7 -- third + * derivative matches the third divided difference. + */ +enum BoundaryCondition { + PERIODIC = -1, ///< Periodic boundary condition: s'(x(0))=s'(x(-1)) and + ///< s''(x(0))=s''(x(-1)) + NOT_A_KNOT = 0, ///< Not-a-knot boundary condition + FIRST_DERIVATIVE_MATCH = 1, ///< First derivative match at boundary + SECOND_DERIVATIVE_MATCH = 2, ///< Second derivative match at boundary + FIRST_DERIVATIVE_ZERO = 3, ///< First derivative equal to zero at boundary + SECOND_DERIVATIVE_ZERO = 4, ///< Second derivative equal to zero at boundary + FIRST_DIV_DIFF_MATCH = + 5, ///< First derivative matches first divided difference + SECOND_DIV_DIFF_MATCH = + 6, ///< Second derivative matches second divided difference + THIRD_DIV_DIFF_MATCH = + 7 ///< Third derivative matches third divided difference +}; + +/** \brief CubicSplineInterpolator class + * + * \details Derived from from Princeton Splines library + * Original developers: PPPL Computational Plasma Physics Group + * Original release: February 5, 1999 + */ +template class CubicSplineInterpolator { +public: + using execution_space = typename MemorySpace::execution_space; + + virtual void evaluate(Rank1View xvec, + Rank2View fval) = 0; + virtual void evaluate(Kokkos::View selector, + Rank1View xvec, + Rank2View fval) = 0; + +protected: + Rank1View x_; + + Kokkos::View get_coefficients(); + void set_coefficients(Kokkos::View coefficients); + + void sanity_check(Rank1View x); + +private: + Kokkos::View coefficients_; +}; + +/** \brief ExplicitCubicSplineInterpolator class + * + * \details This class provides methods for 1d explicit cubic spline + * interpolation and serves as a base class for higher dimensions and compact + * cubic spline interpolator implementations. + * + * The 1d explicit cubic spline are evaluated using the following formula: + * s(x)=C(1,i)+(x-x(i))*C(2,i)+(x-x(i))**2*C(3,i)+(x-x(i))**3*C(4,i) + * for x(i).le.x.le.x(i+1) + * where C(1,i), C(2,i), C(3,i), and C(4,i) are the coefficients of the cubic + * spline. + * + * Performance considerations: The memory cost of coeeficients are: + * - explicit -- 4**dimension*(N1*N2*...*Nn) + * - compact -- 2**dimension*(N1*N2*...*Nn) + * Explicit spline representation offers better performance in 1D cases. + * (Compact representations actually call the explicit spline setup functions.) + * Compact spline representation provides performance advantages in higher + * dimensions due to memory efficiency gains that outweigh the modest increase + * in computational cost. + */ template -KOKKOS_INLINE_FUNCTION void -CompactBiCubicSplineInterpolator::lookup( - T xget, T yget, Rank1View x, const LO &nx, - Rank1View y, const LO &ny, LO &i, LO &j, T &xparam, - T &yparam, T &hx, T &hxi, T &hy, T &hyi, LO &ier) { - ier = 0; +class ExplicitCubicSplineInterpolator + : public CubicSplineInterpolator { +public: + using execution_space = typename MemorySpace::execution_space; + using member_type = typename Kokkos::TeamPolicy::member_type; + ExplicitCubicSplineInterpolator() = default; - T zxget = xget; - T zyget = yget; + /** \brief Construct the interpolator object and set up the coefficients + * + * \param x input grid points + * \param values values of given grid points + * \param ibcxmin bounday condition flag at x(0) + * \param bcxmin bounday condition data at x(0) + * \param ibcxmax bounday condition flag at x(-1) + * \param bcxmax bounday condition data at x(-1) + */ + ExplicitCubicSplineInterpolator(Rank1View x, + Rank1View values, + BoundaryCondition ibcxmin, const T &bcxmin, + BoundaryCondition ibcxmax, const T &bcxmax); + + /** \brief Construct the interpolator object and set up the coefficients with + * default boundary conditions + * + * \param x input grid points + * \param values values of given grid points + * + * \details The boundary condition flags are set to 0, which corresponds to + * not-a-knot boundary condition. + */ + ExplicitCubicSplineInterpolator(Rank1View x, + Rank1View values); - ExplicitCubicSplineInterpolator::inGrid(xget, zxget, x, nx, - ier); - ExplicitCubicSplineInterpolator::inGrid(yget, zyget, y, ny, - ier); + /** \brief Evaluate the function value of cubic spline at given points + * + * \param xvec input points where the spline is evaluated + * \param fval output values of the spline at given points + * + * \details The size of fval should match the size of xvec. + */ + void evaluate(Rank1View xvec, + Rank2View fval) override; - LO nxm = nx - 1; // Number of LOervals in x - LO nym = ny - 1; // Number of LOervals in y - // Determine zone index i - LO ii = static_cast(nxm * (zxget - x[0]) / (x[nx - 1] - x[0])); - i = std::min(nxm - 1, ii); - if (zxget < x[i]) - --i; - else if (zxget > x[i + 1]) - ++i; + /** \brief Evaluate the cubic spline at given points with selector + * + * \param selector selector array indicating which derivatives to compute + * \param xvec input points where the spline is evaluated + * \param fval output values of the spline at given points + * + * \details The size of fval should match the size of xvec and the size of + * selector. The selector array can be used to specify which derivatives to + * compute. For example, if selector = {1, 1, 0}, then the function value and + * first derivative will be computed. + */ + void evaluate(Kokkos::View selector, + Rank1View xvec, + Rank2View fval) override; + +private: + Rank2View get_coefficients(); +}; + +/** + * CompactCubicSplineInterpolator class + * This class provides methods for 1d compact cubic spline interpolation. + * It inherits from ExplicitCubicSplineInterpolator and implements the + * compact representation of cubic spline coefficients. + * + * The 1d compact cubic spline are evaluated using the following formula: + * If x(i).le.x.le.x(i+1), let + * h = (x(i+1)-x(i)) + * p = (x-x(i))/h + * q = 1-p + * s(x)= q*D(1,i) + p*D(1,i+1) + + * (h**2/6)*{[q**3-q]*D(2,i) + [p**3-p]*D(2,i+1)} + * where D(1,i) and D(2,i) are the coefficients of the compact cubic spline. + */ +template +class CompactCubicSplineInterpolator + : public CubicSplineInterpolator { +public: + using execution_space = typename MemorySpace::execution_space; + using member_type = typename Kokkos::TeamPolicy::member_type; + CompactCubicSplineInterpolator() = default; + /** \brief Construct the interpolator object and set up the coefficients + * + * \param x input grid points + * \param values values of given grid points + * \param ibcxmin bounday condition flag at x(0) + * \param bcxmin bounday condition data at x(0) + * \param ibcxmax bounday condition flag at x(-1) + * \param bcxmax bounday condition data at x(-1) + */ + CompactCubicSplineInterpolator(Rank1View x, + Rank1View values, + BoundaryCondition ibcxmin, const T &bcxmin, + BoundaryCondition ibcxmax, const T &bcxmax); + + /** \brief Construct the interpolator object and set up the coefficients with + * default boundary conditions + * + * \param x input grid points + * \param values values of given grid points + */ + CompactCubicSplineInterpolator(Rank1View x, + Rank1View values); + + /** \brief Evaluate the function value of compact cubic spline at given points + * + * \param xvec input points where the spline is evaluated + * \param fval output values of the spline at given points + */ + void evaluate(Rank1View xvec, + Rank2View fval) override; + + /** \brief Evaluate the compact cubic spline at given points with selector + * + * \param selector selector array indicating which derivatives to compute + * \param xvec input points where the spline is evaluated + * \param fval output values of the spline at given points + * + * \details The selector follows the same rules as in + * ExplicitCubicSplineInterpolator. + */ + void evaluate(Kokkos::View selector, + Rank1View xvec, + Rank2View fval) override; + +private: + Rank2View get_coefficients(); +}; + +template class BiCubicSplineInterpolator { +public: + using execution_space = typename MemorySpace::execution_space; + virtual void evaluate(Rank1View xvec, + Rank1View yvec, + Rank2View fval) = 0; + virtual void evaluate(Kokkos::View selector, + Rank1View xvec, + Rank1View yvec, + Rank2View fval) = 0; + +protected: + Rank1View x_; + Rank1View y_; + + Kokkos::View get_coefficients(); + + void set_coefficients(Kokkos::View coefficients); + + void sanity_check(Rank1View x, Rank1View y); + +private: + Kokkos::View coefficients_; +}; + +/** \brief BiCubicSplineInterpolator class + * This class provides methods for 2D explicit bicubic spline interpolation. + * It inherits from ExplicitCubicSplineInterpolator and implements the bicubic + * representation of cubic spline coefficients. + * + * The 2D explicit bicubic spline are evaluated using the following formula: + * s(x,y)= C11 + dx*C21 + dx**2*C31 + dx**3*C41 + * +dy*(C12 + dx*C22 + dx**2*C32 + dx**3*C42) + * +dy**2*(C13 + dx*C23 + dx**2*C33 + dx**3*C43) + * +dy**3*(C14 + dx*C24 + dx**2*C34 + dx**3*C44) + * where Cij are the coefficients of the bicubic spline. + */ +template +class ExplicitBiCubicSplineInterpolator + : public BiCubicSplineInterpolator { +public: + using execution_space = typename MemorySpace::execution_space; + using member_type = typename Kokkos::TeamPolicy::member_type; + + ExplicitBiCubicSplineInterpolator() = default; + + /** \brief Construct the interpolator object and set up the coefficients + * + * \param x input grid points in x direction + * \param y input grid points in y direction + * \param values values of given grid points + * \param ibcxmin boundary condition flag at x(0) + * \param bcxmin boundary condition data at x(0) + * \param ibcxmax boundary condition flag at x(-1) + * \param bcxmax boundary condition data at x(-1) + * \param ibcymin boundary condition flag at y(0) + * \param bcymin boundary condition data at y(0) + * \param ibcymax boundary condition flag at y(-1) + * \param bcymax boundary condition data at y(-1) + * + * \details The boundary condition flags take the same values as in + * CubicSplineInterpolator at each direction. + */ + ExplicitBiCubicSplineInterpolator( + Rank1View x, Rank1View y, + Rank1View values, BoundaryCondition ibcxmin, + Rank1View bcxmin, BoundaryCondition ibcxmax, + Rank1View bcxmax, BoundaryCondition ibcymin, + Rank1View bcymin, BoundaryCondition ibcymax, + Rank1View bcymax); + + /** \brief Construct the interpolator object and set up the coefficients with + * default boundary conditions + * + * \param x input grid points in x direction + * \param y input grid points in y direction + * \param values values of given grid points + */ + ExplicitBiCubicSplineInterpolator(Rank1View x, + Rank1View y, + Rank1View values); + + /** \brief Evaluate the bicubic spline at given points + * + * \param xvec input points in x direction where the spline is evaluated + * \param yvec input points in y direction where the spline is evaluated + * \param fval output values of the spline at given points + */ + void evaluate(Rank1View xvec, Rank1View yvec, + Rank2View fval) override; + + /** \brief Evaluate the bicubic spline at given points with selector + * + * \param iselect selector array indicating which derivatives to compute + * \param xvec input points in x direction where the spline is evaluated + * \param yvec input points in y direction where the spline is evaluated + * \param fval output values of the spline at given points + * + * \details The selector follows the the following rules: + * iselect(1)=1 -- evaluate f + * iselect(2)=1 -- evaluate df/dx + * iselect(3)=1 -- evaluate df/dy + * iselect(4)=1 -- evaluate d2f/dx2 + * iselect(5)=1 -- evaluate d2f/dy2 + * iselect(6)=1 -- evaluate d2f/dxdy + */ + void evaluate(Kokkos::View iselect, + Rank1View xvec, Rank1View yvec, + Rank2View fval) override; + +private: + Rank4View get_coefficients(); +}; + +/** \brief CompactBiCubicSplineInterpolator class + * This class provides methods for 2D compact bicubic spline interpolation. + * It inherits from ExplicitBiCubicSplineInterpolator and implements the compact + * representation of bicubic spline coefficients. + * + * The 2D compact bicubic spline are evaluated using the following formula: + * for x(i).le.x.le.x(i+1) and y(j).le.y.le.y(j+1), let + * hx = x(i+1)-x(i) hy = y(j+1)-y(j) + * px = (x-x(i))/hx py = (y-y(j))/hy + * qx = 1-px qy = 1-py + * rx = (px**3-px) ry = (py**3-py) + * sx = (qx**3-qx) sy = (qy**3-qy) + * + * s(x,y) = qx*(qy*D(1,i,j)+py*D(1,i,j+1)) + + * px*(qy*D(1,i+1,j)+py*D(1,i+1,j+1)) + + * (hx**2/6)*{sx*(qy*D(2,i,j)+py*D(2,i,j+1)) + + * rx*(qy*D(2,i+1,j)+py*D(2,i+1,j+1))} + + * (hy**2/6)*{qx*(sy*D(3,i,j)+ry*D(3,i,j+1)) + + * px*(sy*D(3,i+1,j)+ry*D(3,i+1,j+1))} + + * (hx**2*hy**2/36)*{sx*(sy*D(4,i,j)+ry*D(4,i,j+1)) + + * rx*(sy*D(4,i+1,j)+ry*D(4,i+1,j+1))} + */ +template +class CompactBiCubicSplineInterpolator + : public BiCubicSplineInterpolator { +public: + using execution_space = typename MemorySpace::execution_space; + using member_type = typename Kokkos::TeamPolicy::member_type; + + CompactBiCubicSplineInterpolator() = default; + + /** \brief Construct the interpolator object and set up the coefficients + * + * \param x input grid points in x direction + * \param y input grid points in y direction + * \param values values of given grid points + * \param ibcxmin boundary condition flag at x(0) + * \param bcxmin boundary condition data at x(0) + * \param ibcxmax boundary condition flag at x(-1) + * \param bcxmax boundary condition data at x(-1) + * \param ibcymin boundary condition flag at y(0) + * \param bcymin boundary condition data at y(0) + * \param ibcymax boundary condition flag at y(-1) + * \param bcymax boundary condition data at y(-1) + * + * \details The boundary condition flags take the same values as in + * CubicSplineInterpolator at each direction. + */ + CompactBiCubicSplineInterpolator( + Rank1View x, Rank1View y, + Rank1View values, BoundaryCondition ibcxmin, + Rank1View bcxmin, BoundaryCondition ibcxmax, + Rank1View bcxmax, BoundaryCondition ibcymin, + Rank1View bcymin, BoundaryCondition ibcymax, + Rank1View bcymax); + + /** \brief Construct the interpolator object and set up the coefficients with + * default boundary conditions \param x input grid points in x direction + * \param y input grid points in y direction + * \param values values of given grid points + */ + CompactBiCubicSplineInterpolator(Rank1View x, + Rank1View y, + Rank1View values); + + /** \brief Evaluate the bicubic spline at given points + * + * \param xvec input points in x direction where the spline is evaluated + * \param yvec input points in y direction where the spline is evaluated + * \param fval output values of the spline at given points + */ + void evaluate(Rank1View xvec, Rank1View yvec, + Rank2View fval) override; + + /** \brief Evaluate the bicubic spline at given points with selector + * + * \param iselect selector array indicating which derivatives to compute + * \param xvec input points in x direction where the spline is evaluated + * \param yvec input points in y direction where the spline is evaluated + * \param fval output values of the spline at given points + * + * \details The selector follows the same rules as in + * ExplicitBiCubicSplineInterpolator. + */ + void evaluate(Kokkos::View iselect, + Rank1View xvec, Rank1View yvec, + Rank2View fval) override; + +private: + Rank3View get_coefficients(); +}; + +template +Kokkos::View +CubicSplineInterpolator::get_coefficients() { + return coefficients_; +} + +template +void CubicSplineInterpolator::set_coefficients( + Kokkos::View coefficients) { + coefficients_ = coefficients; +} - // Determine zone index j - ii = static_cast(nym * (zyget - y[0]) / (y[ny - 1] - y[0])); - j = std::min(nym - 1, ii); - if (zyget < y[j]) - --j; - else if (zyget > y[j + 1]) - ++j; +template +Rank2View +ExplicitCubicSplineInterpolator::get_coefficients() { + auto coeffs = CubicSplineInterpolator::get_coefficients(); + return Rank2View(coeffs.data(), 4, this->x_.extent(0)); +} - hx = x[i + 1] - x[i]; - hy = y[j + 1] - y[j]; +template +Rank2View +CompactCubicSplineInterpolator::get_coefficients() { + auto coeffs = CubicSplineInterpolator::get_coefficients(); + return Rank2View(coeffs.data(), 2, this->x_.extent(0)); +} - hxi = 1.0 / hx; - hyi = 1.0 / hy; +template +Rank4View +ExplicitBiCubicSplineInterpolator::get_coefficients() { + auto coeffs = BiCubicSplineInterpolator::get_coefficients(); + return Rank4View(coeffs.data(), 4, 4, this->x_.extent(0), + this->y_.extent(0)); +} - xparam = (zxget - x[i]) * hxi; - yparam = (zyget - y[j]) * hyi; +template +Rank3View +CompactBiCubicSplineInterpolator::get_coefficients() { + auto coeffs = BiCubicSplineInterpolator::get_coefficients(); + return Rank3View(coeffs.data(), 4, this->x_.extent(0), + this->y_.extent(0)); } template -KOKKOS_INLINE_FUNCTION void -CompactBiCubicSplineInterpolator::evalfn( - Kokkos::View ict, LO ivec, LO ivecd, - Rank1View fval, const LO &i, const LO &j, const T &xparam, - const T &yparam, const T &hx, const T &hxi, const T &hy, const T &hyi, - Rank3View f) { - constexpr T sixth = 1.0 / 6.0; - const T z36th = sixth * sixth; - LO iadr = 0; +Kokkos::View +BiCubicSplineInterpolator::get_coefficients() { + return coefficients_; +} - // ict[0] = 1 or 2 → f, df/dx, df/dy, d²f/dx², d²f/dy², d²f/dxdy - if (ict[0] <= 2) { - // f (function value) - if (ict[0] == 1) { - iadr++; - T xp = xparam, xpi = 1.0 - xp; - T xp2 = xp * xp, xpi2 = xpi * xpi; - T cx = xp * (xp2 - 1.0); - T cxi = xpi * (xpi2 - 1.0); - T hx2 = hx * hx; +template +void BiCubicSplineInterpolator::set_coefficients( + Kokkos::View coefficients) { + coefficients_ = coefficients; +} - T yp = yparam, ypi = 1.0 - yp; - T yp2 = yp * yp, ypi2 = ypi * ypi; - T cy = yp * (yp2 - 1.0); - T cyi = ypi * (ypi2 - 1.0); - T hy2 = hy * hy; +template +void CubicSplineInterpolator::sanity_check( + Rank1View x) { + PCMS_ALWAYS_ASSERT(x.extent(0) >= 2); + detail::isUniformAscending(x, 1.0e-3); +} - T sum = xpi * (ypi * f(0, i, j) + yp * f(0, i, j + 1)) + - xp * (ypi * f(0, i + 1, j) + yp * f(0, i + 1, j + 1)); - sum += sixth * hx2 * - (cxi * (ypi * f(1, i, j) + yp * f(1, i, j + 1)) + - cx * (ypi * f(1, i + 1, j) + yp * f(1, i + 1, j + 1))); - sum += sixth * hy2 * - (xpi * (cyi * f(2, i, j) + cy * f(2, i, j + 1)) + - xp * (cyi * f(2, i + 1, j) + cy * f(2, i + 1, j + 1))); - sum += z36th * hx2 * hy2 * - (cxi * (cyi * f(3, i, j) + cy * f(3, i, j + 1)) + - cx * (cyi * f(3, i + 1, j) + cy * f(3, i + 1, j + 1))); - fval(iadr - 1) = sum; - } +template struct InitCubicCoeffFunctor { + // Member variables to capture the lambda's captured variables + Rank2View fspl; + Rank1View values; - // df/dx - if (ict[1] == 1) { - iadr++; - T xp = xparam, xpi = 1.0 - xp; - T xp2 = xp * xp, xpi2 = xpi * xpi; - T cxd = 3.0 * xp2 - 1.0; - T cxdi = -3.0 * xpi2 + 1.0; - T yp = yparam, ypi = 1.0 - yp; - T yp2 = yp * yp, ypi2 = ypi * ypi; - T cy = yp * (yp2 - 1.0); - T cyi = ypi * (ypi2 - 1.0); - T hy2 = hy * hy; + // Constructor to initialize captured variables + InitCubicCoeffFunctor(Rank2View fspl_, + Rank1View values_) + : fspl(fspl_), values(values_) {} - T sum = hxi * (-(ypi * f(0, i, j) + yp * f(0, i, j + 1)) + - (ypi * f(0, i + 1, j) + yp * f(0, i + 1, j + 1))); - sum += sixth * hx * - (cxdi * (ypi * f(1, i, j) + yp * f(1, i, j + 1)) + - cxd * (ypi * f(1, i + 1, j) + yp * f(1, i + 1, j + 1))); - sum += sixth * hxi * hy2 * - (-(cyi * f(2, i, j) + cy * f(2, i, j + 1)) + - (cyi * f(2, i + 1, j) + cy * f(2, i + 1, j + 1))); - sum += z36th * hx * hy2 * - (cxdi * (cyi * f(3, i, j) + cy * f(3, i, j + 1)) + - cxd * (cyi * f(3, i + 1, j) + cy * f(3, i + 1, j + 1))); - fval(iadr - 1) = sum; - } + // Operator() that replaces the lambda + KOKKOS_INLINE_FUNCTION + void operator()(const LO i) const { fspl(0, i) = values(i); } +}; - // df/dy - if (ict[2] == 1) { - iadr++; - T xp = xparam, xpi = 1.0 - xp; - T xp2 = xp * xp, xpi2 = xpi * xpi; - T cx = xp * (xp2 - 1.0); - T cxi = xpi * (xpi2 - 1.0); - T hx2 = hx * hx; - T yp = yparam, ypi = 1.0 - yp; - T yp2 = yp * yp, ypi2 = ypi * ypi; - T cyd = 3.0 * yp2 - 1.0; - T cydi = -3.0 * ypi2 + 1.0; +template +struct SolveCompactCubicSplineFunctor { + using execution_space = typename MemorySpace::execution_space; + using member_type = typename Kokkos::TeamPolicy::member_type; + // Member variables to capture the lambda's captured variables + Rank1View x; + LO nx; + Rank2View fspl; + Rank2View fspl4; + LO ibcxmin; + T bcxmin; + LO ibcxmax; + T bcxmax; + Rank1View wk; + + // Constructor to initialize captured variables + SolveCompactCubicSplineFunctor(Rank1View x_, LO nx_, + Rank2View fspl_, + Rank2View fspl4_, LO ibcxmin_, + T bcxmin_, LO ibcxmax_, T bcxmax_, + Rank1View wk_) + : x(x_), nx(nx_), fspl(fspl_), fspl4(fspl4_), ibcxmin(ibcxmin_), + bcxmin(bcxmin_), ibcxmax(ibcxmax_), bcxmax(bcxmax_), wk(wk_) {} + + // Operator() that replaces the lambda + KOKKOS_INLINE_FUNCTION + void operator()(const member_type &team_member) const { + Kokkos::single(Kokkos::PerTeam(team_member), [=]() { + detail::solve_cubic_spline_compact(x, nx, fspl, fspl4, ibcxmin, bcxmin, + ibcxmax, bcxmax, wk); + }); + } +}; - T sum = hyi * (xpi * (-f(0, i, j) + f(0, i, j + 1)) + - xp * (-f(0, i + 1, j) + f(0, i + 1, j + 1))); - sum += sixth * hx2 * hyi * - (cxi * (-f(1, i, j) + f(1, i, j + 1)) + - cx * (-f(1, i + 1, j) + f(1, i + 1, j + 1))); - sum += sixth * hy * - (xpi * (cydi * f(2, i, j) + cyd * f(2, i, j + 1)) + - xp * (cydi * f(2, i + 1, j) + cyd * f(2, i + 1, j + 1))); - sum += z36th * hx2 * hy * - (cxi * (cydi * f(3, i, j) + cyd * f(3, i, j + 1)) + - cx * (cydi * f(3, i + 1, j) + cyd * f(3, i + 1, j + 1))); - fval(iadr - 1) = sum; - } +template +struct SolveExplicitCubicSplineFunctor { + using execution_space = typename MemorySpace::execution_space; + using member_type = typename Kokkos::TeamPolicy::member_type; + // Member variables to capture the lambda's captured variables + Rank1View x; + LO nx; + Rank2View fspl; + LO ibcxmin; + T bcxmin; + LO ibcxmax; + T bcxmax; + Rank1View wk; + + // Constructor to initialize captured variables + SolveExplicitCubicSplineFunctor(Rank1View x_, LO nx_, + Rank2View fspl_, LO ibcxmin_, + T bcxmin_, LO ibcxmax_, T bcxmax_, + Rank1View wk_) + : x(x_), nx(nx_), fspl(fspl_), ibcxmin(ibcxmin_), bcxmin(bcxmin_), + ibcxmax(ibcxmax_), bcxmax(bcxmax_), wk(wk_) {} + + // Operator() that replaces the lambda + KOKKOS_INLINE_FUNCTION + void operator()(const member_type &team_member) const { + Kokkos::single(Kokkos::PerTeam(team_member), [=]() { + detail::solve_cubic_spline_explicit(x, nx, fspl, ibcxmin, bcxmin, ibcxmax, + bcxmax, wk); + }); + } +}; - // d2f/dx2 - if (ict[3] == 1) { - iadr++; - T xp = xparam, xpi = 1.0 - xp; - T yp = yparam, ypi = 1.0 - yp; - T yp2 = yp * yp, ypi2 = ypi * ypi; - T cy = yp * (yp2 - 1.0); - T cyi = ypi * (ypi2 - 1.0); - T hy2 = hy * hy; +template +ExplicitCubicSplineInterpolator:: + ExplicitCubicSplineInterpolator(Rank1View x, + Rank1View values, + BoundaryCondition ibcxmin, const T &bcxmin, + BoundaryCondition ibcxmax, + const T &bcxmax) { + CubicSplineInterpolator::sanity_check(x); + this->x_ = x; + LO nx = x.extent(0); + Kokkos::View fspl_view("coefficients", 4 * nx); + CubicSplineInterpolator::set_coefficients(fspl_view); + // auto fspl = Rank2View(fspl_view.data(), 4, nx); + auto fspl = get_coefficients(); + InitCubicCoeffFunctor init_functor(fspl, values); + Kokkos::parallel_for("initialize_coefficients", nx, init_functor); - T sum = xpi * (ypi * f(1, i, j) + yp * f(1, i, j + 1)) + - xp * (ypi * f(1, i + 1, j) + yp * f(1, i + 1, j + 1)); - sum += sixth * hy2 * - (xpi * (cyi * f(3, i, j) + cy * f(3, i, j + 1)) + - xp * (cyi * f(3, i + 1, j) + cy * f(3, i + 1, j + 1))); - fval(iadr - 1) = sum; - } + Kokkos::View wk_view("working space", 10); + auto wk = Rank1View(wk_view.data(), 10); + // TODO: pass member type to solve_spline + SolveExplicitCubicSplineFunctor functor( + x, nx, fspl, static_cast(ibcxmin), bcxmin, static_cast(ibcxmax), + bcxmax, wk); + Kokkos::parallel_for("solve_cubic_spline_explicit", + Kokkos::TeamPolicy(1, Kokkos::AUTO), + functor); + // this->fspl_ = fspl; +} - // d2f/dy2 - if (ict[4] == 1) { - iadr++; - T xp = xparam, xpi = 1.0 - xp; - T xp2 = xp * xp, xpi2 = xpi * xpi; - T cx = xp * (xp2 - 1.0); - T cxi = xpi * (xpi2 - 1.0); - T hx2 = hx * hx; - T yp = yparam, ypi = 1.0 - yp; +template +ExplicitCubicSplineInterpolator:: + ExplicitCubicSplineInterpolator(Rank1View x, + Rank1View values) + : ExplicitCubicSplineInterpolator(x, values, NOT_A_KNOT, 0, NOT_A_KNOT, + 0) { // Delegates to primary constructor + std::cout << "Not a knot boundary condition is applied by default" + << std::endl; +} - T sum = xpi * (ypi * f(2, i, j) + yp * f(2, i, j + 1)) + - xp * (ypi * f(2, i + 1, j) + yp * f(2, i + 1, j + 1)); - sum += sixth * hx2 * - (cxi * (ypi * f(3, i, j) + yp * f(3, i, j + 1)) + - cx * (ypi * f(3, i + 1, j) + yp * f(3, i + 1, j + 1))); - fval(iadr - 1) = sum; - } +template +CompactCubicSplineInterpolator::CompactCubicSplineInterpolator( + Rank1View x, Rank1View values, + BoundaryCondition ibcxmin, const T &bcxmin, BoundaryCondition ibcxmax, + const T &bcxmax) { + CubicSplineInterpolator::sanity_check(x); + this->x_ = x; + LO nx = x.extent(0); + Kokkos::View fspl_view("coefficients", 2 * nx); + CubicSplineInterpolator::set_coefficients(fspl_view); + auto fspl = get_coefficients(); + InitCubicCoeffFunctor init_functor(fspl, values); + Kokkos::parallel_for("initialize_coefficients", nx, init_functor); + + Kokkos::View fspl4_view("explicit coefficients", 4 * nx); + auto fspl4 = Rank2View(fspl4_view.data(), 4, nx); + Kokkos::View wk_view("working space", 10); + auto wk = Rank1View(wk_view.data(), 10); - // d2f/dxdy - if (ict[5] == 1) { - iadr++; - T xp = xparam, xpi = 1.0 - xp; - T xp2 = xp * xp, xpi2 = xpi * xpi; - T cxd = 3.0 * xp2 - 1.0; - T cxdi = -3.0 * xpi2 + 1.0; - T yp = yparam, ypi = 1.0 - yp; - T yp2 = yp * yp, ypi2 = ypi * ypi; - T cyd = 3.0 * yp2 - 1.0; - T cydi = -3.0 * ypi2 + 1.0; + SolveCompactCubicSplineFunctor functor( + x, nx, fspl, fspl4, static_cast(ibcxmin), bcxmin, + static_cast(ibcxmax), bcxmax, wk); + Kokkos::parallel_for("solve_cubic_spline_compact", + Kokkos::TeamPolicy(1, Kokkos::AUTO), + functor); + // this->fspl_ = fspl; +} - T sum = - hxi * hyi * - (f(0, i, j) - f(0, i, j + 1) - f(0, i + 1, j) + f(0, i + 1, j + 1)); - sum += sixth * hx * hyi * - (cxdi * (-f(1, i, j) + f(1, i, j + 1)) + - cxd * (-f(1, i + 1, j) + f(1, i + 1, j + 1))); - sum += sixth * hxi * hy * - (-(cydi * f(2, i, j) + cyd * f(2, i, j + 1)) + - (cydi * f(2, i + 1, j) + cyd * f(2, i + 1, j + 1))); - sum += z36th * hx * hy * - (cxdi * (cydi * f(3, i, j) + cyd * f(3, i, j + 1)) + - cxd * (cydi * f(3, i + 1, j) + cyd * f(3, i + 1, j + 1))); - fval(iadr - 1) = sum; - } - } +template +CompactCubicSplineInterpolator::CompactCubicSplineInterpolator( + Rank1View x, Rank1View fx) + : CompactCubicSplineInterpolator(x, fx, NOT_A_KNOT, 0, NOT_A_KNOT, + 0) { // Delegates to primary constructor + std::cout << "Not a knot boundary condition is applied by default" + << std::endl; +} + +template +void ExplicitCubicSplineInterpolator::evaluate( + const Kokkos::View selector, + Rank1View xvec, Rank2View fval) { + LO ivd = fval.extent(1); + auto fspl = get_coefficients(); + Kokkos::parallel_for( + Kokkos::RangePolicy(0, xvec.extent(0)), + KOKKOS_CLASS_LAMBDA(const LO i) { + LO ier = 0; + auto fval_view = + Rank1View(fval.data_handle() + i * ivd, ivd); + detail::cubic_eval_explicit(xvec(i), selector, fval_view, this->x_, + this->x_.extent(0), fspl, ier); + }); +} + +template +void ExplicitCubicSplineInterpolator::evaluate( + Rank1View xvec, Rank2View fval) { + std::array ict_arr = {1, 0, 0}; + evaluate(Kokkos::View(ict_arr.data(), 3), xvec, fval); +}; + +template +void CompactCubicSplineInterpolator::evaluate( + Kokkos::View selector, Rank1View xvec, + Rank2View fval) { + LO ivd = fval.extent(1); + auto fspl = get_coefficients(); + Kokkos::parallel_for( + Kokkos::RangePolicy(0, xvec.extent(0)), + KOKKOS_CLASS_LAMBDA(const LO i) { + LO ier = 0; + auto fval_view = + Rank1View(fval.data_handle() + i * ivd, ivd); + detail::cubic_eval_compact(xvec(i), selector, fval_view, this->x_, + this->x_.extent(0), fspl, ier); + }); +} + +// TODO: evluation functions are exactly the same, so put them in base class and override? +template +void CompactCubicSplineInterpolator::evaluate( + Rank1View xvec, Rank2View fval) { + std::array ict_arr = {1, 0, 0}; + evaluate(Kokkos::View(ict_arr.data(), 3), xvec, fval); +}; - // ict[0] = 3 → 3rd‑order derivative combinations - else if (ict[0] == 3) { - // d3f/dx3 - if (ict[1] == 1) { - iadr++; - T yp = yparam, ypi = 1.0 - yp; - T yp2 = yp * yp, ypi2 = ypi * ypi; - T cy = yp * (yp2 - 1.0); - T cyi = ypi * (ypi2 - 1.0); - T hy2 = hy * hy; - T sum = hxi * (-(ypi * f(1, i, j) + yp * f(1, i, j + 1)) + - (ypi * f(1, i + 1, j) + yp * f(1, i + 1, j + 1))); - sum += sixth * hy2 * hxi * - (-(cyi * f(3, i, j) + cy * f(3, i, j + 1)) + - (cyi * f(3, i + 1, j) + cy * f(3, i + 1, j + 1))); - fval(iadr - 1) = sum; - } +template +void BiCubicSplineInterpolator::sanity_check( + Rank1View x, Rank1View y) { + PCMS_ALWAYS_ASSERT(x.extent(0) >= 2); + PCMS_ALWAYS_ASSERT(y.extent(0) >= 2); - // d3f/dx2dy - if (ict[2] == 1) { - iadr++; - T xp = xparam, xpi = 1.0 - xp; - T yp = yparam, ypi = 1.0 - yp; - T yp2 = yp * yp, ypi2 = ypi * ypi; - T cyd = 3.0 * yp2 - 1.0; - T cydi = -3.0 * ypi2 + 1.0; - T sum = hyi * (xpi * (-f(1, i, j) + f(1, i, j + 1)) + - xp * (-f(1, i + 1, j) + f(1, i + 1, j + 1))); - sum += sixth * hy * - (xpi * (cydi * f(3, i, j) + cyd * f(3, i, j + 1)) + - xp * (cydi * f(3, i + 1, j) + cyd * f(3, i + 1, j + 1))); - fval(iadr - 1) = sum; - } + detail::isUniformAscending(x, 1.0e-3); + detail::isUniformAscending(y, 1.0e-3); +} - // d3f/dxdy2 - if (ict[3] == 1) { - iadr++; - T xp = xparam, xpi = 1.0 - xp; - T xp2 = xp * xp, xpi2 = xpi * xpi; - T cxd = 3.0 * xp2 - 1.0; - T cxdi = -3.0 * xpi2 + 1.0; - T yp = yparam, ypi = 1.0 - yp; - T sum = hxi * (-(ypi * f(2, i, j) + yp * f(2, i, j + 1)) + - (ypi * f(2, i + 1, j) + yp * f(2, i + 1, j + 1))); - sum += sixth * hx * - (cxdi * (ypi * f(3, i, j) + yp * f(3, i, j + 1)) + - cxd * (ypi * f(3, i + 1, j) + yp * f(3, i + 1, j + 1))); - fval(iadr - 1) = sum; - } +template +void ExplicitBiCubicSplineInterpolator::evaluate( + Kokkos::View iselect, Rank1View xvec, + Rank1View yvec, Rank2View fval) { + PCMS_ALWAYS_ASSERT(xvec.extent(0) == yvec.extent(0) && + xvec.extent(0) == fval.extent(0)); - // d3f/dy3 - if (ict[4] == 1) { - iadr++; - T xp = xparam, xpi = 1.0 - xp; - T xp2 = xp * xp, xpi2 = xpi * xpi; - T cx = xp * (xp2 - 1.0); - T cxi = xpi * (xpi2 - 1.0); - T hx2 = hx * hx; - T sum = hyi * (xpi * (-f(2, i, j) + f(2, i, j + 1)) + - xp * (-f(2, i + 1, j) + f(2, i + 1, j + 1))); - sum += sixth * hx2 * hyi * - (cxi * (-f(3, i, j) + f(3, i, j + 1)) + - cx * (-f(3, i + 1, j) + f(3, i + 1, j + 1))); - fval(iadr - 1) = sum; - } - } + LO ivd = fval.extent(1); + auto fspl = get_coefficients(); + Kokkos::parallel_for( + Kokkos::RangePolicy(0, xvec.extent(0)), + KOKKOS_CLASS_LAMBDA(const LO i) { + LO ier = 0; + auto fval_view = + Rank1View(fval.data_handle() + i * ivd, ivd); + detail::bicubic_eval_explicit(xvec(i), yvec(i), iselect, fval_view, + this->x_, this->x_.extent(0), this->y_, + this->y_.extent(0), fspl, ier); + }); +} - // ict[0] = 4 → 4th‑order derivative combinations - else if (ict[0] == 4) { - // d4f/dx3dy - if (ict[1] == 1) { - iadr++; - T yp = yparam, ypi = 1.0 - yp; - T yp2 = yp * yp, ypi2 = ypi * ypi; - T cyd = 3.0 * yp2 - 1.0; - T cydi = -3.0 * ypi2 + 1.0; - T sum = - hxi * hyi * - (f(1, i, j) - f(1, i, j + 1) - f(1, i + 1, j) + f(1, i + 1, j + 1)); - sum += sixth * hy * hxi * - (-(cydi * f(3, i, j) + cyd * f(3, i, j + 1)) + - (cydi * f(3, i + 1, j) + cyd * f(3, i + 1, j + 1))); - fval(iadr - 1) = sum; - } +template +void ExplicitBiCubicSplineInterpolator::evaluate( + Rank1View xvec, Rank1View yvec, + Rank2View fval) { + LO ict_arr[6] = {1, 0, 0, 0, 0, 0}; + Kokkos::View ict("select", 6); + Kokkos::parallel_for( + Kokkos::RangePolicy(0, ict.size()), + KOKKOS_LAMBDA(const LO i) { ict(i) = ict_arr[i]; }); + evaluate(ict, xvec, yvec, fval); +} - // d4f/dx2dy2 - if (ict[2] == 1) { - iadr++; - T xp = xparam, xpi = 1.0 - xp; - T yp = yparam, ypi = 1.0 - yp; - T sum = xpi * (ypi * f(3, i, j) + yp * f(3, i, j + 1)) + - xp * (ypi * f(3, i + 1, j) + yp * f(3, i + 1, j + 1)); - fval(iadr - 1) = sum; - } +template +void CompactBiCubicSplineInterpolator::evaluate( + Kokkos::View iselect, Rank1View xvec, + Rank1View yvec, Rank2View fval) { - // d4f/dxdy3 - if (ict[3] == 1) { - iadr++; - T xp = xparam, xpi = 1.0 - xp; - T xp2 = xp * xp, xpi2 = xpi * xpi; - T cxd = 3.0 * xp2 - 1.0; - T cxdi = -3.0 * xpi2 + 1.0; - T sum = - hxi * hyi * - (f(2, i, j) - f(2, i, j + 1) - f(2, i + 1, j) + f(2, i + 1, j + 1)); - sum += sixth * hx * hyi * - (cxdi * (-f(3, i, j) + f(3, i, j + 1)) + - cxd * (-f(3, i + 1, j) + f(3, i + 1, j + 1))); - fval(iadr - 1) = sum; - } - } + PCMS_ALWAYS_ASSERT(xvec.extent(0) == yvec.extent(0) && + xvec.extent(0) == fval.extent(0)); + LO ivd = fval.extent(1); + auto fspl = get_coefficients(); + Kokkos::parallel_for( + Kokkos::RangePolicy(0, xvec.extent(0)), + KOKKOS_CLASS_LAMBDA(const LO i) { + LO ier = 0; + auto fval_view = + Rank1View(fval.data_handle() + i * ivd, ivd); + detail::bicubic_eval_compact(xvec(i), yvec(i), iselect, fval_view, + this->x_, this->x_.extent(0), this->y_, + this->y_.extent(0), fspl, ier); + }); +} - // ict[0] = 5 → 5th‑order derivative combinations - else if (ict[0] == 5) { - // d5f/dx3dy2 - if (ict[1] == 1) { - iadr++; - T yp = yparam, ypi = 1.0 - yp; - T sum = hxi * (-(ypi * f(3, i, j) + yp * f(3, i, j + 1)) + - (ypi * f(3, i + 1, j) + yp * f(3, i + 1, j + 1))); - fval(iadr - 1) = sum; - } +template +void CompactBiCubicSplineInterpolator::evaluate( + Rank1View xvec, Rank1View yvec, + Rank2View fval) { + LO ict_arr[6] = {1, 0, 0, 0, 0, 0}; + Kokkos::View ict("select", 6); + Kokkos::parallel_for( + Kokkos::RangePolicy(0, ict.size()), + KOKKOS_LAMBDA(const LO i) { ict(i) = ict_arr[i]; }); + evaluate(ict, xvec, yvec, fval); +} - // d5f/dx2dy3 - if (ict[2] == 1) { - iadr++; - T xp = xparam, xpi = 1.0 - xp; - T sum = hyi * (xpi * (-f(3, i, j) + f(3, i, j + 1)) + - xp * (-f(3, i + 1, j) + f(3, i + 1, j + 1))); - fval(iadr - 1) = sum; - } +template +struct InitExplicitBiCubicCoeffFunctor { + Rank4View fspl; + Rank1View values; + LO ny; + + InitExplicitBiCubicCoeffFunctor(Rank4View fspl_, + Rank1View values_, LO ny_) + : fspl(fspl_), values(values_), ny(ny_) {} + + KOKKOS_INLINE_FUNCTION + void operator()(const LO iy, const LO ix) const { + fspl(0, 0, ix, iy) = values(ix * ny + iy); } +}; - // ict[0] = 6 → 6th‑order derivative (dx³dy³) - else if (ict[0] == 6) { - iadr++; - T sum = hxi * hyi * - (f(3, i, j) - f(3, i, j + 1) - f(3, i + 1, j) + f(3, i + 1, j + 1)); - fval(iadr - 1) = sum; +template +struct InitCompactBiCubicCoeffFunctor { + Rank3View fspl; + Rank1View values; + LO ny; + + InitCompactBiCubicCoeffFunctor(Rank3View fspl_, + Rank1View values_, LO ny_) + : fspl(fspl_), values(values_), ny(ny_) {} + + KOKKOS_INLINE_FUNCTION + void operator()(const LO iy, const LO ix) const { + fspl(0, ix, iy) = values(ix * ny + iy); } +}; + +template +ExplicitBiCubicSplineInterpolator:: + ExplicitBiCubicSplineInterpolator( + Rank1View x, // size: inx + Rank1View y, // size: iny + Rank1View values, BoundaryCondition ibcxmin, + Rank1View + bcxmin, // size: iny (used if ibcxmin = 1 or 2) + BoundaryCondition ibcxmax, + Rank1View + bcxmax, // size: iny (used if ibcxmax = 1 or 2) + BoundaryCondition ibcymin, + Rank1View + bcymin, // size: inx (used if ibcymin = 1 or 2) + BoundaryCondition ibcymax, + Rank1View bcymax // size: inx (used if ibcymax = 1 or 2) + ) { + BiCubicSplineInterpolator::sanity_check(x, y); + + this->x_ = x; + this->y_ = y; + LO ny = y.extent(0); + LO nx = x.extent(0); + Kokkos::View fspl_view("fspl view", 4 * 4 * nx * ny); + BiCubicSplineInterpolator::set_coefficients(fspl_view); + auto fspl = get_coefficients(); + InitExplicitBiCubicCoeffFunctor init_functor(fspl, values, + ny); + Kokkos::parallel_for(Kokkos::MDRangePolicy>({0, 0}, {ny, nx}), + init_functor); + + Kokkos::View wk_view("wk", 9 * nx * ny); + auto wk = Rank1View(wk_view.data(), 9 * nx * ny); + + detail::solve_bicubic_spline_explicit( + x, nx, y, ny, fspl, static_cast(ibcxmin), bcxmin, + static_cast(ibcxmax), bcxmax, static_cast(ibcymin), bcymin, + static_cast(ibcymax), bcymax, wk); } template -KOKKOS_INLINE_FUNCTION void -CompactBiCubicSplineInterpolator::eval( - T xget, T yget, Kokkos::View ict, - Rank1View fval, // output (size depends on ict) - Rank1View x, const LO &nx, Rank1View y, - const LO &ny, Rank3View f, // input (size depends on ict) - LO &ier) { - // Local variables - LO i = 0, j = 0; - T xparam = 0.0, yparam = 0.0; - T hx = 0.0, hy = 0.0; - T hxi = 0.0, hyi = 0.0; +ExplicitBiCubicSplineInterpolator:: + ExplicitBiCubicSplineInterpolator(Rank1View x, // size: inx + Rank1View y, // size: iny + Rank1View values) + : ExplicitBiCubicSplineInterpolator( + x, y, values, NOT_A_KNOT, {}, NOT_A_KNOT, {}, NOT_A_KNOT, {}, + NOT_A_KNOT, {}) { // Delegates to primary constructor + std::cout << "Not a knot boundary condition is applied by default" + << std::endl; +} - // Call herm2xy to locate cell and compute params - lookup(xget, yget, x, nx, y, ny, i, j, xparam, yparam, hx, hxi, hy, hyi, ier); +template +CompactBiCubicSplineInterpolator:: + CompactBiCubicSplineInterpolator( + Rank1View x, Rank1View y, + Rank1View values, BoundaryCondition ibcxmin, + Rank1View bcxmin, BoundaryCondition ibcxmax, + Rank1View bcxmax, BoundaryCondition ibcymin, + Rank1View bcymin, BoundaryCondition ibcymax, + Rank1View bcymax) { + BiCubicSplineInterpolator::sanity_check(x, y); - if (ier != 0) - return; + this->x_ = x; + this->y_ = y; + LO ny = y.extent(0); + LO nx = x.extent(0); + Kokkos::View fspl_view("fspl view", 4 * nx * ny); + BiCubicSplineInterpolator::set_coefficients(fspl_view); + auto fspl = get_coefficients(); - // Call evalfn with scalar-vector LOerface - evalfn(ict, 1, 1, fval, i, j, xparam, yparam, hx, hxi, hy, hyi, f); + InitCompactBiCubicCoeffFunctor init_functor(fspl, values, ny); + Kokkos::parallel_for(Kokkos::MDRangePolicy>({0, 0}, {ny, nx}), + init_functor); + + Kokkos::View wk_view("wk", 9 * nx * ny); + auto wk = Rank1View(wk_view.data(), 9 * nx * ny); + + detail::solve_bicubic_spline_compact( + x, nx, y, ny, fspl, static_cast(ibcxmin), bcxmin, + static_cast(ibcxmax), bcxmax, static_cast(ibcymin), bcymin, + static_cast(ibcymax), bcymax, wk); +} + +template +CompactBiCubicSplineInterpolator:: + CompactBiCubicSplineInterpolator(Rank1View x, // size: inx + Rank1View y, // size: iny + Rank1View values) + : CompactBiCubicSplineInterpolator(x, y, values, NOT_A_KNOT, {}, NOT_A_KNOT, + {}, NOT_A_KNOT, {}, NOT_A_KNOT, + {}) { // Delegates to primary constructor + std::cout << "Not a knot boundary condition is applied by default" + << std::endl; } } // namespace pcms diff --git a/test/test_spline_interpolator.cpp b/test/test_spline_interpolator.cpp index b97666adb..111e17d72 100644 --- a/test/test_spline_interpolator.cpp +++ b/test/test_spline_interpolator.cpp @@ -165,7 +165,8 @@ void dotest1(int ns, Rank1View x, // interpolator.cspline(x, ns, fspl, 1, 1, 1, 1, wk); ExplicitCubicSplineInterpolator - explicit_interpolator(x, f, 1, 1, 1, 1); + explicit_interpolator(x, f, BoundaryCondition::FIRST_DERIVATIVE_MATCH, 1, + BoundaryCondition::FIRST_DERIVATIVE_MATCH, 1); explicit_interpolator.evaluate(xt, splinv); auto res1 = Rank1View(res_1d.data(), 2); @@ -173,7 +174,8 @@ void dotest1(int ns, Rank1View x, reset_2dspan(splinv); ExplicitCubicSplineInterpolator - explicit_interpolator_periodic(x, f, -1, 0, -1, 0); + explicit_interpolator_periodic(x, f, BoundaryCondition::PERIODIC, 0, + BoundaryCondition::PERIODIC, 0); explicit_interpolator_periodic.evaluate(xt, splinv); auto res2 = Rank1View(res_1d.data() + 2, 2); @@ -181,7 +183,8 @@ void dotest1(int ns, Rank1View x, reset_2dspan(splinv); CompactCubicSplineInterpolator compact_interpolator( - x, f, 1, 1, 1, 1); + x, f, BoundaryCondition::FIRST_DERIVATIVE_MATCH, 1, + BoundaryCondition::FIRST_DERIVATIVE_MATCH, 1); compact_interpolator.evaluate(xt, splinv); auto res3 = Rank1View(res_1d.data() + 4, 2); @@ -263,8 +266,11 @@ void dotest2(Rank1View x, generate_gt_2d(splinv_gt, fxtest, fthtest, ntest); ExplicitBiCubicSplineInterpolator - explicit_interpolator(x, th, values, 1, bcx1, 1, bcx2, 1, bcth1, 1, - bcth2); + explicit_interpolator(x, th, values, + BoundaryCondition::FIRST_DERIVATIVE_MATCH, bcx1, + BoundaryCondition::FIRST_DERIVATIVE_MATCH, bcx2, + BoundaryCondition::FIRST_DERIVATIVE_MATCH, bcth1, + BoundaryCondition::FIRST_DERIVATIVE_MATCH, bcth2); explicit_interpolator.evaluate(xtest_grid, thtest_grid, splinv); auto res1 = Rank1View(res_2d.data(), 2); @@ -272,7 +278,11 @@ void dotest2(Rank1View x, reset_2dspan(splinv); CompactBiCubicSplineInterpolator - compact_interpolator(x, th, values, 1, bcx1, 1, bcx2, 1, bcth1, 1, bcth2); + compact_interpolator(x, th, values, + BoundaryCondition::FIRST_DERIVATIVE_MATCH, bcx1, + BoundaryCondition::FIRST_DERIVATIVE_MATCH, bcx2, + BoundaryCondition::FIRST_DERIVATIVE_MATCH, bcth1, + BoundaryCondition::FIRST_DERIVATIVE_MATCH, bcth2); compact_interpolator.evaluate(xtest_grid, thtest_grid, splinv); auto res2 = Rank1View(res_2d.data() + 2, 2); From 422e449c93b1e7c4532da32ee1338a2ae95e810b Mon Sep 17 00:00:00 2001 From: Sichao25 Date: Fri, 22 Aug 2025 00:19:57 -0400 Subject: [PATCH 10/18] clean unused code --- src/pcms/interpolator/spline_interpolator.hpp | 49 +++++++------------ 1 file changed, 18 insertions(+), 31 deletions(-) diff --git a/src/pcms/interpolator/spline_interpolator.hpp b/src/pcms/interpolator/spline_interpolator.hpp index 8b1995cf5..61d18a283 100644 --- a/src/pcms/interpolator/spline_interpolator.hpp +++ b/src/pcms/interpolator/spline_interpolator.hpp @@ -2116,6 +2116,7 @@ template class CubicSplineInterpolator { Rank1View x_; Kokkos::View get_coefficients(); + void set_coefficients(Kokkos::View coefficients); void sanity_check(Rank1View x); @@ -2151,7 +2152,6 @@ class ExplicitCubicSplineInterpolator public: using execution_space = typename MemorySpace::execution_space; using member_type = typename Kokkos::TeamPolicy::member_type; - ExplicitCubicSplineInterpolator() = default; /** \brief Construct the interpolator object and set up the coefficients * @@ -2229,7 +2229,7 @@ class CompactCubicSplineInterpolator public: using execution_space = typename MemorySpace::execution_space; using member_type = typename Kokkos::TeamPolicy::member_type; - CompactCubicSplineInterpolator() = default; + /** \brief Construct the interpolator object and set up the coefficients * * \param x input grid points @@ -2322,8 +2322,6 @@ class ExplicitBiCubicSplineInterpolator using execution_space = typename MemorySpace::execution_space; using member_type = typename Kokkos::TeamPolicy::member_type; - ExplicitBiCubicSplineInterpolator() = default; - /** \brief Construct the interpolator object and set up the coefficients * * \param x input grid points in x direction @@ -2421,8 +2419,6 @@ class CompactBiCubicSplineInterpolator using execution_space = typename MemorySpace::execution_space; using member_type = typename Kokkos::TeamPolicy::member_type; - CompactBiCubicSplineInterpolator() = default; - /** \brief Construct the interpolator object and set up the coefficients * * \param x input grid points in x direction @@ -2546,7 +2542,7 @@ void CubicSplineInterpolator::sanity_check( } template struct InitCubicCoeffFunctor { - // Member variables to capture the lambda's captured variables + Rank2View fspl; Rank1View values; @@ -2555,7 +2551,6 @@ template struct InitCubicCoeffFunctor { Rank1View values_) : fspl(fspl_), values(values_) {} - // Operator() that replaces the lambda KOKKOS_INLINE_FUNCTION void operator()(const LO i) const { fspl(0, i) = values(i); } }; @@ -2564,7 +2559,7 @@ template struct SolveCompactCubicSplineFunctor { using execution_space = typename MemorySpace::execution_space; using member_type = typename Kokkos::TeamPolicy::member_type; - // Member variables to capture the lambda's captured variables + Rank1View x; LO nx; Rank2View fspl; @@ -2575,7 +2570,6 @@ struct SolveCompactCubicSplineFunctor { T bcxmax; Rank1View wk; - // Constructor to initialize captured variables SolveCompactCubicSplineFunctor(Rank1View x_, LO nx_, Rank2View fspl_, Rank2View fspl4_, LO ibcxmin_, @@ -2584,7 +2578,6 @@ struct SolveCompactCubicSplineFunctor { : x(x_), nx(nx_), fspl(fspl_), fspl4(fspl4_), ibcxmin(ibcxmin_), bcxmin(bcxmin_), ibcxmax(ibcxmax_), bcxmax(bcxmax_), wk(wk_) {} - // Operator() that replaces the lambda KOKKOS_INLINE_FUNCTION void operator()(const member_type &team_member) const { Kokkos::single(Kokkos::PerTeam(team_member), [=]() { @@ -2598,7 +2591,7 @@ template struct SolveExplicitCubicSplineFunctor { using execution_space = typename MemorySpace::execution_space; using member_type = typename Kokkos::TeamPolicy::member_type; - // Member variables to capture the lambda's captured variables + Rank1View x; LO nx; Rank2View fspl; @@ -2608,7 +2601,6 @@ struct SolveExplicitCubicSplineFunctor { T bcxmax; Rank1View wk; - // Constructor to initialize captured variables SolveExplicitCubicSplineFunctor(Rank1View x_, LO nx_, Rank2View fspl_, LO ibcxmin_, T bcxmin_, LO ibcxmax_, T bcxmax_, @@ -2616,7 +2608,6 @@ struct SolveExplicitCubicSplineFunctor { : x(x_), nx(nx_), fspl(fspl_), ibcxmin(ibcxmin_), bcxmin(bcxmin_), ibcxmax(ibcxmax_), bcxmax(bcxmax_), wk(wk_) {} - // Operator() that replaces the lambda KOKKOS_INLINE_FUNCTION void operator()(const member_type &team_member) const { Kokkos::single(Kokkos::PerTeam(team_member), [=]() { @@ -2638,7 +2629,6 @@ ExplicitCubicSplineInterpolator:: LO nx = x.extent(0); Kokkos::View fspl_view("coefficients", 4 * nx); CubicSplineInterpolator::set_coefficients(fspl_view); - // auto fspl = Rank2View(fspl_view.data(), 4, nx); auto fspl = get_coefficients(); InitCubicCoeffFunctor init_functor(fspl, values); Kokkos::parallel_for("initialize_coefficients", nx, init_functor); @@ -2652,7 +2642,6 @@ ExplicitCubicSplineInterpolator:: Kokkos::parallel_for("solve_cubic_spline_explicit", Kokkos::TeamPolicy(1, Kokkos::AUTO), functor); - // this->fspl_ = fspl; } template @@ -2690,7 +2679,6 @@ CompactCubicSplineInterpolator::CompactCubicSplineInterpolator( Kokkos::parallel_for("solve_cubic_spline_compact", Kokkos::TeamPolicy(1, Kokkos::AUTO), functor); - // this->fspl_ = fspl; } template @@ -2744,6 +2732,7 @@ void CompactCubicSplineInterpolator::evaluate( } // TODO: evluation functions are exactly the same, so put them in base class and override? +// need to figure out if this is possible with the Kokkos template void CompactCubicSplineInterpolator::evaluate( Rank1View xvec, Rank2View fval) { @@ -2862,19 +2851,17 @@ struct InitCompactBiCubicCoeffFunctor { template ExplicitBiCubicSplineInterpolator:: ExplicitBiCubicSplineInterpolator( - Rank1View x, // size: inx - Rank1View y, // size: iny - Rank1View values, BoundaryCondition ibcxmin, - Rank1View - bcxmin, // size: iny (used if ibcxmin = 1 or 2) + Rank1View x, + Rank1View y, + Rank1View values, + BoundaryCondition ibcxmin, + Rank1View bcxmin, BoundaryCondition ibcxmax, - Rank1View - bcxmax, // size: iny (used if ibcxmax = 1 or 2) + Rank1View bcxmax, BoundaryCondition ibcymin, - Rank1View - bcymin, // size: inx (used if ibcymin = 1 or 2) + Rank1View bcymin, BoundaryCondition ibcymax, - Rank1View bcymax // size: inx (used if ibcymax = 1 or 2) + Rank1View bcymax ) { BiCubicSplineInterpolator::sanity_check(x, y); @@ -2901,8 +2888,8 @@ ExplicitBiCubicSplineInterpolator:: template ExplicitBiCubicSplineInterpolator:: - ExplicitBiCubicSplineInterpolator(Rank1View x, // size: inx - Rank1View y, // size: iny + ExplicitBiCubicSplineInterpolator(Rank1View x, + Rank1View y, Rank1View values) : ExplicitBiCubicSplineInterpolator( x, y, values, NOT_A_KNOT, {}, NOT_A_KNOT, {}, NOT_A_KNOT, {}, @@ -2945,8 +2932,8 @@ CompactBiCubicSplineInterpolator:: template CompactBiCubicSplineInterpolator:: - CompactBiCubicSplineInterpolator(Rank1View x, // size: inx - Rank1View y, // size: iny + CompactBiCubicSplineInterpolator(Rank1View x, + Rank1View y, Rank1View values) : CompactBiCubicSplineInterpolator(x, y, values, NOT_A_KNOT, {}, NOT_A_KNOT, {}, NOT_A_KNOT, {}, NOT_A_KNOT, From 3ec3233345a2bb2a0781516d316e9849f35b2558 Mon Sep 17 00:00:00 2001 From: Sichao25 Date: Fri, 22 Aug 2025 19:47:13 -0400 Subject: [PATCH 11/18] yus/spline_interpolator --- src/pcms/interpolator/spline_interpolator.hpp | 148 ++++++------------ 1 file changed, 47 insertions(+), 101 deletions(-) diff --git a/src/pcms/interpolator/spline_interpolator.hpp b/src/pcms/interpolator/spline_interpolator.hpp index 61d18a283..a5e56cb4c 100644 --- a/src/pcms/interpolator/spline_interpolator.hpp +++ b/src/pcms/interpolator/spline_interpolator.hpp @@ -50,6 +50,13 @@ void isUniformAscending(Rank1View x, const T &ztol) { }); } +template +void check_grid( + Rank1View x) { + PCMS_ALWAYS_ASSERT(x.extent(0) >= 2); + detail::isUniformAscending(x, 1.0e-3); +} + template KOKKOS_INLINE_FUNCTION void inGrid(T &xget, T &zxget, Rank1View x, const LO &nx, LO &ier) { @@ -2104,25 +2111,11 @@ enum BoundaryCondition { */ template class CubicSplineInterpolator { public: - using execution_space = typename MemorySpace::execution_space; - virtual void evaluate(Rank1View xvec, Rank2View fval) = 0; virtual void evaluate(Kokkos::View selector, Rank1View xvec, Rank2View fval) = 0; - -protected: - Rank1View x_; - - Kokkos::View get_coefficients(); - - void set_coefficients(Kokkos::View coefficients); - - void sanity_check(Rank1View x); - -private: - Kokkos::View coefficients_; }; /** \brief ExplicitCubicSplineInterpolator class @@ -2205,7 +2198,9 @@ class ExplicitCubicSplineInterpolator Rank2View fval) override; private: - Rank2View get_coefficients(); + Rank1View x_; + Kokkos::View coefficients_; + Rank2View get_coefficients_view(); }; /** @@ -2275,12 +2270,13 @@ class CompactCubicSplineInterpolator Rank2View fval) override; private: - Rank2View get_coefficients(); + Rank1View x_; + Kokkos::View coefficients_; + Rank2View get_coefficients_view(); }; template class BiCubicSplineInterpolator { public: - using execution_space = typename MemorySpace::execution_space; virtual void evaluate(Rank1View xvec, Rank1View yvec, Rank2View fval) = 0; @@ -2288,19 +2284,6 @@ template class BiCubicSplineInterpolator { Rank1View xvec, Rank1View yvec, Rank2View fval) = 0; - -protected: - Rank1View x_; - Rank1View y_; - - Kokkos::View get_coefficients(); - - void set_coefficients(Kokkos::View coefficients); - - void sanity_check(Rank1View x, Rank1View y); - -private: - Kokkos::View coefficients_; }; /** \brief BiCubicSplineInterpolator class @@ -2387,7 +2370,10 @@ class ExplicitBiCubicSplineInterpolator Rank2View fval) override; private: - Rank4View get_coefficients(); + Rank1View x_; + Rank1View y_; + Kokkos::View coefficients_; + Rank4View get_coefficients_view(); }; /** \brief CompactBiCubicSplineInterpolator class @@ -2477,70 +2463,38 @@ class CompactBiCubicSplineInterpolator Rank2View fval) override; private: - Rank3View get_coefficients(); + Rank1View x_; + Rank1View y_; + Kokkos::View coefficients_; + Rank3View get_coefficients_view(); }; -template -Kokkos::View -CubicSplineInterpolator::get_coefficients() { - return coefficients_; -} - -template -void CubicSplineInterpolator::set_coefficients( - Kokkos::View coefficients) { - coefficients_ = coefficients; -} - template Rank2View -ExplicitCubicSplineInterpolator::get_coefficients() { - auto coeffs = CubicSplineInterpolator::get_coefficients(); - return Rank2View(coeffs.data(), 4, this->x_.extent(0)); +ExplicitCubicSplineInterpolator::get_coefficients_view() { + return Rank2View(this->coefficients_.data(), 4, this->x_.extent(0)); } template Rank2View -CompactCubicSplineInterpolator::get_coefficients() { - auto coeffs = CubicSplineInterpolator::get_coefficients(); - return Rank2View(coeffs.data(), 2, this->x_.extent(0)); +CompactCubicSplineInterpolator::get_coefficients_view() { + return Rank2View(this->coefficients_.data(), 2, this->x_.extent(0)); } template Rank4View -ExplicitBiCubicSplineInterpolator::get_coefficients() { - auto coeffs = BiCubicSplineInterpolator::get_coefficients(); - return Rank4View(coeffs.data(), 4, 4, this->x_.extent(0), +ExplicitBiCubicSplineInterpolator::get_coefficients_view() { + return Rank4View(this->coefficients_.data(), 4, 4, this->x_.extent(0), this->y_.extent(0)); } template Rank3View -CompactBiCubicSplineInterpolator::get_coefficients() { - auto coeffs = BiCubicSplineInterpolator::get_coefficients(); - return Rank3View(coeffs.data(), 4, this->x_.extent(0), +CompactBiCubicSplineInterpolator::get_coefficients_view() { + return Rank3View(this->coefficients_.data(), 4, this->x_.extent(0), this->y_.extent(0)); } -template -Kokkos::View -BiCubicSplineInterpolator::get_coefficients() { - return coefficients_; -} - -template -void BiCubicSplineInterpolator::set_coefficients( - Kokkos::View coefficients) { - coefficients_ = coefficients; -} - -template -void CubicSplineInterpolator::sanity_check( - Rank1View x) { - PCMS_ALWAYS_ASSERT(x.extent(0) >= 2); - detail::isUniformAscending(x, 1.0e-3); -} - template struct InitCubicCoeffFunctor { Rank2View fspl; @@ -2624,12 +2578,12 @@ ExplicitCubicSplineInterpolator:: BoundaryCondition ibcxmin, const T &bcxmin, BoundaryCondition ibcxmax, const T &bcxmax) { - CubicSplineInterpolator::sanity_check(x); + detail::check_grid(x); this->x_ = x; LO nx = x.extent(0); Kokkos::View fspl_view("coefficients", 4 * nx); - CubicSplineInterpolator::set_coefficients(fspl_view); - auto fspl = get_coefficients(); + this->coefficients_ = fspl_view; + auto fspl = get_coefficients_view(); InitCubicCoeffFunctor init_functor(fspl, values); Kokkos::parallel_for("initialize_coefficients", nx, init_functor); @@ -2659,12 +2613,12 @@ CompactCubicSplineInterpolator::CompactCubicSplineInterpolator( Rank1View x, Rank1View values, BoundaryCondition ibcxmin, const T &bcxmin, BoundaryCondition ibcxmax, const T &bcxmax) { - CubicSplineInterpolator::sanity_check(x); + detail::check_grid(x); this->x_ = x; LO nx = x.extent(0); Kokkos::View fspl_view("coefficients", 2 * nx); - CubicSplineInterpolator::set_coefficients(fspl_view); - auto fspl = get_coefficients(); + this->coefficients_ = fspl_view; + auto fspl = get_coefficients_view(); InitCubicCoeffFunctor init_functor(fspl, values); Kokkos::parallel_for("initialize_coefficients", nx, init_functor); @@ -2695,7 +2649,7 @@ void ExplicitCubicSplineInterpolator::evaluate( const Kokkos::View selector, Rank1View xvec, Rank2View fval) { LO ivd = fval.extent(1); - auto fspl = get_coefficients(); + auto fspl = get_coefficients_view(); Kokkos::parallel_for( Kokkos::RangePolicy(0, xvec.extent(0)), KOKKOS_CLASS_LAMBDA(const LO i) { @@ -2719,7 +2673,7 @@ void CompactCubicSplineInterpolator::evaluate( Kokkos::View selector, Rank1View xvec, Rank2View fval) { LO ivd = fval.extent(1); - auto fspl = get_coefficients(); + auto fspl = get_coefficients_view(); Kokkos::parallel_for( Kokkos::RangePolicy(0, xvec.extent(0)), KOKKOS_CLASS_LAMBDA(const LO i) { @@ -2740,16 +2694,6 @@ void CompactCubicSplineInterpolator::evaluate( evaluate(Kokkos::View(ict_arr.data(), 3), xvec, fval); }; -template -void BiCubicSplineInterpolator::sanity_check( - Rank1View x, Rank1View y) { - PCMS_ALWAYS_ASSERT(x.extent(0) >= 2); - PCMS_ALWAYS_ASSERT(y.extent(0) >= 2); - - detail::isUniformAscending(x, 1.0e-3); - detail::isUniformAscending(y, 1.0e-3); -} - template void ExplicitBiCubicSplineInterpolator::evaluate( Kokkos::View iselect, Rank1View xvec, @@ -2758,7 +2702,7 @@ void ExplicitBiCubicSplineInterpolator::evaluate( xvec.extent(0) == fval.extent(0)); LO ivd = fval.extent(1); - auto fspl = get_coefficients(); + auto fspl = get_coefficients_view(); Kokkos::parallel_for( Kokkos::RangePolicy(0, xvec.extent(0)), KOKKOS_CLASS_LAMBDA(const LO i) { @@ -2791,7 +2735,7 @@ void CompactBiCubicSplineInterpolator::evaluate( PCMS_ALWAYS_ASSERT(xvec.extent(0) == yvec.extent(0) && xvec.extent(0) == fval.extent(0)); LO ivd = fval.extent(1); - auto fspl = get_coefficients(); + auto fspl = get_coefficients_view(); Kokkos::parallel_for( Kokkos::RangePolicy(0, xvec.extent(0)), KOKKOS_CLASS_LAMBDA(const LO i) { @@ -2863,15 +2807,16 @@ ExplicitBiCubicSplineInterpolator:: BoundaryCondition ibcymax, Rank1View bcymax ) { - BiCubicSplineInterpolator::sanity_check(x, y); + detail::check_grid(x); + detail::check_grid(y); this->x_ = x; this->y_ = y; LO ny = y.extent(0); LO nx = x.extent(0); Kokkos::View fspl_view("fspl view", 4 * 4 * nx * ny); - BiCubicSplineInterpolator::set_coefficients(fspl_view); - auto fspl = get_coefficients(); + this->coefficients_ = fspl_view; + auto fspl = get_coefficients_view(); InitExplicitBiCubicCoeffFunctor init_functor(fspl, values, ny); Kokkos::parallel_for(Kokkos::MDRangePolicy>({0, 0}, {ny, nx}), @@ -2907,15 +2852,16 @@ CompactBiCubicSplineInterpolator:: Rank1View bcxmax, BoundaryCondition ibcymin, Rank1View bcymin, BoundaryCondition ibcymax, Rank1View bcymax) { - BiCubicSplineInterpolator::sanity_check(x, y); + detail::check_grid(x); + detail::check_grid(y); this->x_ = x; this->y_ = y; LO ny = y.extent(0); LO nx = x.extent(0); Kokkos::View fspl_view("fspl view", 4 * nx * ny); - BiCubicSplineInterpolator::set_coefficients(fspl_view); - auto fspl = get_coefficients(); + this->coefficients_ = fspl_view; + auto fspl = get_coefficients_view(); InitCompactBiCubicCoeffFunctor init_functor(fspl, values, ny); Kokkos::parallel_for(Kokkos::MDRangePolicy>({0, 0}, {ny, nx}), From 6f56ca5ad5b832bbdd22e80f8121f7879abfb29b Mon Sep 17 00:00:00 2001 From: Sichao25 Date: Fri, 22 Aug 2025 20:47:58 -0400 Subject: [PATCH 12/18] modify func parameters --- src/pcms/interpolator/spline_interpolator.hpp | 81 +++++++++---------- 1 file changed, 37 insertions(+), 44 deletions(-) diff --git a/src/pcms/interpolator/spline_interpolator.hpp b/src/pcms/interpolator/spline_interpolator.hpp index a5e56cb4c..69dbcaf8b 100644 --- a/src/pcms/interpolator/spline_interpolator.hpp +++ b/src/pcms/interpolator/spline_interpolator.hpp @@ -30,7 +30,7 @@ T get_element_from_span(Rank1View span, LO index) { } template -void isUniformAscending(Rank1View x, const T &ztol) { +void isUniformAscending(Rank1View x, T ztol) { using execution_space = typename MemorySpace::execution_space; LO inx = static_cast(x.extent(0)); @@ -59,7 +59,7 @@ void check_grid( template KOKKOS_INLINE_FUNCTION void -inGrid(T &xget, T &zxget, Rank1View x, const LO &nx, LO &ier) { +inGrid(T xget, T &zxget, Rank1View x, LO nx, LO &ier) { if (xget < x[0] || xget > x[nx - 1]) { T zxtol = 4.0e-7 * std::max(std::abs(x[0]), std::abs(x[nx - 1])); @@ -92,8 +92,8 @@ inGrid(T &xget, T &zxget, Rank1View x, const LO &nx, LO &ier) { * during spline setup. */ template -void correction_detect(Rank1View bcmin, LO &ibcmin, LO &iflg2, - LO &nx) { +void correction_detect(Rank1View bcmin, LO ibcmin, LO &iflg2, + LO nx) { using execution_space = typename MemorySpace::execution_space; if (ibcmin == 1 || ibcmin == 2) { Kokkos::parallel_reduce( @@ -123,7 +123,7 @@ void correction_detect(Rank1View bcmin, LO &ibcmin, LO &iflg2, * 1996, p. 251. [3] W. A. Houlberg and D. McCune, March 2000. */ template -KOKKOS_FUNCTION void v_spline(const LO &k_bc1, const LO &k_bcn, const LO &n, +KOKKOS_FUNCTION void v_spline(LO k_bc1, LO k_bcn, LO n, Rank1View x, Rank2View f, Rank1View wk) { @@ -594,9 +594,9 @@ KOKKOS_FUNCTION void v_spline(const LO &k_bc1, const LO &k_bcn, const LO &n, template KOKKOS_FUNCTION void -solve_cubic_spline_explicit(Rank1View x, const LO &nx, - Rank2View fspl, const LO &ibcxmin, - const T &bcxmin, const LO &ibcxmax, const T &bcxmax, +solve_cubic_spline_explicit(Rank1View x, LO nx, + Rank2View fspl, LO ibcxmin, + T bcxmin, LO ibcxmax, T bcxmax, Rank1View wk) { T half = 0.5; @@ -631,7 +631,7 @@ solve_cubic_spline_explicit(Rank1View x, const LO &nx, template KOKKOS_INLINE_FUNCTION void cubic_evalfn_explicit(Kokkos::View selector, - Rank1View fval, const LO &i, const T &dx, + Rank1View fval, LO i, T dx, Rank2View fspl) { LO iaval = 0; @@ -674,7 +674,7 @@ cubic_evalfn_explicit(Kokkos::View selector, */ template KOKKOS_INLINE_FUNCTION void -cubic_lookup_explicit(T xget, Rank1View x, const LO &nx, LO &i, +cubic_lookup_explicit(T xget, Rank1View x, LO nx, LO &i, T &dx, LO &ier) { LO nxm = nx - 1; T zxget = xget; @@ -712,7 +712,7 @@ template KOKKOS_INLINE_FUNCTION void cubic_eval_explicit(T xget, Kokkos::View iselect, Rank1View fval, Rank1View x, - const LO &nx, Rank2View fspl, LO &ier) { + LO nx, Rank2View fspl, LO &ier) { LO ia = 0; T dxa = 0.0; cubic_lookup_explicit(xget, x, nx, ia, dxa, ier); @@ -727,9 +727,9 @@ cubic_eval_explicit(T xget, Kokkos::View iselect, // TODO: take member type as parameter for further optimization template KOKKOS_FUNCTION void solve_cubic_spline_compact( - Rank1View x, const LO &nx, Rank2View fspl, - Rank2View fspl4, const LO &ibcxmin, const T &bcxmin, - const LO &ibcxmax, const T &bcxmax, Rank1View wk) { + Rank1View x, LO nx, Rank2View fspl, + Rank2View fspl4, LO ibcxmin, T bcxmin, + LO ibcxmax, T bcxmax, Rank1View wk) { // Copy f data to fspl4 and zero out second derivative output for (LO i = 0; i < nx; ++i) { fspl4(0, i) = fspl(0, i); @@ -761,8 +761,8 @@ KOKKOS_FUNCTION void solve_cubic_spline_compact( template KOKKOS_INLINE_FUNCTION void cubic_evalfn_compact(Kokkos::View selector, - Rank1View fval, const LO &i, - const T &xparam, const T &hx, const T &hxi, + Rank1View fval, LO i, + T xparam, T hx, T hxi, Rank2View fs2) { const T sixth = 1.0 / 6.0; LO iadr = 0; @@ -833,7 +833,7 @@ cubic_evalfn_compact(Kokkos::View selector, */ template KOKKOS_INLINE_FUNCTION void -cubic_lookup_compact(T xget, Rank1View x, const LO &nx, LO &i, +cubic_lookup_compact(T xget, Rank1View x, LO nx, LO &i, T &xparam, T &hx, T &hxi, LO &ier) { ier = 0; @@ -871,8 +871,7 @@ template KOKKOS_INLINE_FUNCTION void cubic_eval_compact(T xget, Kokkos::View ict, Rank1View fval, Rank1View x, - const LO &nx, // size of x - Rank2View fspl, LO &ier) { + LO nx, Rank2View fspl, LO &ier) { // Initialize output zone info LO i = 0; @@ -906,7 +905,7 @@ cubic_eval_compact(T xget, Kokkos::View ict, template KOKKOS_INLINE_FUNCTION void bicubic_lookup_explicit(T xget, T yget, Rank1View x, - const LO &nx, Rank1View y, const LO &ny, + LO nx, Rank1View y, LO ny, LO &i, LO &j, T &dx, T &dy, LO &ier) { LO nxm = nx - 1; LO nym = ny - 1; @@ -954,14 +953,8 @@ bicubic_lookup_explicit(T xget, T yget, Rank1View x, */ template KOKKOS_INLINE_FUNCTION void bicubic_evalfn_explicit( - Kokkos::View - ict, // Selector array for which derivatives to compute - Rank1View fval, // Output array: size [ivd, *] (flattened) - const LO &i, // Grid cell indices in x direction - const LO &j, // Grid cell indices in y direction - const T &dx, // x displacements within cells - const T &dy, // y displacements within cells - Rank4View fspl // Spline coefficients + Kokkos::View ict, Rank1View fval, + LO i, LO j, T dx, T dy, Rank4View fspl ) { LO iaval = 0; // Index for fval if (ict[0] <= 2) { @@ -1165,8 +1158,8 @@ template KOKKOS_INLINE_FUNCTION void bicubic_eval_explicit(T xget, T yget, Kokkos::View iselect, Rank1View fval, - Rank1View x, const LO &nx, - Rank1View y, const LO &ny, + Rank1View x, LO nx, + Rank1View y, LO ny, Rank4View fspl, LO &ier) { LO i = 0; LO j = 0; @@ -1469,7 +1462,7 @@ void solve_bicubic_spline_explicit(Rank1View x, LO inx, template KOKKOS_INLINE_FUNCTION void bicubic_lookup_compact(T xget, T yget, Rank1View x, - const LO &nx, Rank1View y, const LO &ny, + LO nx, Rank1View y, LO ny, LO &i, LO &j, T &xparam, T &yparam, T &hx, T &hxi, T &hy, T &hyi, LO &ier) { ier = 0; @@ -1525,9 +1518,9 @@ bicubic_lookup_compact(T xget, T yget, Rank1View x, template KOKKOS_INLINE_FUNCTION void bicubic_evalfn_compact(Kokkos::View ict, LO ivec, LO ivecd, - Rank1View fval, const LO &i, const LO &j, - const T &xparam, const T &yparam, const T &hx, - const T &hxi, const T &hy, const T &hyi, + Rank1View fval, LO i, LO j, + T xparam, T yparam, T hx, + T hxi, T hy, T hyi, Rank3View f) { constexpr T sixth = 1.0 / 6.0; const T z36th = sixth * sixth; @@ -1841,8 +1834,8 @@ template KOKKOS_INLINE_FUNCTION void bicubic_eval_compact( T xget, T yget, Kokkos::View ict, Rank1View fval, // output (size depends on ict) - Rank1View x, const LO &nx, Rank1View y, - const LO &ny, Rank3View f, // input (size depends on ict) + Rank1View x, LO nx, Rank1View y, + LO ny, Rank3View f, // input (size depends on ict) LO &ier) { // Local variables LO i = 0, j = 0; @@ -2157,8 +2150,8 @@ class ExplicitCubicSplineInterpolator */ ExplicitCubicSplineInterpolator(Rank1View x, Rank1View values, - BoundaryCondition ibcxmin, const T &bcxmin, - BoundaryCondition ibcxmax, const T &bcxmax); + BoundaryCondition ibcxmin, T bcxmin, + BoundaryCondition ibcxmax, T bcxmax); /** \brief Construct the interpolator object and set up the coefficients with * default boundary conditions @@ -2236,8 +2229,8 @@ class CompactCubicSplineInterpolator */ CompactCubicSplineInterpolator(Rank1View x, Rank1View values, - BoundaryCondition ibcxmin, const T &bcxmin, - BoundaryCondition ibcxmax, const T &bcxmax); + BoundaryCondition ibcxmin, T bcxmin, + BoundaryCondition ibcxmax, T bcxmax); /** \brief Construct the interpolator object and set up the coefficients with * default boundary conditions @@ -2575,9 +2568,9 @@ template ExplicitCubicSplineInterpolator:: ExplicitCubicSplineInterpolator(Rank1View x, Rank1View values, - BoundaryCondition ibcxmin, const T &bcxmin, + BoundaryCondition ibcxmin, T bcxmin, BoundaryCondition ibcxmax, - const T &bcxmax) { + T bcxmax) { detail::check_grid(x); this->x_ = x; LO nx = x.extent(0); @@ -2611,8 +2604,8 @@ ExplicitCubicSplineInterpolator:: template CompactCubicSplineInterpolator::CompactCubicSplineInterpolator( Rank1View x, Rank1View values, - BoundaryCondition ibcxmin, const T &bcxmin, BoundaryCondition ibcxmax, - const T &bcxmax) { + BoundaryCondition ibcxmin, T bcxmin, BoundaryCondition ibcxmax, + T bcxmax) { detail::check_grid(x); this->x_ = x; LO nx = x.extent(0); From 664a9c8ec1a8ffea5f663895158d9edcb99c6460 Mon Sep 17 00:00:00 2001 From: Sichao25 Date: Sun, 24 Aug 2025 13:04:12 -0400 Subject: [PATCH 13/18] improve coding style --- src/pcms/interpolator/spline_interpolator.hpp | 225 +++++++----------- 1 file changed, 84 insertions(+), 141 deletions(-) diff --git a/src/pcms/interpolator/spline_interpolator.hpp b/src/pcms/interpolator/spline_interpolator.hpp index 69dbcaf8b..98eb910b7 100644 --- a/src/pcms/interpolator/spline_interpolator.hpp +++ b/src/pcms/interpolator/spline_interpolator.hpp @@ -13,12 +13,6 @@ namespace pcms { namespace detail { -void ibc_check(LO ibc, const std::string &slbl, const std::string &xlbl, - LO imin, LO imax) { - - PCMS_ALWAYS_ASSERT(ibc >= imin && ibc <= imax); -} - template T get_element_from_span(Rank1View span, LO index) { T element; @@ -129,9 +123,6 @@ KOKKOS_FUNCTION void v_spline(LO k_bc1, LO k_bcn, LO n, Rank1View wk) { LO i_bc1 = k_bc1; LO i_bcn = k_bcn; - LO iord1, iord2, imin, imax; - T a1, b1, an, bn, f0, fh, h; - const T dx = x(1) - x(0); // Clip to allowed ranges if (i_bc1 < -1 || i_bc1 > 7) @@ -158,6 +149,9 @@ KOKKOS_FUNCTION void v_spline(LO k_bc1, LO k_bcn, LO n, i3perio = 1; } + LO iord1; + LO iord2; + if (n == 2) { if (i_bc1 == -1) { i_bc1 = 5; @@ -180,13 +174,16 @@ KOKKOS_FUNCTION void v_spline(LO k_bc1, LO k_bcn, LO n, else iord2 = 2; } - imin = 0; - imax = n - 1; - a1 = 0.0; - b1 = 0.0; - an = 0.0; - bn = 0.0; + T imin = 0; + T imax = n - 1; + T a1 = 0.0; + T b1 = 0.0; + T an = 0.0; + T bn = 0.0; + T f0, fh, h; + + const T dx = x(1) - x(0); if (i_bc1 == 1) { a1 = f(1, 0); @@ -599,8 +596,8 @@ solve_cubic_spline_explicit(Rank1View x, LO nx, T bcxmin, LO ibcxmax, T bcxmax, Rank1View wk) { - T half = 0.5; - T sixth = 0.166666666666666667; + const T half = 0.5; + const T sixth = 0.166666666666666667; if (ibcxmin == 1) { fspl(1, 0) = bcxmin; @@ -663,6 +660,20 @@ cubic_evalfn_explicit(Kokkos::View selector, } } // end evalfn +template +KOKKOS_INLINE_FUNCTION LO lookup_in_grid(T zxget, Rank1View x, + LO nx) { + LO nxm = nx - 1; + LO ii = static_cast(nxm * (zxget - x[0]) / (x[nx - 1] - x[0])); + LO i = std::min(nxm - 1, ii); + if (zxget < x[i]) { + i = std::max(0, i - 1); + } else if (zxget > x[i + 1]) { + i = std::min(nxm - 1, i + 1); + } + return i; +} + /** \brief Lookup the grid point and compute the displacement * * \param xget input point where the spline is evaluated @@ -676,20 +687,12 @@ template KOKKOS_INLINE_FUNCTION void cubic_lookup_explicit(T xget, Rank1View x, LO nx, LO &i, T &dx, LO &ier) { - LO nxm = nx - 1; T zxget = xget; // Range check inGrid(xget, zxget, x, nx, ier); - LO ii = static_cast(nxm * (zxget - x[0]) / (x[nx - 1] - x[0])); - i = std::min(nxm - 1, ii); - - if (zxget < x[i]) { - i = std::max(0, i - 1); - } else if (zxget > x[i + 1]) { - i = std::min(nxm - 1, i + 1); - } + i = lookup_in_grid(zxget, x, nx); dx = zxget - x[i]; } @@ -768,12 +771,12 @@ cubic_evalfn_compact(Kokkos::View selector, LO iadr = 0; if (selector[0] <= 2) { + T xp = xparam; + T xpi = 1.0 - xp; if (selector[0] == 1) { // Function value f(x) ++iadr; // TODO: too much temp varibale created? - T xp = xparam; - T xpi = 1.0 - xp; T xp2 = xp * xp; T xpi2 = xpi * xpi; T cx = xp * (xp2 - 1.0); @@ -789,8 +792,6 @@ cubic_evalfn_compact(Kokkos::View selector, if (selector[1] == 1) { // First derivative df/dx ++iadr; - T xp = xparam; - T xpi = 1.0 - xp; T xp2 = xp * xp; T xpi2 = xpi * xpi; @@ -806,8 +807,6 @@ cubic_evalfn_compact(Kokkos::View selector, if (selector[2] == 1) { // Second derivative d2f/dx2 ++iadr; - T xp = xparam; - T xpi = 1.0 - xp; T sum = xpi * fs2(1, i) + xp * fs2(1, i + 1); fval(iadr - 1) = sum; @@ -835,22 +834,11 @@ template KOKKOS_INLINE_FUNCTION void cubic_lookup_compact(T xget, Rank1View x, LO nx, LO &i, T &xparam, T &hx, T &hxi, LO &ier) { - ier = 0; - T zxget = xget; inGrid(xget, zxget, x, nx, ier); - LO nxm = nx - 1; - - // TODO: potential duplicate code - LO ii = static_cast(nxm * (zxget - x[0]) / (x[nx - 1] - x[0])); - i = std::min(nxm - 1, ii); - if (zxget < x[i]) { - i = std::max(0, i - 1); - } else if (zxget > x[i + 1]) { - i = std::min(nxm - 2, i + 1); - } + i = lookup_in_grid(zxget, x, nx); hx = x[i + 1] - x[i]; hxi = 1.0 / hx; @@ -907,11 +895,6 @@ KOKKOS_INLINE_FUNCTION void bicubic_lookup_explicit(T xget, T yget, Rank1View x, LO nx, Rank1View y, LO ny, LO &i, LO &j, T &dx, T &dy, LO &ier) { - LO nxm = nx - 1; - LO nym = ny - 1; - LO ii, jj; - - ier = 0; T zxget = xget; T zyget = yget; @@ -921,21 +904,8 @@ bicubic_lookup_explicit(T xget, T yget, Rank1View x, if (ier != 0) return; - ii = static_cast(nxm * (zxget - x[0]) / (x[nx - 1] - x[0])); - i = std::min(nxm - 2, ii); - if (zxget < x[i]) { - i--; - } else if (zxget > x[i + 1]) { - i++; - } - - jj = static_cast(nym * (zyget - y[0]) / (y[ny - 1] - y[0])); - j = std::min(nym - 2, jj); - if (zyget < y[j]) { - j--; - } else if (zyget > y[j + 1]) { - j++; - } + i = lookup_in_grid(zxget, x, nx); + j = lookup_in_grid(zyget, y, ny); dx = zxget - x[i]; dy = zyget - y[j]; @@ -1186,7 +1156,15 @@ void solve_bicubic_spline_explicit(Rank1View x, LO inx, Rank1View wk) { using execution_space = typename MemorySpace::execution_space; using member_type = typename Kokkos::TeamPolicy::member_type; + LO iflg2 = 0; + if (ibcymin != -1) { + correction_detect(bcymin, ibcymin, iflg2, inx); + correction_detect(bcymax, ibcymax, iflg2, inx); + } + + const T xo2 = 0.5; + const T xo6 = 1.0 / 6.0; auto fspl_l_x = Rank2View(wk.data_handle() + 4 * inx * iny, 4 * inx, iny); @@ -1194,14 +1172,6 @@ void solve_bicubic_spline_explicit(Rank1View x, LO inx, inx * iny); auto fspl_l_y = Rank2View(wk.data_handle(), 4 * inx, iny); - if (ibcymin != -1) { - correction_detect(bcymin, ibcymin, iflg2, inx); - correction_detect(bcymax, ibcymax, iflg2, inx); - } - - T xo2 = 0.5; - T xo6 = 1.0 / 6.0; - Kokkos::parallel_for( Kokkos::TeamPolicy(iny, Kokkos::AUTO), KOKKOS_LAMBDA(const member_type &team) { @@ -1465,31 +1435,14 @@ bicubic_lookup_compact(T xget, T yget, Rank1View x, LO nx, Rank1View y, LO ny, LO &i, LO &j, T &xparam, T &yparam, T &hx, T &hxi, T &hy, T &hyi, LO &ier) { - ier = 0; - T zxget = xget; T zyget = yget; inGrid(xget, zxget, x, nx, ier); inGrid(yget, zyget, y, ny, ier); - LO nxm = nx - 1; // Number of LOervals in x - LO nym = ny - 1; // Number of LOervals in y - // Determine zone index i - LO ii = static_cast(nxm * (zxget - x[0]) / (x[nx - 1] - x[0])); - i = std::min(nxm - 1, ii); - if (zxget < x[i]) - --i; - else if (zxget > x[i + 1]) - ++i; - - // Determine zone index j - ii = static_cast(nym * (zyget - y[0]) / (y[ny - 1] - y[0])); - j = std::min(nym - 1, ii); - if (zyget < y[j]) - --j; - else if (zyget > y[j + 1]) - ++j; + i = lookup_in_grid(zxget, x, nx); + j = lookup_in_grid(zyget, y, ny); hx = x[i + 1] - x[i]; hy = y[j + 1] - y[j]; @@ -1528,16 +1481,15 @@ bicubic_evalfn_compact(Kokkos::View ict, LO ivec, LO ivecd, // ict[0] = 1 or 2 → f, df/dx, df/dy, d²f/dx², d²f/dy², d²f/dxdy if (ict[0] <= 2) { + T xp = xparam, xpi = 1.0 - xp; + T yp = yparam, ypi = 1.0 - yp; // f (function value) if (ict[0] == 1) { iadr++; - T xp = xparam, xpi = 1.0 - xp; T xp2 = xp * xp, xpi2 = xpi * xpi; T cx = xp * (xp2 - 1.0); T cxi = xpi * (xpi2 - 1.0); T hx2 = hx * hx; - - T yp = yparam, ypi = 1.0 - yp; T yp2 = yp * yp, ypi2 = ypi * ypi; T cy = yp * (yp2 - 1.0); T cyi = ypi * (ypi2 - 1.0); @@ -1560,11 +1512,9 @@ bicubic_evalfn_compact(Kokkos::View ict, LO ivec, LO ivecd, // df/dx if (ict[1] == 1) { iadr++; - T xp = xparam, xpi = 1.0 - xp; T xp2 = xp * xp, xpi2 = xpi * xpi; T cxd = 3.0 * xp2 - 1.0; T cxdi = -3.0 * xpi2 + 1.0; - T yp = yparam, ypi = 1.0 - yp; T yp2 = yp * yp, ypi2 = ypi * ypi; T cy = yp * (yp2 - 1.0); T cyi = ypi * (ypi2 - 1.0); @@ -1587,12 +1537,10 @@ bicubic_evalfn_compact(Kokkos::View ict, LO ivec, LO ivecd, // df/dy if (ict[2] == 1) { iadr++; - T xp = xparam, xpi = 1.0 - xp; T xp2 = xp * xp, xpi2 = xpi * xpi; T cx = xp * (xp2 - 1.0); T cxi = xpi * (xpi2 - 1.0); T hx2 = hx * hx; - T yp = yparam, ypi = 1.0 - yp; T yp2 = yp * yp, ypi2 = ypi * ypi; T cyd = 3.0 * yp2 - 1.0; T cydi = -3.0 * ypi2 + 1.0; @@ -1614,8 +1562,6 @@ bicubic_evalfn_compact(Kokkos::View ict, LO ivec, LO ivecd, // d2f/dx2 if (ict[3] == 1) { iadr++; - T xp = xparam, xpi = 1.0 - xp; - T yp = yparam, ypi = 1.0 - yp; T yp2 = yp * yp, ypi2 = ypi * ypi; T cy = yp * (yp2 - 1.0); T cyi = ypi * (ypi2 - 1.0); @@ -1632,12 +1578,10 @@ bicubic_evalfn_compact(Kokkos::View ict, LO ivec, LO ivecd, // d2f/dy2 if (ict[4] == 1) { iadr++; - T xp = xparam, xpi = 1.0 - xp; T xp2 = xp * xp, xpi2 = xpi * xpi; T cx = xp * (xp2 - 1.0); T cxi = xpi * (xpi2 - 1.0); T hx2 = hx * hx; - T yp = yparam, ypi = 1.0 - yp; T sum = xpi * (ypi * f(2, i, j) + yp * f(2, i, j + 1)) + xp * (ypi * f(2, i + 1, j) + yp * f(2, i + 1, j + 1)); @@ -1650,11 +1594,9 @@ bicubic_evalfn_compact(Kokkos::View ict, LO ivec, LO ivecd, // d2f/dxdy if (ict[5] == 1) { iadr++; - T xp = xparam, xpi = 1.0 - xp; T xp2 = xp * xp, xpi2 = xpi * xpi; T cxd = 3.0 * xp2 - 1.0; T cxdi = -3.0 * xpi2 + 1.0; - T yp = yparam, ypi = 1.0 - yp; T yp2 = yp * yp, ypi2 = ypi * ypi; T cyd = 3.0 * yp2 - 1.0; T cydi = -3.0 * ypi2 + 1.0; @@ -1972,11 +1914,11 @@ void solve_bicubic_spline_compact(Rank1View x, LO nx, [=](LO iy) { f(3, ix, iy) = fwk_y_view(1, iy); }); }); - T zbcmin = 0.0; - T zbcmax = 0.0; - // Correct for inhomogeneous boundary conditions if needed if (iflg2 == 1) { + T zbcmin = 0.0; + T zbcmax = 0.0; + auto fcorr = Rank3View(wk.data_handle() + 7 * ny * nx, 2, nx, ny); @@ -2080,7 +2022,7 @@ void solve_bicubic_spline_compact(Rank1View x, LO nx, * difference. THIRD_DIV_DIFF_MATCH | ibcxmin=7 | ibcxmax=7 -- third * derivative matches the third divided difference. */ -enum BoundaryCondition { +enum class BoundaryCondition { PERIODIC = -1, ///< Periodic boundary condition: s'(x(0))=s'(x(-1)) and ///< s''(x(0))=s''(x(-1)) NOT_A_KNOT = 0, ///< Not-a-knot boundary condition @@ -2465,27 +2407,27 @@ class CompactBiCubicSplineInterpolator template Rank2View ExplicitCubicSplineInterpolator::get_coefficients_view() { - return Rank2View(this->coefficients_.data(), 4, this->x_.extent(0)); + return Rank2View(coefficients_.data(), 4, x_.extent(0)); } template Rank2View CompactCubicSplineInterpolator::get_coefficients_view() { - return Rank2View(this->coefficients_.data(), 2, this->x_.extent(0)); + return Rank2View(coefficients_.data(), 2, x_.extent(0)); } template Rank4View ExplicitBiCubicSplineInterpolator::get_coefficients_view() { - return Rank4View(this->coefficients_.data(), 4, 4, this->x_.extent(0), - this->y_.extent(0)); + return Rank4View(coefficients_.data(), 4, 4, x_.extent(0), + y_.extent(0)); } template Rank3View CompactBiCubicSplineInterpolator::get_coefficients_view() { - return Rank3View(this->coefficients_.data(), 4, this->x_.extent(0), - this->y_.extent(0)); + return Rank3View(coefficients_.data(), 4, x_.extent(0), + y_.extent(0)); } template struct InitCubicCoeffFunctor { @@ -2572,10 +2514,10 @@ ExplicitCubicSplineInterpolator:: BoundaryCondition ibcxmax, T bcxmax) { detail::check_grid(x); - this->x_ = x; + x_ = x; LO nx = x.extent(0); Kokkos::View fspl_view("coefficients", 4 * nx); - this->coefficients_ = fspl_view; + coefficients_ = fspl_view; auto fspl = get_coefficients_view(); InitCubicCoeffFunctor init_functor(fspl, values); Kokkos::parallel_for("initialize_coefficients", nx, init_functor); @@ -2595,8 +2537,8 @@ template ExplicitCubicSplineInterpolator:: ExplicitCubicSplineInterpolator(Rank1View x, Rank1View values) - : ExplicitCubicSplineInterpolator(x, values, NOT_A_KNOT, 0, NOT_A_KNOT, - 0) { // Delegates to primary constructor + : ExplicitCubicSplineInterpolator(x, values, BoundaryCondition::NOT_A_KNOT, 0, + BoundaryCondition::NOT_A_KNOT, 0) { std::cout << "Not a knot boundary condition is applied by default" << std::endl; } @@ -2607,10 +2549,10 @@ CompactCubicSplineInterpolator::CompactCubicSplineInterpolator( BoundaryCondition ibcxmin, T bcxmin, BoundaryCondition ibcxmax, T bcxmax) { detail::check_grid(x); - this->x_ = x; + x_ = x; LO nx = x.extent(0); Kokkos::View fspl_view("coefficients", 2 * nx); - this->coefficients_ = fspl_view; + coefficients_ = fspl_view; auto fspl = get_coefficients_view(); InitCubicCoeffFunctor init_functor(fspl, values); Kokkos::parallel_for("initialize_coefficients", nx, init_functor); @@ -2631,8 +2573,8 @@ CompactCubicSplineInterpolator::CompactCubicSplineInterpolator( template CompactCubicSplineInterpolator::CompactCubicSplineInterpolator( Rank1View x, Rank1View fx) - : CompactCubicSplineInterpolator(x, fx, NOT_A_KNOT, 0, NOT_A_KNOT, - 0) { // Delegates to primary constructor + : CompactCubicSplineInterpolator(x, fx, BoundaryCondition::NOT_A_KNOT, 0, + BoundaryCondition::NOT_A_KNOT, 0) { std::cout << "Not a knot boundary condition is applied by default" << std::endl; } @@ -2649,8 +2591,8 @@ void ExplicitCubicSplineInterpolator::evaluate( LO ier = 0; auto fval_view = Rank1View(fval.data_handle() + i * ivd, ivd); - detail::cubic_eval_explicit(xvec(i), selector, fval_view, this->x_, - this->x_.extent(0), fspl, ier); + detail::cubic_eval_explicit(xvec(i), selector, fval_view, x_, + x_.extent(0), fspl, ier); }); } @@ -2673,8 +2615,8 @@ void CompactCubicSplineInterpolator::evaluate( LO ier = 0; auto fval_view = Rank1View(fval.data_handle() + i * ivd, ivd); - detail::cubic_eval_compact(xvec(i), selector, fval_view, this->x_, - this->x_.extent(0), fspl, ier); + detail::cubic_eval_compact(xvec(i), selector, fval_view, x_, + x_.extent(0), fspl, ier); }); } @@ -2703,8 +2645,8 @@ void ExplicitBiCubicSplineInterpolator::evaluate( auto fval_view = Rank1View(fval.data_handle() + i * ivd, ivd); detail::bicubic_eval_explicit(xvec(i), yvec(i), iselect, fval_view, - this->x_, this->x_.extent(0), this->y_, - this->y_.extent(0), fspl, ier); + x_, x_.extent(0), y_, + y_.extent(0), fspl, ier); }); } @@ -2736,8 +2678,8 @@ void CompactBiCubicSplineInterpolator::evaluate( auto fval_view = Rank1View(fval.data_handle() + i * ivd, ivd); detail::bicubic_eval_compact(xvec(i), yvec(i), iselect, fval_view, - this->x_, this->x_.extent(0), this->y_, - this->y_.extent(0), fspl, ier); + x_, x_.extent(0), y_, + y_.extent(0), fspl, ier); }); } @@ -2803,12 +2745,12 @@ ExplicitBiCubicSplineInterpolator:: detail::check_grid(x); detail::check_grid(y); - this->x_ = x; - this->y_ = y; + x_ = x; + y_ = y; LO ny = y.extent(0); LO nx = x.extent(0); Kokkos::View fspl_view("fspl view", 4 * 4 * nx * ny); - this->coefficients_ = fspl_view; + coefficients_ = fspl_view; auto fspl = get_coefficients_view(); InitExplicitBiCubicCoeffFunctor init_functor(fspl, values, ny); @@ -2830,8 +2772,8 @@ ExplicitBiCubicSplineInterpolator:: Rank1View y, Rank1View values) : ExplicitBiCubicSplineInterpolator( - x, y, values, NOT_A_KNOT, {}, NOT_A_KNOT, {}, NOT_A_KNOT, {}, - NOT_A_KNOT, {}) { // Delegates to primary constructor + x, y, values, BoundaryCondition::NOT_A_KNOT, {}, BoundaryCondition::NOT_A_KNOT, + {}, BoundaryCondition::NOT_A_KNOT, {}, BoundaryCondition::NOT_A_KNOT, {}) { std::cout << "Not a knot boundary condition is applied by default" << std::endl; } @@ -2848,12 +2790,12 @@ CompactBiCubicSplineInterpolator:: detail::check_grid(x); detail::check_grid(y); - this->x_ = x; - this->y_ = y; + x_ = x; + y_ = y; LO ny = y.extent(0); LO nx = x.extent(0); Kokkos::View fspl_view("fspl view", 4 * nx * ny); - this->coefficients_ = fspl_view; + coefficients_ = fspl_view; auto fspl = get_coefficients_view(); InitCompactBiCubicCoeffFunctor init_functor(fspl, values, ny); @@ -2874,9 +2816,10 @@ CompactBiCubicSplineInterpolator:: CompactBiCubicSplineInterpolator(Rank1View x, Rank1View y, Rank1View values) - : CompactBiCubicSplineInterpolator(x, y, values, NOT_A_KNOT, {}, NOT_A_KNOT, - {}, NOT_A_KNOT, {}, NOT_A_KNOT, - {}) { // Delegates to primary constructor + : CompactBiCubicSplineInterpolator(x, y, values, BoundaryCondition::NOT_A_KNOT, {}, + BoundaryCondition::NOT_A_KNOT, {}, + BoundaryCondition::NOT_A_KNOT, {}, + BoundaryCondition::NOT_A_KNOT, {}) { std::cout << "Not a knot boundary condition is applied by default" << std::endl; } From 58a382eeb3909946947dd7eb9ed7766ee6e5d884 Mon Sep 17 00:00:00 2001 From: Sichao25 Date: Fri, 29 Aug 2025 18:31:09 -0400 Subject: [PATCH 14/18] rename utilities and add boolean return value --- src/pcms/interpolator/spline_interpolator.hpp | 206 +++++++++--------- 1 file changed, 99 insertions(+), 107 deletions(-) diff --git a/src/pcms/interpolator/spline_interpolator.hpp b/src/pcms/interpolator/spline_interpolator.hpp index 98eb910b7..a41320ae9 100644 --- a/src/pcms/interpolator/spline_interpolator.hpp +++ b/src/pcms/interpolator/spline_interpolator.hpp @@ -24,36 +24,38 @@ T get_element_from_span(Rank1View span, LO index) { } template -void isUniformAscending(Rank1View x, T ztol) { +bool isUniformAscending(Rank1View x, T ztol) { using execution_space = typename MemorySpace::execution_space; LO inx = static_cast(x.extent(0)); - - if (inx <= 1) - return; - T dxavg = (get_element_from_span(x, inx - 1) - get_element_from_span(x, 0)) / (inx - 1); T zeps = std::abs(ztol * dxavg); + bool is_uniform_ascending = true; - Kokkos::parallel_for( - Kokkos::RangePolicy(1, inx), KOKKOS_LAMBDA(const LO ix) { + Kokkos::parallel_reduce( + "check_uniform_ascending", Kokkos::RangePolicy(1, inx), + KOKKOS_LAMBDA(const LO ix, bool &local_flag) { T zdiffx = x(ix) - x(ix - 1); - assert(zdiffx > 0.0); T zdiff = zdiffx - dxavg; - assert(std::abs(zdiff) <= zeps); - }); + if (zdiffx < 0.0 || std::abs(zdiff) > zeps) { + local_flag = false; + } + }, + Kokkos::LAnd(is_uniform_ascending)); + return is_uniform_ascending; } template -void check_grid( - Rank1View x) { +void grid_valid(Rank1View x) { PCMS_ALWAYS_ASSERT(x.extent(0) >= 2); - detail::isUniformAscending(x, 1.0e-3); + bool is_uniform_ascending = isUniformAscending(x, 1.0e-3); + PCMS_ALWAYS_ASSERT(is_uniform_ascending); } template -KOKKOS_INLINE_FUNCTION void -inGrid(T xget, T &zxget, Rank1View x, LO nx, LO &ier) { +KOKKOS_INLINE_FUNCTION void clamp_to_grid_range(T xget, T &zxget, + Rank1View x, + LO nx, LO &ier) { if (xget < x[0] || xget > x[nx - 1]) { T zxtol = 4.0e-7 * std::max(std::abs(x[0]), std::abs(x[nx - 1])); @@ -86,8 +88,8 @@ inGrid(T xget, T &zxget, Rank1View x, LO nx, LO &ier) { * during spline setup. */ template -void correction_detect(Rank1View bcmin, LO ibcmin, LO &iflg2, - LO nx) { +void detect_inhomogeneous_bc(Rank1View bcmin, LO ibcmin, + LO &iflg2, LO nx) { using execution_space = typename MemorySpace::execution_space; if (ibcmin == 1 || ibcmin == 2) { Kokkos::parallel_reduce( @@ -117,10 +119,10 @@ void correction_detect(Rank1View bcmin, LO ibcmin, LO &iflg2, * 1996, p. 251. [3] W. A. Houlberg and D. McCune, March 2000. */ template -KOKKOS_FUNCTION void v_spline(LO k_bc1, LO k_bcn, LO n, - Rank1View x, - Rank2View f, - Rank1View wk) { +KOKKOS_FUNCTION void compute_spline_coefficients(LO k_bc1, LO k_bcn, LO n, + Rank1View x, + Rank2View f, + Rank1View wk) { LO i_bc1 = k_bc1; LO i_bcn = k_bcn; @@ -587,14 +589,12 @@ KOKKOS_FUNCTION void v_spline(LO k_bc1, LO k_bcn, LO n, } } } -} // v_spline +} // compute_spline_coefficients template -KOKKOS_FUNCTION void -solve_cubic_spline_explicit(Rank1View x, LO nx, - Rank2View fspl, LO ibcxmin, - T bcxmin, LO ibcxmax, T bcxmax, - Rank1View wk) { +KOKKOS_FUNCTION void solve_cubic_spline_explicit( + Rank1View x, LO nx, Rank2View fspl, + LO ibcxmin, T bcxmin, LO ibcxmax, T bcxmax, Rank1View wk) { const T half = 0.5; const T sixth = 0.166666666666666667; @@ -610,7 +610,8 @@ solve_cubic_spline_explicit(Rank1View x, LO nx, } else if (ibcxmax == 2) { fspl(2, nx - 1) = bcxmax; } - v_spline(ibcxmin, ibcxmax, nx, x, fspl, wk); + compute_spline_coefficients(ibcxmin, ibcxmax, nx, x, fspl, + wk); for (LO i = 0; i < nx; ++i) { fspl(2, i) = half * fspl(2, i); fspl(3, i) = sixth * fspl(3, i); @@ -662,7 +663,7 @@ cubic_evalfn_explicit(Kokkos::View selector, template KOKKOS_INLINE_FUNCTION LO lookup_in_grid(T zxget, Rank1View x, - LO nx) { + LO nx) { LO nxm = nx - 1; LO ii = static_cast(nxm * (zxget - x[0]) / (x[nx - 1] - x[0])); LO i = std::min(nxm - 1, ii); @@ -685,12 +686,12 @@ KOKKOS_INLINE_FUNCTION LO lookup_in_grid(T zxget, Rank1View x, */ template KOKKOS_INLINE_FUNCTION void -cubic_lookup_explicit(T xget, Rank1View x, LO nx, LO &i, - T &dx, LO &ier) { +cubic_lookup_explicit(T xget, Rank1View x, LO nx, LO &i, T &dx, + LO &ier) { T zxget = xget; // Range check - inGrid(xget, zxget, x, nx, ier); + clamp_to_grid_range(xget, zxget, x, nx, ier); i = lookup_in_grid(zxget, x, nx); @@ -731,8 +732,8 @@ cubic_eval_explicit(T xget, Kokkos::View iselect, template KOKKOS_FUNCTION void solve_cubic_spline_compact( Rank1View x, LO nx, Rank2View fspl, - Rank2View fspl4, LO ibcxmin, T bcxmin, - LO ibcxmax, T bcxmax, Rank1View wk) { + Rank2View fspl4, LO ibcxmin, T bcxmin, LO ibcxmax, T bcxmax, + Rank1View wk) { // Copy f data to fspl4 and zero out second derivative output for (LO i = 0; i < nx; ++i) { fspl4(0, i) = fspl(0, i); @@ -764,9 +765,8 @@ KOKKOS_FUNCTION void solve_cubic_spline_compact( template KOKKOS_INLINE_FUNCTION void cubic_evalfn_compact(Kokkos::View selector, - Rank1View fval, LO i, - T xparam, T hx, T hxi, - Rank2View fs2) { + Rank1View fval, LO i, T xparam, T hx, + T hxi, Rank2View fs2) { const T sixth = 1.0 / 6.0; LO iadr = 0; @@ -836,7 +836,7 @@ cubic_lookup_compact(T xget, Rank1View x, LO nx, LO &i, T &xparam, T &hx, T &hxi, LO &ier) { T zxget = xget; - inGrid(xget, zxget, x, nx, ier); + clamp_to_grid_range(xget, zxget, x, nx, ier); i = lookup_in_grid(zxget, x, nx); @@ -892,14 +892,14 @@ cubic_eval_compact(T xget, Kokkos::View ict, */ template KOKKOS_INLINE_FUNCTION void -bicubic_lookup_explicit(T xget, T yget, Rank1View x, - LO nx, Rank1View y, LO ny, - LO &i, LO &j, T &dx, T &dy, LO &ier) { +bicubic_lookup_explicit(T xget, T yget, Rank1View x, LO nx, + Rank1View y, LO ny, LO &i, LO &j, T &dx, + T &dy, LO &ier) { T zxget = xget; T zyget = yget; - inGrid(xget, zxget, x, nx, ier); - inGrid(yget, zyget, y, ny, ier); + clamp_to_grid_range(xget, zxget, x, nx, ier); + clamp_to_grid_range(yget, zyget, y, ny, ier); if (ier != 0) return; @@ -922,10 +922,10 @@ bicubic_lookup_explicit(T xget, T yget, Rank1View x, * \param fspl bicubic spline coefficients */ template -KOKKOS_INLINE_FUNCTION void bicubic_evalfn_explicit( - Kokkos::View ict, Rank1View fval, - LO i, LO j, T dx, T dy, Rank4View fspl -) { +KOKKOS_INLINE_FUNCTION void +bicubic_evalfn_explicit(Kokkos::View ict, + Rank1View fval, LO i, LO j, T dx, T dy, + Rank4View fspl) { LO iaval = 0; // Index for fval if (ict[0] <= 2) { if ((ict[0] > 0) || (ict[0] == -1)) { @@ -1159,8 +1159,8 @@ void solve_bicubic_spline_explicit(Rank1View x, LO inx, LO iflg2 = 0; if (ibcymin != -1) { - correction_detect(bcymin, ibcymin, iflg2, inx); - correction_detect(bcymax, ibcymax, iflg2, inx); + detect_inhomogeneous_bc(bcymin, ibcymin, iflg2, inx); + detect_inhomogeneous_bc(bcymax, ibcymax, iflg2, inx); } const T xo2 = 0.5; @@ -1197,8 +1197,8 @@ void solve_bicubic_spline_explicit(Rank1View x, LO inx, else if (ibcxmax == 2) fspl_x_view(2, inx - 1) = bcxmax[iy]; - v_spline(ibcxmin, ibcxmax, inx, x, fspl_x_view, - wk_x_view); + compute_spline_coefficients(ibcxmin, ibcxmax, inx, x, + fspl_x_view, wk_x_view); } Kokkos::parallel_for(Kokkos::TeamThreadRange(team, inx), [=](LO ix) { @@ -1239,8 +1239,8 @@ void solve_bicubic_spline_explicit(Rank1View x, LO inx, ibcymaxa = 0; } - v_spline(ibcymina, ibcymaxa, iny, y, fspl_y_view, - wk_y_view); + compute_spline_coefficients( + ibcymina, ibcymaxa, iny, y, fspl_y_view, wk_y_view); } Kokkos::parallel_for(Kokkos::TeamThreadRange(team, iny), [=](LO iy) { @@ -1359,7 +1359,7 @@ void solve_bicubic_spline_explicit(Rank1View x, LO inx, auto fspl_s_y = Rank2View(fspl_l_y.data_handle() + iadr, 4, iny); - v_spline(ibcymin, ibcymax, iny, y, fspl_s_y, wk_y); + compute_spline_coefficients(ibcymin, ibcymax, iny, y, fspl_s_y, wk_y); }); Kokkos::parallel_for( @@ -1397,7 +1397,8 @@ void solve_bicubic_spline_explicit(Rank1View x, LO inx, fspl_x_view(1, inx - 1) = 0.0; fspl_x_view(2, inx - 1) = 0.0; - v_spline(ibcxmin, ibcxmax, inx, x, fspl_x_view, wk_x_view); + compute_spline_coefficients(ibcxmin, ibcxmax, inx, x, fspl_x_view, + wk_x_view); } Kokkos::parallel_for( @@ -1431,15 +1432,15 @@ void solve_bicubic_spline_explicit(Rank1View x, LO inx, */ template KOKKOS_INLINE_FUNCTION void -bicubic_lookup_compact(T xget, T yget, Rank1View x, - LO nx, Rank1View y, LO ny, - LO &i, LO &j, T &xparam, T &yparam, T &hx, T &hxi, T &hy, - T &hyi, LO &ier) { +bicubic_lookup_compact(T xget, T yget, Rank1View x, LO nx, + Rank1View y, LO ny, LO &i, LO &j, + T &xparam, T &yparam, T &hx, T &hxi, T &hy, T &hyi, + LO &ier) { T zxget = xget; T zyget = yget; - inGrid(xget, zxget, x, nx, ier); - inGrid(yget, zyget, y, ny, ier); + clamp_to_grid_range(xget, zxget, x, nx, ier); + clamp_to_grid_range(yget, zyget, y, ny, ier); i = lookup_in_grid(zxget, x, nx); j = lookup_in_grid(zyget, y, ny); @@ -1471,9 +1472,8 @@ bicubic_lookup_compact(T xget, T yget, Rank1View x, template KOKKOS_INLINE_FUNCTION void bicubic_evalfn_compact(Kokkos::View ict, LO ivec, LO ivecd, - Rank1View fval, LO i, LO j, - T xparam, T yparam, T hx, - T hxi, T hy, T hyi, + Rank1View fval, LO i, LO j, T xparam, + T yparam, T hx, T hxi, T hy, T hyi, Rank3View f) { constexpr T sixth = 1.0 / 6.0; const T z36th = sixth * sixth; @@ -1775,10 +1775,9 @@ bicubic_evalfn_compact(Kokkos::View ict, LO ivec, LO ivecd, template KOKKOS_INLINE_FUNCTION void bicubic_eval_compact( T xget, T yget, Kokkos::View ict, - Rank1View fval, // output (size depends on ict) - Rank1View x, LO nx, Rank1View y, - LO ny, Rank3View f, // input (size depends on ict) - LO &ier) { + Rank1View fval, Rank1View x, + LO nx, Rank1View y, LO ny, + Rank3View f, LO &ier) { // Local variables LO i = 0, j = 0; T xparam = 0.0, yparam = 0.0; @@ -1812,8 +1811,8 @@ void solve_bicubic_spline_compact(Rank1View x, LO nx, // Check if inhomogeneous y-boundary conditions exist if (ibcymin != -1) { - correction_detect(bcymin, ibcymin, iflg2, nx); - correction_detect(bcymax, ibcymax, iflg2, nx); + detect_inhomogeneous_bc(bcymin, ibcymin, iflg2, nx); + detect_inhomogeneous_bc(bcymax, ibcymax, iflg2, nx); } auto fspl_l_x = Rank2View(wk.data_handle(), 2 * ny, nx); @@ -2511,9 +2510,8 @@ ExplicitCubicSplineInterpolator:: ExplicitCubicSplineInterpolator(Rank1View x, Rank1View values, BoundaryCondition ibcxmin, T bcxmin, - BoundaryCondition ibcxmax, - T bcxmax) { - detail::check_grid(x); + BoundaryCondition ibcxmax, T bcxmax) { + detail::grid_valid(x); x_ = x; LO nx = x.extent(0); Kokkos::View fspl_view("coefficients", 4 * nx); @@ -2537,8 +2535,8 @@ template ExplicitCubicSplineInterpolator:: ExplicitCubicSplineInterpolator(Rank1View x, Rank1View values) - : ExplicitCubicSplineInterpolator(x, values, BoundaryCondition::NOT_A_KNOT, 0, - BoundaryCondition::NOT_A_KNOT, 0) { + : ExplicitCubicSplineInterpolator(x, values, BoundaryCondition::NOT_A_KNOT, + 0, BoundaryCondition::NOT_A_KNOT, 0) { std::cout << "Not a knot boundary condition is applied by default" << std::endl; } @@ -2546,9 +2544,8 @@ ExplicitCubicSplineInterpolator:: template CompactCubicSplineInterpolator::CompactCubicSplineInterpolator( Rank1View x, Rank1View values, - BoundaryCondition ibcxmin, T bcxmin, BoundaryCondition ibcxmax, - T bcxmax) { - detail::check_grid(x); + BoundaryCondition ibcxmin, T bcxmin, BoundaryCondition ibcxmax, T bcxmax) { + detail::grid_valid(x); x_ = x; LO nx = x.extent(0); Kokkos::View fspl_view("coefficients", 2 * nx); @@ -2620,7 +2617,8 @@ void CompactCubicSplineInterpolator::evaluate( }); } -// TODO: evluation functions are exactly the same, so put them in base class and override? +// TODO: evluation functions are exactly the same, so put them in base class and +// override? // need to figure out if this is possible with the Kokkos template void CompactCubicSplineInterpolator::evaluate( @@ -2644,9 +2642,9 @@ void ExplicitBiCubicSplineInterpolator::evaluate( LO ier = 0; auto fval_view = Rank1View(fval.data_handle() + i * ivd, ivd); - detail::bicubic_eval_explicit(xvec(i), yvec(i), iselect, fval_view, - x_, x_.extent(0), y_, - y_.extent(0), fspl, ier); + detail::bicubic_eval_explicit(xvec(i), yvec(i), iselect, fval_view, x_, + x_.extent(0), y_, y_.extent(0), fspl, + ier); }); } @@ -2677,9 +2675,8 @@ void CompactBiCubicSplineInterpolator::evaluate( LO ier = 0; auto fval_view = Rank1View(fval.data_handle() + i * ivd, ivd); - detail::bicubic_eval_compact(xvec(i), yvec(i), iselect, fval_view, - x_, x_.extent(0), y_, - y_.extent(0), fspl, ier); + detail::bicubic_eval_compact(xvec(i), yvec(i), iselect, fval_view, x_, + x_.extent(0), y_, y_.extent(0), fspl, ier); }); } @@ -2730,20 +2727,14 @@ struct InitCompactBiCubicCoeffFunctor { template ExplicitBiCubicSplineInterpolator:: ExplicitBiCubicSplineInterpolator( - Rank1View x, - Rank1View y, - Rank1View values, - BoundaryCondition ibcxmin, - Rank1View bcxmin, - BoundaryCondition ibcxmax, - Rank1View bcxmax, - BoundaryCondition ibcymin, - Rank1View bcymin, - BoundaryCondition ibcymax, - Rank1View bcymax - ) { - detail::check_grid(x); - detail::check_grid(y); + Rank1View x, Rank1View y, + Rank1View values, BoundaryCondition ibcxmin, + Rank1View bcxmin, BoundaryCondition ibcxmax, + Rank1View bcxmax, BoundaryCondition ibcymin, + Rank1View bcymin, BoundaryCondition ibcymax, + Rank1View bcymax) { + detail::grid_valid(x); + detail::grid_valid(y); x_ = x; y_ = y; @@ -2772,8 +2763,9 @@ ExplicitBiCubicSplineInterpolator:: Rank1View y, Rank1View values) : ExplicitBiCubicSplineInterpolator( - x, y, values, BoundaryCondition::NOT_A_KNOT, {}, BoundaryCondition::NOT_A_KNOT, - {}, BoundaryCondition::NOT_A_KNOT, {}, BoundaryCondition::NOT_A_KNOT, {}) { + x, y, values, BoundaryCondition::NOT_A_KNOT, {}, + BoundaryCondition::NOT_A_KNOT, {}, BoundaryCondition::NOT_A_KNOT, {}, + BoundaryCondition::NOT_A_KNOT, {}) { std::cout << "Not a knot boundary condition is applied by default" << std::endl; } @@ -2787,8 +2779,8 @@ CompactBiCubicSplineInterpolator:: Rank1View bcxmax, BoundaryCondition ibcymin, Rank1View bcymin, BoundaryCondition ibcymax, Rank1View bcymax) { - detail::check_grid(x); - detail::check_grid(y); + detail::grid_valid(x); + detail::grid_valid(y); x_ = x; y_ = y; @@ -2816,10 +2808,10 @@ CompactBiCubicSplineInterpolator:: CompactBiCubicSplineInterpolator(Rank1View x, Rank1View y, Rank1View values) - : CompactBiCubicSplineInterpolator(x, y, values, BoundaryCondition::NOT_A_KNOT, {}, - BoundaryCondition::NOT_A_KNOT, {}, - BoundaryCondition::NOT_A_KNOT, {}, - BoundaryCondition::NOT_A_KNOT, {}) { + : CompactBiCubicSplineInterpolator( + x, y, values, BoundaryCondition::NOT_A_KNOT, {}, + BoundaryCondition::NOT_A_KNOT, {}, BoundaryCondition::NOT_A_KNOT, {}, + BoundaryCondition::NOT_A_KNOT, {}) { std::cout << "Not a knot boundary condition is applied by default" << std::endl; } From 8e91a1cbf3d5a2fadc434ca4b504af46441b16a4 Mon Sep 17 00:00:00 2001 From: Sichao25 Date: Fri, 29 Aug 2025 18:35:28 -0400 Subject: [PATCH 15/18] add documentation to utilities --- src/pcms/interpolator/spline_interpolator.hpp | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/pcms/interpolator/spline_interpolator.hpp b/src/pcms/interpolator/spline_interpolator.hpp index a41320ae9..f13af36e1 100644 --- a/src/pcms/interpolator/spline_interpolator.hpp +++ b/src/pcms/interpolator/spline_interpolator.hpp @@ -23,6 +23,18 @@ T get_element_from_span(Rank1View span, LO index) { return element; } +/** \brief Check if the grid is uniformly spaced and ascending + * + * \param x input grid points + * \param ztol tolerance for uniformity check + * \return true if the grid is uniformly spaced and ascending, false otherwise + * + * \details This function checks if the input grid points are uniformly spaced + * and in ascending order. It calculates the average spacing and verifies that + * each interval between consecutive points is within a specified tolerance of + * this average spacing. The tolerance is defined as a fraction (ztol) of the + * average spacing. + */ template bool isUniformAscending(Rank1View x, T ztol) { using execution_space = typename MemorySpace::execution_space; @@ -52,6 +64,19 @@ void grid_valid(Rank1View x) { PCMS_ALWAYS_ASSERT(is_uniform_ascending); } +/** \brief Clamp xget to the grid range [x[0], x[nx-1]] with tolerance + * + * \param xget input coordinate + * \param zxget output clamped coordinate + * \param x input grid points + * \param nx number of grid points + * \param ier error flag (0 = no error, 1 = out of range) + * + * \details If xget is outside the range [x[0], x[nx-1]], then check if it is + * within a small tolerance of the range. If it is within the tolerance, then + * clamp it to the nearest boundary value. If it is outside the tolerance, then + * set the error flag ier to 1. + */ template KOKKOS_INLINE_FUNCTION void clamp_to_grid_range(T xget, T &zxget, Rank1View x, From 691ea7a0f63a49581d542ed66fd333c5bb43e4cb Mon Sep 17 00:00:00 2001 From: Sichao25 Date: Thu, 18 Sep 2025 21:18:42 -0400 Subject: [PATCH 16/18] add lookup tolerance and minor constant value update --- src/pcms/interpolator/spline_interpolator.hpp | 91 +++++++++++-------- 1 file changed, 53 insertions(+), 38 deletions(-) diff --git a/src/pcms/interpolator/spline_interpolator.hpp b/src/pcms/interpolator/spline_interpolator.hpp index f13af36e1..18aa01a8f 100644 --- a/src/pcms/interpolator/spline_interpolator.hpp +++ b/src/pcms/interpolator/spline_interpolator.hpp @@ -80,9 +80,9 @@ void grid_valid(Rank1View x) { template KOKKOS_INLINE_FUNCTION void clamp_to_grid_range(T xget, T &zxget, Rank1View x, - LO nx, LO &ier) { + LO nx, LO &ier, T tol) { if (xget < x[0] || xget > x[nx - 1]) { - T zxtol = 4.0e-7 * std::max(std::abs(x[0]), std::abs(x[nx - 1])); + T zxtol = tol * std::max(std::abs(x[0]), std::abs(x[nx - 1])); if (xget < x[0] - zxtol || xget > x[nx - 1] + zxtol) { ier = 1; // Error code for out of range @@ -621,8 +621,8 @@ KOKKOS_FUNCTION void solve_cubic_spline_explicit( Rank1View x, LO nx, Rank2View fspl, LO ibcxmin, T bcxmin, LO ibcxmax, T bcxmax, Rank1View wk) { - const T half = 0.5; - const T sixth = 0.166666666666666667; + const T half = 1.0 / 2.0; + const T sixth = 1.0 / 6.0; if (ibcxmin == 1) { fspl(1, 0) = bcxmin; @@ -708,15 +708,16 @@ KOKKOS_INLINE_FUNCTION LO lookup_in_grid(T zxget, Rank1View x, * \param i index of the grid point * \param dx displacement from the grid point * \param ier error flag, 0 if successful, non-zero otherwise + * \param lookup_tol tolerance for out-of-bound checking */ template KOKKOS_INLINE_FUNCTION void cubic_lookup_explicit(T xget, Rank1View x, LO nx, LO &i, T &dx, - LO &ier) { + LO &ier, T lookup_tol) { T zxget = xget; // Range check - clamp_to_grid_range(xget, zxget, x, nx, ier); + clamp_to_grid_range(xget, zxget, x, nx, ier, lookup_tol); i = lookup_in_grid(zxget, x, nx); @@ -732,6 +733,7 @@ cubic_lookup_explicit(T xget, Rank1View x, LO nx, LO &i, T &dx, * \param nx number of grid points * \param fspl spline coefficients * \param ier error flag, 0 if successful, non-zero otherwise + * \param lookup_tol tolerance for out-of-bound checking * * \details A static function that can be used to evaluate the cubic spline at a * single point. Note that this function does nothing when tje input point is @@ -741,10 +743,10 @@ template KOKKOS_INLINE_FUNCTION void cubic_eval_explicit(T xget, Kokkos::View iselect, Rank1View fval, Rank1View x, - LO nx, Rank2View fspl, LO &ier) { + LO nx, Rank2View fspl, LO &ier, T lookup_tol) { LO ia = 0; T dxa = 0.0; - cubic_lookup_explicit(xget, x, nx, ia, dxa, ier); + cubic_lookup_explicit(xget, x, nx, ia, dxa, ier, lookup_tol); if (ier != 0) { printf("error in evaluation, ier = %d\n", ier); return; @@ -854,14 +856,15 @@ cubic_evalfn_compact(Kokkos::View selector, * \param hx step size in the x direction * \param hxi inverse step size in the x direction * \param ier error flag, 0 if successful, non-zero otherwise + * \param lookup_tol tolerance for looking up the grid point */ template KOKKOS_INLINE_FUNCTION void cubic_lookup_compact(T xget, Rank1View x, LO nx, LO &i, - T &xparam, T &hx, T &hxi, LO &ier) { + T &xparam, T &hx, T &hxi, LO &ier, T lookup_tol) { T zxget = xget; - clamp_to_grid_range(xget, zxget, x, nx, ier); + clamp_to_grid_range(xget, zxget, x, nx, ier, lookup_tol); i = lookup_in_grid(zxget, x, nx); @@ -879,12 +882,13 @@ cubic_lookup_compact(T xget, Rank1View x, LO nx, LO &i, * \param nx number of grid points * \param fs2 compact spline coefficients * \param ier error flag, 0 if successful, non-zero otherwise + * \param lookup_tol tolerance for out-of-bound checking */ template KOKKOS_INLINE_FUNCTION void cubic_eval_compact(T xget, Kokkos::View ict, Rank1View fval, Rank1View x, - LO nx, Rank2View fspl, LO &ier) { + LO nx, Rank2View fspl, LO &ier, T lookup_tol) { // Initialize output zone info LO i = 0; @@ -893,7 +897,7 @@ cubic_eval_compact(T xget, Kokkos::View ict, T hxi = 0.0; // Find the interval containing xget - cubic_lookup_compact(xget, x, nx, i, xparam, hx, hxi, ier); + cubic_lookup_compact(xget, x, nx, i, xparam, hx, hxi, ier, lookup_tol); if (ier != 0) return; @@ -914,17 +918,18 @@ cubic_eval_compact(T xget, Kokkos::View ict, * \param dx displacement from the grid point in x direction * \param dy displacement from the grid point in y direction * \param ier error flag, 0 if successful, non-zero otherwise + * \param lookup_tol tolerance for looking up the grid point */ template KOKKOS_INLINE_FUNCTION void bicubic_lookup_explicit(T xget, T yget, Rank1View x, LO nx, Rank1View y, LO ny, LO &i, LO &j, T &dx, - T &dy, LO &ier) { + T &dy, LO &ier, T lookup_tol) { T zxget = xget; T zyget = yget; - clamp_to_grid_range(xget, zxget, x, nx, ier); - clamp_to_grid_range(yget, zyget, y, ny, ier); + clamp_to_grid_range(xget, zxget, x, nx, ier, lookup_tol); + clamp_to_grid_range(yget, zyget, y, ny, ier, lookup_tol); if (ier != 0) return; @@ -1148,6 +1153,7 @@ bicubic_evalfn_explicit(Kokkos::View ict, * \param ny number of grid points in y direction * \param fspl bicubic spline coefficients * \param ier error flag, 0 if successful, non-zero otherwise + * \param lookup_tol tolerance for looking up the grid point */ template KOKKOS_INLINE_FUNCTION void @@ -1155,14 +1161,15 @@ bicubic_eval_explicit(T xget, T yget, Kokkos::View iselect, Rank1View fval, Rank1View x, LO nx, Rank1View y, LO ny, - Rank4View fspl, LO &ier) { + Rank4View fspl, LO &ier, T lookup_tol) { LO i = 0; LO j = 0; T dx = 0.0; T dy = 0.0; // Range finding - bicubic_lookup_explicit(xget, yget, x, nx, y, ny, i, j, dx, dy, ier); + bicubic_lookup_explicit(xget, yget, x, nx, y, ny, i, + j, dx, dy, ier, lookup_tol); if (ier != 0) return; @@ -1345,7 +1352,7 @@ void solve_bicubic_spline_explicit(Rank1View x, LO inx, zhy * 3.0 * fspl(0, 3, ix, jy)); } else { bicubic_eval_explicit(x[inx - 1], y[iny - 1], iselect2, zcur, x, - inx, y, iny, fspl, ier); + inx, y, iny, fspl, ier, 4.0e-7); if (ier != 0) return; } @@ -1356,7 +1363,7 @@ void solve_bicubic_spline_explicit(Rank1View x, LO inx, 2.0 * fspl(0, 2, ix, jy) + 6.0 * zhy * fspl(0, 3, ix, jy); } else { bicubic_eval_explicit(x[inx - 1], y[iny - 1], iselect2, zcur, x, - inx, y, iny, fspl, ier); + inx, y, iny, fspl, ier, 4.0e-7); if (ier != 0) return; } @@ -1454,18 +1461,19 @@ void solve_bicubic_spline_explicit(Rank1View x, LO inx, * \param hy step size in the y direction * \param hyi inverse step size in the y direction * \param ier error flag, 0 if successful, non-zero otherwise + * \param lookup_tol tolerance for the lookup */ template KOKKOS_INLINE_FUNCTION void bicubic_lookup_compact(T xget, T yget, Rank1View x, LO nx, Rank1View y, LO ny, LO &i, LO &j, T &xparam, T &yparam, T &hx, T &hxi, T &hy, T &hyi, - LO &ier) { + LO &ier, T lookup_tol) { T zxget = xget; T zyget = yget; - clamp_to_grid_range(xget, zxget, x, nx, ier); - clamp_to_grid_range(yget, zyget, y, ny, ier); + clamp_to_grid_range(xget, zxget, x, nx, ier, lookup_tol); + clamp_to_grid_range(yget, zyget, y, ny, ier, lookup_tol); i = lookup_in_grid(zxget, x, nx); j = lookup_in_grid(zyget, y, ny); @@ -1796,13 +1804,14 @@ bicubic_evalfn_compact(Kokkos::View ict, LO ivec, LO ivecd, * \param ny number of grid points in y direction * \param f bicubic spline coefficients * \param ier error flag, 0 if successful, non-zero otherwise + * \param lookup_tol tolerance for the lookup */ template KOKKOS_INLINE_FUNCTION void bicubic_eval_compact( T xget, T yget, Kokkos::View ict, Rank1View fval, Rank1View x, LO nx, Rank1View y, LO ny, - Rank3View f, LO &ier) { + Rank3View f, LO &ier, T lookup_tol) { // Local variables LO i = 0, j = 0; T xparam = 0.0, yparam = 0.0; @@ -1811,7 +1820,7 @@ KOKKOS_INLINE_FUNCTION void bicubic_eval_compact( // Call herm2xy to locate cell and compute params bicubic_lookup_compact(xget, yget, x, nx, y, ny, i, j, xparam, yparam, hx, - hxi, hy, hyi, ier); + hxi, hy, hyi, ier, lookup_tol); if (ier != 0) return; @@ -2074,7 +2083,8 @@ template class CubicSplineInterpolator { Rank2View fval) = 0; virtual void evaluate(Kokkos::View selector, Rank1View xvec, - Rank2View fval) = 0; + Rank2View fval, + T lookup_tol) = 0; }; /** \brief ExplicitCubicSplineInterpolator class @@ -2146,6 +2156,7 @@ class ExplicitCubicSplineInterpolator * \param selector selector array indicating which derivatives to compute * \param xvec input points where the spline is evaluated * \param fval output values of the spline at given points + * \param lookup_tol tolerance for the lookup * * \details The size of fval should match the size of xvec and the size of * selector. The selector array can be used to specify which derivatives to @@ -2154,7 +2165,7 @@ class ExplicitCubicSplineInterpolator */ void evaluate(Kokkos::View selector, Rank1View xvec, - Rank2View fval) override; + Rank2View fval, T lookup_tol = 4.0e-7) override; private: Rank1View x_; @@ -2220,13 +2231,14 @@ class CompactCubicSplineInterpolator * \param selector selector array indicating which derivatives to compute * \param xvec input points where the spline is evaluated * \param fval output values of the spline at given points + * \param lookup_tol tolerance for the lookup * * \details The selector follows the same rules as in * ExplicitCubicSplineInterpolator. */ void evaluate(Kokkos::View selector, Rank1View xvec, - Rank2View fval) override; + Rank2View fval, T lookup_tol = 4.0e-7) override; private: Rank1View x_; @@ -2242,7 +2254,8 @@ template class BiCubicSplineInterpolator { virtual void evaluate(Kokkos::View selector, Rank1View xvec, Rank1View yvec, - Rank2View fval) = 0; + Rank2View fval, + T lookup_tol) = 0; }; /** \brief BiCubicSplineInterpolator class @@ -2315,6 +2328,7 @@ class ExplicitBiCubicSplineInterpolator * \param xvec input points in x direction where the spline is evaluated * \param yvec input points in y direction where the spline is evaluated * \param fval output values of the spline at given points + * \param lookup_tol tolerance for the lookup * * \details The selector follows the the following rules: * iselect(1)=1 -- evaluate f @@ -2326,7 +2340,7 @@ class ExplicitBiCubicSplineInterpolator */ void evaluate(Kokkos::View iselect, Rank1View xvec, Rank1View yvec, - Rank2View fval) override; + Rank2View fval, T lookup_tol = 4.0e-7) override; private: Rank1View x_; @@ -2413,13 +2427,14 @@ class CompactBiCubicSplineInterpolator * \param xvec input points in x direction where the spline is evaluated * \param yvec input points in y direction where the spline is evaluated * \param fval output values of the spline at given points + * \param lookup_tol tolerance for locating the interval in the grid * * \details The selector follows the same rules as in * ExplicitBiCubicSplineInterpolator. */ void evaluate(Kokkos::View iselect, Rank1View xvec, Rank1View yvec, - Rank2View fval) override; + Rank2View fval, T lookup_tol = 4.0e-7) override; private: Rank1View x_; @@ -2604,7 +2619,7 @@ CompactCubicSplineInterpolator::CompactCubicSplineInterpolator( template void ExplicitCubicSplineInterpolator::evaluate( const Kokkos::View selector, - Rank1View xvec, Rank2View fval) { + Rank1View xvec, Rank2View fval, T lookup_tol) { LO ivd = fval.extent(1); auto fspl = get_coefficients_view(); Kokkos::parallel_for( @@ -2614,7 +2629,7 @@ void ExplicitCubicSplineInterpolator::evaluate( auto fval_view = Rank1View(fval.data_handle() + i * ivd, ivd); detail::cubic_eval_explicit(xvec(i), selector, fval_view, x_, - x_.extent(0), fspl, ier); + x_.extent(0), fspl, ier, lookup_tol); }); } @@ -2628,7 +2643,7 @@ void ExplicitCubicSplineInterpolator::evaluate( template void CompactCubicSplineInterpolator::evaluate( Kokkos::View selector, Rank1View xvec, - Rank2View fval) { + Rank2View fval, T lookup_tol) { LO ivd = fval.extent(1); auto fspl = get_coefficients_view(); Kokkos::parallel_for( @@ -2638,7 +2653,7 @@ void CompactCubicSplineInterpolator::evaluate( auto fval_view = Rank1View(fval.data_handle() + i * ivd, ivd); detail::cubic_eval_compact(xvec(i), selector, fval_view, x_, - x_.extent(0), fspl, ier); + x_.extent(0), fspl, ier, lookup_tol); }); } @@ -2655,7 +2670,7 @@ void CompactCubicSplineInterpolator::evaluate( template void ExplicitBiCubicSplineInterpolator::evaluate( Kokkos::View iselect, Rank1View xvec, - Rank1View yvec, Rank2View fval) { + Rank1View yvec, Rank2View fval, T lookup_tol) { PCMS_ALWAYS_ASSERT(xvec.extent(0) == yvec.extent(0) && xvec.extent(0) == fval.extent(0)); @@ -2669,7 +2684,7 @@ void ExplicitBiCubicSplineInterpolator::evaluate( Rank1View(fval.data_handle() + i * ivd, ivd); detail::bicubic_eval_explicit(xvec(i), yvec(i), iselect, fval_view, x_, x_.extent(0), y_, y_.extent(0), fspl, - ier); + ier, lookup_tol); }); } @@ -2688,7 +2703,7 @@ void ExplicitBiCubicSplineInterpolator::evaluate( template void CompactBiCubicSplineInterpolator::evaluate( Kokkos::View iselect, Rank1View xvec, - Rank1View yvec, Rank2View fval) { + Rank1View yvec, Rank2View fval, T lookup_tol) { PCMS_ALWAYS_ASSERT(xvec.extent(0) == yvec.extent(0) && xvec.extent(0) == fval.extent(0)); @@ -2701,7 +2716,7 @@ void CompactBiCubicSplineInterpolator::evaluate( auto fval_view = Rank1View(fval.data_handle() + i * ivd, ivd); detail::bicubic_eval_compact(xvec(i), yvec(i), iselect, fval_view, x_, - x_.extent(0), y_, y_.extent(0), fspl, ier); + x_.extent(0), y_, y_.extent(0), fspl, ier, lookup_tol); }); } From 780ced42d721a4bd733163b7d877641c200c7492 Mon Sep 17 00:00:00 2001 From: Sichao25 Date: Fri, 19 Sep 2025 12:24:18 -0400 Subject: [PATCH 17/18] reformat spline interpolator --- src/pcms/interpolator/CMakeLists.txt | 3 +- src/pcms/interpolator/spline_interpolator.hpp | 1461 +++++++++-------- test/test_spline_interpolator.cpp | 310 ++-- 3 files changed, 932 insertions(+), 842 deletions(-) diff --git a/src/pcms/interpolator/CMakeLists.txt b/src/pcms/interpolator/CMakeLists.txt index 3a0df26d9..5319a4eaa 100644 --- a/src/pcms/interpolator/CMakeLists.txt +++ b/src/pcms/interpolator/CMakeLists.txt @@ -10,8 +10,7 @@ set(PCMS_FIELD_TRANSFER_HEADERS mls_interpolation.hpp pcms_interpolator_view_utils.hpp pcms_interpolator_logger.hpp - spline_interpolator.hpp -) + spline_interpolator.hpp) set(PCMS_FIELD_TRANSFER_SOURCES mls_interpolation.cpp) install(FILES ${PCMS_FIELD_TRANSFER_HEADERS} diff --git a/src/pcms/interpolator/spline_interpolator.hpp b/src/pcms/interpolator/spline_interpolator.hpp index 18aa01a8f..fb4f06e23 100644 --- a/src/pcms/interpolator/spline_interpolator.hpp +++ b/src/pcms/interpolator/spline_interpolator.hpp @@ -9,14 +9,17 @@ #include #include -namespace pcms { +namespace pcms +{ -namespace detail { +namespace detail +{ template -T get_element_from_span(Rank1View span, LO index) { +T get_element_from_span(Rank1View span, LO index) +{ T element; - Kokkos::View data_view(span.data_handle() + index, 1); + Kokkos::View data_view(span.data_handle() + index, 1); auto element_host = Kokkos::create_mirror_view(data_view); Kokkos::deep_copy(element_host, data_view); element = element_host(0); @@ -36,7 +39,8 @@ T get_element_from_span(Rank1View span, LO index) { * average spacing. */ template -bool isUniformAscending(Rank1View x, T ztol) { +bool isUniformAscending(Rank1View x, T ztol) +{ using execution_space = typename MemorySpace::execution_space; LO inx = static_cast(x.extent(0)); T dxavg = (get_element_from_span(x, inx - 1) - get_element_from_span(x, 0)) / @@ -45,20 +49,21 @@ bool isUniformAscending(Rank1View x, T ztol) { bool is_uniform_ascending = true; Kokkos::parallel_reduce( - "check_uniform_ascending", Kokkos::RangePolicy(1, inx), - KOKKOS_LAMBDA(const LO ix, bool &local_flag) { - T zdiffx = x(ix) - x(ix - 1); - T zdiff = zdiffx - dxavg; - if (zdiffx < 0.0 || std::abs(zdiff) > zeps) { - local_flag = false; - } - }, - Kokkos::LAnd(is_uniform_ascending)); + "check_uniform_ascending", Kokkos::RangePolicy(1, inx), + KOKKOS_LAMBDA(const LO ix, bool& local_flag) { + T zdiffx = x(ix) - x(ix - 1); + T zdiff = zdiffx - dxavg; + if (zdiffx < 0.0 || std::abs(zdiff) > zeps) { + local_flag = false; + } + }, + Kokkos::LAnd(is_uniform_ascending)); return is_uniform_ascending; } template -void grid_valid(Rank1View x) { +void grid_valid(Rank1View x) +{ PCMS_ALWAYS_ASSERT(x.extent(0) >= 2); bool is_uniform_ascending = isUniformAscending(x, 1.0e-3); PCMS_ALWAYS_ASSERT(is_uniform_ascending); @@ -78,9 +83,10 @@ void grid_valid(Rank1View x) { * set the error flag ier to 1. */ template -KOKKOS_INLINE_FUNCTION void clamp_to_grid_range(T xget, T &zxget, +KOKKOS_INLINE_FUNCTION void clamp_to_grid_range(T xget, T& zxget, Rank1View x, - LO nx, LO &ier, T tol) { + LO nx, LO& ier, T tol) +{ if (xget < x[0] || xget > x[nx - 1]) { T zxtol = tol * std::max(std::abs(x[0]), std::abs(x[nx - 1])); @@ -114,17 +120,18 @@ KOKKOS_INLINE_FUNCTION void clamp_to_grid_range(T xget, T &zxget, */ template void detect_inhomogeneous_bc(Rank1View bcmin, LO ibcmin, - LO &iflg2, LO nx) { + LO& iflg2, LO nx) +{ using execution_space = typename MemorySpace::execution_space; if (ibcmin == 1 || ibcmin == 2) { Kokkos::parallel_reduce( - "check_nonzero", Kokkos::RangePolicy(0, nx), - KOKKOS_LAMBDA(const LO ix, LO &local_flag) { - if (bcmin(ix) != 0.0) { - local_flag = 1; - } - }, - Kokkos::Max(iflg2)); + "check_nonzero", Kokkos::RangePolicy(0, nx), + KOKKOS_LAMBDA(const LO ix, LO& local_flag) { + if (bcmin(ix) != 0.0) { + local_flag = 1; + } + }, + Kokkos::Max(iflg2)); } } @@ -147,7 +154,8 @@ template KOKKOS_FUNCTION void compute_spline_coefficients(LO k_bc1, LO k_bcn, LO n, Rank1View x, Rank2View f, - Rank1View wk) { + Rank1View wk) +{ LO i_bc1 = k_bc1; LO i_bcn = k_bcn; @@ -255,7 +263,7 @@ KOKKOS_FUNCTION void compute_spline_coefficients(LO k_bc1, LO k_bcn, LO n, f(2, 0) = (3 * (fh - f0) / (h * h) - (2 * a1 + an) / h) * 2; // 2*c2 f(3, 0) = - (-2 * (fh - f0) / (h * h * h) + (a1 + an) / (h * h)) * 6; // 6*c1 + (-2 * (fh - f0) / (h * h * h) + (a1 + an) / (h * h)) * 6; // 6*c1 f(3, 1) = f(3, 0); f(2, 1) = f(3, 0) * h + f(2, 0); @@ -270,7 +278,7 @@ KOKKOS_FUNCTION void compute_spline_coefficients(LO k_bc1, LO k_bcn, LO n, f(2, 0) = (-bn / 4 + 3 * (fh - f0) / (2 * h * h) - 3 * a1 / (2 * h)) * 2; f(3, 0) = - (bn / (4 * h) - (fh - f0) / (2 * h * h * h) + a1 / (2 * h * h)) * 6; + (bn / (4 * h) - (fh - f0) / (2 * h * h * h) + a1 / (2 * h * h)) * 6; f(3, 1) = f(3, 0); f(1, 1) = f(3, 0) * h * h / 2 + f(2, 0) * h + a1; @@ -285,7 +293,7 @@ KOKKOS_FUNCTION void compute_spline_coefficients(LO k_bc1, LO k_bcn, LO n, f(1, 0) = 3 * (fh - f0) / (2 * h) - b1 * h / 4 - an / 2; // c3 f(3, 0) = - (an / (2 * h * h) - (fh - f0) / (2 * h * h * h) - b1 / (4 * h)) * 6; + (an / (2 * h * h) - (fh - f0) / (2 * h * h * h) - b1 / (4 * h)) * 6; f(3, 1) = f(3, 0); f(2, 1) = f(3, 0) * h + f(2, 0); @@ -537,7 +545,7 @@ KOKKOS_FUNCTION void compute_spline_coefficients(LO k_bc1, LO k_bcn, LO n, for (LO ib = 2; ib <= n - 2; ++ib) { LO i = n - ib - 2; f(2, i) = - (f(2, i) - f(3, i) * f(2, i + 1) - wk[i] * f(2, n - 2)) / f(1, i); + (f(2, i) - f(3, i) * f(2, i + 1) - wk[i] * f(2, n - 2)) / f(1, i); } f(2, n - 1) = f(2, 0); @@ -584,8 +592,8 @@ KOKKOS_FUNCTION void compute_spline_coefficients(LO k_bc1, LO k_bcn, LO n, } if (i_bcn <= 0 || i_bcn > 7) { - f(2, n - 1) = f(2, n - 2) + - (f(2, n - 2) - f(2, n - 3)) * f(3, n - 2) / f(3, n - 3); + f(2, n - 1) = + f(2, n - 2) + (f(2, n - 2) - f(2, n - 3)) * f(3, n - 2) / f(3, n - 3); } } @@ -618,8 +626,9 @@ KOKKOS_FUNCTION void compute_spline_coefficients(LO k_bc1, LO k_bcn, LO n, template KOKKOS_FUNCTION void solve_cubic_spline_explicit( - Rank1View x, LO nx, Rank2View fspl, - LO ibcxmin, T bcxmin, LO ibcxmax, T bcxmax, Rank1View wk) { + Rank1View x, LO nx, Rank2View fspl, + LO ibcxmin, T bcxmin, LO ibcxmax, T bcxmax, Rank1View wk) +{ const T half = 1.0 / 2.0; const T sixth = 1.0 / 6.0; @@ -652,10 +661,10 @@ KOKKOS_FUNCTION void solve_cubic_spline_explicit( * \param fspl spline coefficients */ template -KOKKOS_INLINE_FUNCTION void -cubic_evalfn_explicit(Kokkos::View selector, - Rank1View fval, LO i, T dx, - Rank2View fspl) { +KOKKOS_INLINE_FUNCTION void cubic_evalfn_explicit( + Kokkos::View selector, Rank1View fval, LO i, + T dx, Rank2View fspl) +{ LO iaval = 0; @@ -668,14 +677,14 @@ cubic_evalfn_explicit(Kokkos::View selector, // Evaluate f iaval++; fval(iaval - 1) = - fspl(0, i) + dx * (fspl(1, i) + dx * (fspl(2, i) + dx * fspl(3, i))); + fspl(0, i) + dx * (fspl(1, i) + dx * (fspl(2, i) + dx * fspl(3, i))); } if (selector[1] > 0) { // Evaluate df/dx iaval++; fval(iaval - 1) = - fspl(1, i) + dx * (2.0 * fspl(2, i) + dx * 3.0 * fspl(3, i)); + fspl(1, i) + dx * (2.0 * fspl(2, i) + dx * 3.0 * fspl(3, i)); } if (selector[2] > 0) { @@ -688,7 +697,8 @@ cubic_evalfn_explicit(Kokkos::View selector, template KOKKOS_INLINE_FUNCTION LO lookup_in_grid(T zxget, Rank1View x, - LO nx) { + LO nx) +{ LO nxm = nx - 1; LO ii = static_cast(nxm * (zxget - x[0]) / (x[nx - 1] - x[0])); LO i = std::min(nxm - 1, ii); @@ -711,9 +721,11 @@ KOKKOS_INLINE_FUNCTION LO lookup_in_grid(T zxget, Rank1View x, * \param lookup_tol tolerance for out-of-bound checking */ template -KOKKOS_INLINE_FUNCTION void -cubic_lookup_explicit(T xget, Rank1View x, LO nx, LO &i, T &dx, - LO &ier, T lookup_tol) { +KOKKOS_INLINE_FUNCTION void cubic_lookup_explicit(T xget, + Rank1View x, + LO nx, LO& i, T& dx, LO& ier, + T lookup_tol) +{ T zxget = xget; // Range check @@ -740,10 +752,11 @@ cubic_lookup_explicit(T xget, Rank1View x, LO nx, LO &i, T &dx, * out of the grid range (ier is set to non-zero). */ template -KOKKOS_INLINE_FUNCTION void -cubic_eval_explicit(T xget, Kokkos::View iselect, - Rank1View fval, Rank1View x, - LO nx, Rank2View fspl, LO &ier, T lookup_tol) { +KOKKOS_INLINE_FUNCTION void cubic_eval_explicit( + T xget, Kokkos::View iselect, + Rank1View fval, Rank1View x, LO nx, + Rank2View fspl, LO& ier, T lookup_tol) +{ LO ia = 0; T dxa = 0.0; cubic_lookup_explicit(xget, x, nx, ia, dxa, ier, lookup_tol); @@ -758,9 +771,10 @@ cubic_eval_explicit(T xget, Kokkos::View iselect, // TODO: take member type as parameter for further optimization template KOKKOS_FUNCTION void solve_cubic_spline_compact( - Rank1View x, LO nx, Rank2View fspl, - Rank2View fspl4, LO ibcxmin, T bcxmin, LO ibcxmax, T bcxmax, - Rank1View wk) { + Rank1View x, LO nx, Rank2View fspl, + Rank2View fspl4, LO ibcxmin, T bcxmin, LO ibcxmax, T bcxmax, + Rank1View wk) +{ // Copy f data to fspl4 and zero out second derivative output for (LO i = 0; i < nx; ++i) { fspl4(0, i) = fspl(0, i); @@ -776,7 +790,7 @@ KOKKOS_FUNCTION void solve_cubic_spline_compact( } fspl(1, nx - 1) = - 2.0 * fspl4(2, nx - 2) + (x[nx - 1] - x[nx - 2]) * 6.0 * fspl4(3, nx - 2); + 2.0 * fspl4(2, nx - 2) + (x[nx - 1] - x[nx - 2]) * 6.0 * fspl4(3, nx - 2); } /** \brief Evaluate the point given location in the grid @@ -790,10 +804,10 @@ KOKKOS_FUNCTION void solve_cubic_spline_compact( * \param fs2 compact spline coefficients */ template -KOKKOS_INLINE_FUNCTION void -cubic_evalfn_compact(Kokkos::View selector, - Rank1View fval, LO i, T xparam, T hx, - T hxi, Rank2View fs2) { +KOKKOS_INLINE_FUNCTION void cubic_evalfn_compact( + Kokkos::View selector, Rank1View fval, LO i, + T xparam, T hx, T hxi, Rank2View fs2) +{ const T sixth = 1.0 / 6.0; LO iadr = 0; @@ -859,9 +873,11 @@ cubic_evalfn_compact(Kokkos::View selector, * \param lookup_tol tolerance for looking up the grid point */ template -KOKKOS_INLINE_FUNCTION void -cubic_lookup_compact(T xget, Rank1View x, LO nx, LO &i, - T &xparam, T &hx, T &hxi, LO &ier, T lookup_tol) { +KOKKOS_INLINE_FUNCTION void cubic_lookup_compact(T xget, + Rank1View x, + LO nx, LO& i, T& xparam, T& hx, + T& hxi, LO& ier, T lookup_tol) +{ T zxget = xget; clamp_to_grid_range(xget, zxget, x, nx, ier, lookup_tol); @@ -885,10 +901,11 @@ cubic_lookup_compact(T xget, Rank1View x, LO nx, LO &i, * \param lookup_tol tolerance for out-of-bound checking */ template -KOKKOS_INLINE_FUNCTION void -cubic_eval_compact(T xget, Kokkos::View ict, - Rank1View fval, Rank1View x, - LO nx, Rank2View fspl, LO &ier, T lookup_tol) { +KOKKOS_INLINE_FUNCTION void cubic_eval_compact( + T xget, Kokkos::View ict, Rank1View fval, + Rank1View x, LO nx, Rank2View fspl, LO& ier, + T lookup_tol) +{ // Initialize output zone info LO i = 0; @@ -921,10 +938,11 @@ cubic_eval_compact(T xget, Kokkos::View ict, * \param lookup_tol tolerance for looking up the grid point */ template -KOKKOS_INLINE_FUNCTION void -bicubic_lookup_explicit(T xget, T yget, Rank1View x, LO nx, - Rank1View y, LO ny, LO &i, LO &j, T &dx, - T &dy, LO &ier, T lookup_tol) { +KOKKOS_INLINE_FUNCTION void bicubic_lookup_explicit( + T xget, T yget, Rank1View x, LO nx, + Rank1View y, LO ny, LO& i, LO& j, T& dx, T& dy, LO& ier, + T lookup_tol) +{ T zxget = xget; T zyget = yget; @@ -952,148 +970,147 @@ bicubic_lookup_explicit(T xget, T yget, Rank1View x, LO nx, * \param fspl bicubic spline coefficients */ template -KOKKOS_INLINE_FUNCTION void -bicubic_evalfn_explicit(Kokkos::View ict, - Rank1View fval, LO i, LO j, T dx, T dy, - Rank4View fspl) { +KOKKOS_INLINE_FUNCTION void bicubic_evalfn_explicit( + Kokkos::View ict, Rank1View fval, LO i, + LO j, T dx, T dy, Rank4View fspl) +{ LO iaval = 0; // Index for fval if (ict[0] <= 2) { if ((ict[0] > 0) || (ict[0] == -1)) { // Evaluate f iaval++; fval(iaval - 1) = - fspl(0, 0, i, j) + - dy * (fspl(0, 1, i, j) + - dy * (fspl(0, 2, i, j) + dy * fspl(0, 3, i, j))) + - dx * (fspl(1, 0, i, j) + - dy * (fspl(1, 1, i, j) + - dy * (fspl(1, 2, i, j) + dy * fspl(1, 3, i, j))) + - dx * (fspl(2, 0, i, j) + - dy * (fspl(2, 1, i, j) + - dy * (fspl(2, 2, i, j) + dy * fspl(2, 3, i, j))) + - dx * (fspl(3, 0, i, j) + - dy * (fspl(3, 1, i, j) + - dy * (fspl(3, 2, i, j) + - dy * fspl(3, 3, i, j)))))); + fspl(0, 0, i, j) + + dy * + (fspl(0, 1, i, j) + dy * (fspl(0, 2, i, j) + dy * fspl(0, 3, i, j))) + + dx * + (fspl(1, 0, i, j) + + dy * (fspl(1, 1, i, j) + + dy * (fspl(1, 2, i, j) + dy * fspl(1, 3, i, j))) + + dx * + (fspl(2, 0, i, j) + + dy * (fspl(2, 1, i, j) + + dy * (fspl(2, 2, i, j) + dy * fspl(2, 3, i, j))) + + dx * (fspl(3, 0, i, j) + + dy * (fspl(3, 1, i, j) + + dy * (fspl(3, 2, i, j) + dy * fspl(3, 3, i, j)))))); } if ((ict[1] > 0) && (ict[0] != -1)) { // Evaluate df/dx iaval++; fval(iaval - 1) = - fspl(1, 0, i, j) + - dy * (fspl(1, 1, i, j) + - dy * (fspl(1, 2, i, j) + dy * fspl(1, 3, i, j))) + - 2.0 * dx * - (fspl(2, 0, i, j) + - dy * (fspl(2, 1, i, j) + - dy * (fspl(2, 2, i, j) + dy * fspl(2, 3, i, j))) + - 1.5 * dx * - (fspl(3, 0, i, j) + - dy * (fspl(3, 1, i, j) + - dy * (fspl(3, 2, i, j) + dy * fspl(3, 3, i, j))))); + fspl(1, 0, i, j) + + dy * + (fspl(1, 1, i, j) + dy * (fspl(1, 2, i, j) + dy * fspl(1, 3, i, j))) + + 2.0 * dx * + (fspl(2, 0, i, j) + + dy * (fspl(2, 1, i, j) + + dy * (fspl(2, 2, i, j) + dy * fspl(2, 3, i, j))) + + 1.5 * dx * + (fspl(3, 0, i, j) + + dy * (fspl(3, 1, i, j) + + dy * (fspl(3, 2, i, j) + dy * fspl(3, 3, i, j))))); } if ((ict[2] > 0) && (ict[0] != -1)) { // Evaluate df/dy iaval++; fval(iaval - 1) = - fspl(0, 1, i, j) + - dy * (2.0 * fspl(0, 2, i, j) + dy * 3.0 * fspl(0, 3, i, j)) + - dx * (fspl(1, 1, i, j) + - dy * (2.0 * fspl(1, 2, i, j) + dy * 3.0 * fspl(1, 3, i, j)) + - dx * (fspl(2, 1, i, j) + - dy * (2.0 * fspl(2, 2, i, j) + - dy * 3.0 * fspl(2, 3, i, j)) + - dx * (fspl(3, 1, i, j) + - dy * (2.0 * fspl(3, 2, i, j) + - dy * 3.0 * fspl(3, 3, i, j))))); + fspl(0, 1, i, j) + + dy * (2.0 * fspl(0, 2, i, j) + dy * 3.0 * fspl(0, 3, i, j)) + + dx * + (fspl(1, 1, i, j) + + dy * (2.0 * fspl(1, 2, i, j) + dy * 3.0 * fspl(1, 3, i, j)) + + dx * (fspl(2, 1, i, j) + + dy * (2.0 * fspl(2, 2, i, j) + dy * 3.0 * fspl(2, 3, i, j)) + + dx * (fspl(3, 1, i, j) + dy * (2.0 * fspl(3, 2, i, j) + + dy * 3.0 * fspl(3, 3, i, j))))); } if ((ict[3] > 0) || (ict[0] == -1)) { // Evaluate d2f/dx2 iaval++; fval(iaval - 1) = - 2.0 * (fspl(2, 0, i, j) + - dy * (fspl(2, 1, i, j) + - dy * (fspl(2, 2, i, j) + dy * fspl(2, 3, i, j)))) + - 6.0 * dx * - (fspl(3, 0, i, j) + - dy * (fspl(3, 1, i, j) + - dy * (fspl(3, 2, i, j) + dy * fspl(3, 3, i, j)))); + 2.0 * (fspl(2, 0, i, j) + + dy * (fspl(2, 1, i, j) + + dy * (fspl(2, 2, i, j) + dy * fspl(2, 3, i, j)))) + + 6.0 * dx * + (fspl(3, 0, i, j) + + dy * (fspl(3, 1, i, j) + + dy * (fspl(3, 2, i, j) + dy * fspl(3, 3, i, j)))); } if ((ict[4] > 0) || (ict[0] == -1)) { // Evaluate d2f/dy2 iaval++; fval(iaval - 1) = - 2.0 * fspl(0, 2, i, j) + 6.0 * dy * fspl(0, 3, i, j) + - dx * (2.0 * fspl(1, 2, i, j) + 6.0 * dy * fspl(1, 3, i, j) + - dx * (2.0 * fspl(2, 2, i, j) + 6.0 * dy * fspl(2, 3, i, j) + - dx * (2.0 * fspl(3, 2, i, j) + - 6.0 * dy * fspl(3, 3, i, j)))); + 2.0 * fspl(0, 2, i, j) + 6.0 * dy * fspl(0, 3, i, j) + + dx * + (2.0 * fspl(1, 2, i, j) + 6.0 * dy * fspl(1, 3, i, j) + + dx * (2.0 * fspl(2, 2, i, j) + 6.0 * dy * fspl(2, 3, i, j) + + dx * (2.0 * fspl(3, 2, i, j) + 6.0 * dy * fspl(3, 3, i, j)))); } if ((ict[5] > 0) && (ict[0] != -1)) { // Evaluate d2f/dxdy iaval++; fval(iaval - 1) = - fspl(1, 1, i, j) + - dy * (2.0 * fspl(1, 2, i, j) + dy * 3.0 * fspl(1, 3, i, j)) + - 2.0 * dx * - (fspl(2, 1, i, j) + - dy * (2.0 * fspl(2, 2, i, j) + dy * 3.0 * fspl(2, 3, i, j)) + - 1.5 * dx * - (fspl(3, 1, i, j) + dy * (2.0 * fspl(3, 2, i, j) + - dy * 3.0 * fspl(3, 3, i, j)))); + fspl(1, 1, i, j) + + dy * (2.0 * fspl(1, 2, i, j) + dy * 3.0 * fspl(1, 3, i, j)) + + 2.0 * dx * + (fspl(2, 1, i, j) + + dy * (2.0 * fspl(2, 2, i, j) + dy * 3.0 * fspl(2, 3, i, j)) + + 1.5 * dx * + (fspl(3, 1, i, j) + + dy * (2.0 * fspl(3, 2, i, j) + dy * 3.0 * fspl(3, 3, i, j)))); } if (ict[0] == -1) { // Evaluate d4f/dx2dy2 iaval++; fval(iaval - 1) = - 4.0 * fspl(2, 2, i, j) + 12.0 * dy * fspl(2, 3, i, j) + - dx * (12.0 * fspl(3, 2, i, j) + 36.0 * dy * fspl(3, 3, i, j)); + 4.0 * fspl(2, 2, i, j) + 12.0 * dy * fspl(2, 3, i, j) + + dx * (12.0 * fspl(3, 2, i, j) + 36.0 * dy * fspl(3, 3, i, j)); } } else if (ict[0] == 3) { if (ict[1] == 1) { // d³f/dx³ (not continuous) iaval++; fval(iaval - 1) = - 6.0 * (fspl(3, 0, i, j) + - dy * (fspl(3, 1, i, j) + - dy * (fspl(3, 2, i, j) + dy * fspl(3, 3, i, j)))); + 6.0 * (fspl(3, 0, i, j) + + dy * (fspl(3, 1, i, j) + + dy * (fspl(3, 2, i, j) + dy * fspl(3, 3, i, j)))); } if (ict[2] == 1) { // d³f/dx²dy iaval++; fval(iaval - 1) = - 2.0 * (fspl(2, 1, i, j) + - dy * (2.0 * fspl(2, 2, i, j) + dy * 3.0 * fspl(2, 3, i, j))) + - 6.0 * dx * - (fspl(3, 1, i, j) + - dy * (2.0 * fspl(3, 2, i, j) + dy * 3.0 * fspl(3, 3, i, j))); + 2.0 * (fspl(2, 1, i, j) + + dy * (2.0 * fspl(2, 2, i, j) + dy * 3.0 * fspl(2, 3, i, j))) + + 6.0 * dx * + (fspl(3, 1, i, j) + + dy * (2.0 * fspl(3, 2, i, j) + dy * 3.0 * fspl(3, 3, i, j))); } if (ict[3] == 1) { // d³f/dxdy² iaval++; fval(iaval - 1) = - 2.0 * fspl(1, 2, i, j) + 6.0 * dy * fspl(1, 3, i, j) + - 2.0 * dx * - (2.0 * fspl(2, 2, i, j) + 6.0 * dy * fspl(2, 3, i, j) + - 1.5 * dx * - (2.0 * fspl(3, 2, i, j) + 6.0 * dy * fspl(3, 3, i, j))); + 2.0 * fspl(1, 2, i, j) + 6.0 * dy * fspl(1, 3, i, j) + + 2.0 * dx * + (2.0 * fspl(2, 2, i, j) + 6.0 * dy * fspl(2, 3, i, j) + + 1.5 * dx * (2.0 * fspl(3, 2, i, j) + 6.0 * dy * fspl(3, 3, i, j))); } if (ict[4] == 1) { // d³f/dy³ (not continuous) iaval++; fval(iaval - 1) = - 6.0 * (fspl(0, 3, i, j) + - dx * (fspl(1, 3, i, j) + - dx * (fspl(2, 3, i, j) + dx * fspl(3, 3, i, j)))); + 6.0 * (fspl(0, 3, i, j) + + dx * (fspl(1, 3, i, j) + + dx * (fspl(2, 3, i, j) + dx * fspl(3, 3, i, j)))); } } else if (ict[0] == 4) { @@ -1101,24 +1118,24 @@ bicubic_evalfn_explicit(Kokkos::View ict, // d⁴f/dx³dy iaval++; fval(iaval - 1) = - 6.0 * (fspl(3, 1, i, j) + - dy * 2.0 * (fspl(3, 2, i, j) + dy * 1.5 * fspl(3, 3, i, j))); + 6.0 * (fspl(3, 1, i, j) + + dy * 2.0 * (fspl(3, 2, i, j) + dy * 1.5 * fspl(3, 3, i, j))); } if (ict[2] == 1) { // d⁴f/dx²dy² iaval++; fval(iaval - 1) = - 4.0 * fspl(2, 2, i, j) + 12.0 * dy * fspl(2, 3, i, j) + - dx * (12.0 * fspl(3, 2, i, j) + 36.0 * dy * fspl(3, 3, i, j)); + 4.0 * fspl(2, 2, i, j) + 12.0 * dy * fspl(2, 3, i, j) + + dx * (12.0 * fspl(3, 2, i, j) + 36.0 * dy * fspl(3, 3, i, j)); } if (ict[3] == 1) { // d⁴f/dxdy³ (not continuous) iaval++; fval(iaval - 1) = - 6.0 * (fspl(1, 3, i, j) + - 2.0 * dx * (fspl(2, 3, i, j) + 1.5 * dx * fspl(3, 3, i, j))); + 6.0 * (fspl(1, 3, i, j) + + 2.0 * dx * (fspl(2, 3, i, j) + 1.5 * dx * fspl(3, 3, i, j))); } } else if (ict[0] == 5) { @@ -1156,20 +1173,20 @@ bicubic_evalfn_explicit(Kokkos::View ict, * \param lookup_tol tolerance for looking up the grid point */ template -KOKKOS_INLINE_FUNCTION void -bicubic_eval_explicit(T xget, T yget, Kokkos::View iselect, - Rank1View fval, - Rank1View x, LO nx, - Rank1View y, LO ny, - Rank4View fspl, LO &ier, T lookup_tol) { +KOKKOS_INLINE_FUNCTION void bicubic_eval_explicit( + T xget, T yget, Kokkos::View iselect, + Rank1View fval, Rank1View x, LO nx, + Rank1View y, LO ny, Rank4View fspl, LO& ier, + T lookup_tol) +{ LO i = 0; LO j = 0; T dx = 0.0; T dy = 0.0; // Range finding - bicubic_lookup_explicit(xget, yget, x, nx, y, ny, i, - j, dx, dy, ier, lookup_tol); + bicubic_lookup_explicit(xget, yget, x, nx, y, ny, i, j, dx, dy, ier, + lookup_tol); if (ier != 0) return; @@ -1185,7 +1202,8 @@ void solve_bicubic_spline_explicit(Rank1View x, LO inx, Rank1View bcxmax, LO ibcymin, Rank1View bcymin, LO ibcymax, Rank1View bcymax, - Rank1View wk) { + Rank1View wk) +{ using execution_space = typename MemorySpace::execution_space; using member_type = typename Kokkos::TeamPolicy::member_type; @@ -1199,98 +1217,98 @@ void solve_bicubic_spline_explicit(Rank1View x, LO inx, const T xo6 = 1.0 / 6.0; auto fspl_l_x = - Rank2View(wk.data_handle() + 4 * inx * iny, 4 * inx, iny); - auto wk_l = Rank1View(wk.data_handle() + 2 * 4 * inx * iny, - inx * iny); + Rank2View(wk.data_handle() + 4 * inx * iny, 4 * inx, iny); + auto wk_l = + Rank1View(wk.data_handle() + 2 * 4 * inx * iny, inx * iny); auto fspl_l_y = Rank2View(wk.data_handle(), 4 * inx, iny); Kokkos::parallel_for( - Kokkos::TeamPolicy(iny, Kokkos::AUTO), - KOKKOS_LAMBDA(const member_type &team) { - const LO iy = team.league_rank(); + Kokkos::TeamPolicy(iny, Kokkos::AUTO), + KOKKOS_LAMBDA(const member_type& team) { + const LO iy = team.league_rank(); - auto fspl_x_view = Rank2View( - fspl_l_x.data_handle() + 4 * inx * iy, 4, inx); - auto wk_x_view = - Rank1View(wk_l.data_handle() + iy * inx, inx); + auto fspl_x_view = Rank2View( + fspl_l_x.data_handle() + 4 * inx * iy, 4, inx); + auto wk_x_view = + Rank1View(wk_l.data_handle() + iy * inx, inx); - Kokkos::parallel_for(Kokkos::TeamThreadRange(team, inx), [=](LO ix) { - fspl_x_view(0, ix) = fspl(0, 0, ix, iy); - }); + Kokkos::parallel_for(Kokkos::TeamThreadRange(team, inx), [=](LO ix) { + fspl_x_view(0, ix) = fspl(0, 0, ix, iy); + }); - if (team.team_rank() == 0) { - if (ibcxmin == 1) - fspl_x_view(1, 0) = bcxmin[iy]; - else if (ibcxmin == 2) - fspl_x_view(2, 0) = bcxmin[iy]; - - if (ibcxmax == 1) - fspl_x_view(1, inx - 1) = bcxmax[iy]; - else if (ibcxmax == 2) - fspl_x_view(2, inx - 1) = bcxmax[iy]; - - compute_spline_coefficients(ibcxmin, ibcxmax, inx, x, - fspl_x_view, wk_x_view); - } + if (team.team_rank() == 0) { + if (ibcxmin == 1) + fspl_x_view(1, 0) = bcxmin[iy]; + else if (ibcxmin == 2) + fspl_x_view(2, 0) = bcxmin[iy]; - Kokkos::parallel_for(Kokkos::TeamThreadRange(team, inx), [=](LO ix) { - fspl(1, 0, ix, iy) = fspl_x_view(1, ix); - fspl(2, 0, ix, iy) = fspl_x_view(2, ix) * xo2; - fspl(3, 0, ix, iy) = fspl_x_view(3, ix) * xo6; - }); + if (ibcxmax == 1) + fspl_x_view(1, inx - 1) = bcxmax[iy]; + else if (ibcxmax == 2) + fspl_x_view(2, inx - 1) = bcxmax[iy]; + + compute_spline_coefficients(ibcxmin, ibcxmax, inx, x, + fspl_x_view, wk_x_view); + } + + Kokkos::parallel_for(Kokkos::TeamThreadRange(team, inx), [=](LO ix) { + fspl(1, 0, ix, iy) = fspl_x_view(1, ix); + fspl(2, 0, ix, iy) = fspl_x_view(2, ix) * xo2; + fspl(3, 0, ix, iy) = fspl_x_view(3, ix) * xo6; }); + }); Kokkos::parallel_for( - Kokkos::TeamPolicy(inx, Kokkos::AUTO), - KOKKOS_LAMBDA(const member_type &team) { - const LO ix = team.league_rank(); - - auto fspl_y_view = Rank2View( - fspl_l_y.data_handle() + 4 * ix * iny, 4, iny); - auto wk_y_view = - Rank1View(wk_l.data_handle() + ix * iny, iny); + Kokkos::TeamPolicy(inx, Kokkos::AUTO), + KOKKOS_LAMBDA(const member_type& team) { + const LO ix = team.league_rank(); + + auto fspl_y_view = Rank2View( + fspl_l_y.data_handle() + 4 * ix * iny, 4, iny); + auto wk_y_view = + Rank1View(wk_l.data_handle() + ix * iny, iny); + + for (LO ic = 0; ic < 4; ++ic) { + Kokkos::parallel_for(Kokkos::TeamThreadRange(team, iny), [=](LO iy) { + fspl_y_view(0, iy) = fspl(ic, 0, ix, iy); + }); - for (LO ic = 0; ic < 4; ++ic) { - Kokkos::parallel_for(Kokkos::TeamThreadRange(team, iny), [=](LO iy) { - fspl_y_view(0, iy) = fspl(ic, 0, ix, iy); - }); + // Set linear BCs initially + if (team.team_rank() == 0) { + fspl_y_view(1, 0) = 0.0; + fspl_y_view(2, 0) = 0.0; + fspl_y_view(1, iny - 1) = 0.0; + fspl_y_view(2, iny - 1) = 0.0; - // Set linear BCs initially - if (team.team_rank() == 0) { - fspl_y_view(1, 0) = 0.0; - fspl_y_view(2, 0) = 0.0; - fspl_y_view(1, iny - 1) = 0.0; - fspl_y_view(2, iny - 1) = 0.0; - - LO ibcymina = ibcymin; - LO ibcymaxa = ibcymax; - if (iflg2 == 1) { - if (ibcymin == 1 || ibcymin == 2) - ibcymina = 0; - if (ibcymax == 1 || ibcymax == 2) - ibcymaxa = 0; - } - - compute_spline_coefficients( - ibcymina, ibcymaxa, iny, y, fspl_y_view, wk_y_view); + LO ibcymina = ibcymin; + LO ibcymaxa = ibcymax; + if (iflg2 == 1) { + if (ibcymin == 1 || ibcymin == 2) + ibcymina = 0; + if (ibcymax == 1 || ibcymax == 2) + ibcymaxa = 0; } - Kokkos::parallel_for(Kokkos::TeamThreadRange(team, iny), [=](LO iy) { - fspl(ic, 1, ix, iy) = fspl_y_view(1, iy); - fspl(ic, 2, ix, iy) = fspl_y_view(2, iy) * xo2; - fspl(ic, 3, ix, iy) = fspl_y_view(3, iy) * xo6; - }); + compute_spline_coefficients( + ibcymina, ibcymaxa, iny, y, fspl_y_view, wk_y_view); } - }); + + Kokkos::parallel_for(Kokkos::TeamThreadRange(team, iny), [=](LO iy) { + fspl(ic, 1, ix, iy) = fspl_y_view(1, iy); + fspl(ic, 2, ix, iy) = fspl_y_view(2, iy) * xo2; + fspl(ic, 3, ix, iy) = fspl_y_view(3, iy) * xo6; + }); + } + }); if (iflg2 == 1) { LO iasc = 0; // Workspace base for correction splines LO iinc = 4 * iny; // Spacing between correction splines T zhxn = - get_element_from_span(x, inx - 1) - get_element_from_span(x, inx - 2); + get_element_from_span(x, inx - 1) - get_element_from_span(x, inx - 2); T zhy = - get_element_from_span(y, iny - 1) - get_element_from_span(y, iny - 2); + get_element_from_span(y, iny - 1) - get_element_from_span(y, iny - 2); LO jx = inx - 2; LO jy = iny - 2; @@ -1305,142 +1323,140 @@ void solve_bicubic_spline_explicit(Rank1View x, LO inx, iselect2_arr[2] = 1; if (ibcymax == 2) iselect2_arr[4] = 1; - Kokkos::View iselect1("iselect1", 10); + Kokkos::View iselect1("iselect1", 10); Kokkos::parallel_for( - Kokkos::RangePolicy(0, iselect1.size()), - KOKKOS_LAMBDA(const LO i) { iselect1(i) = iselect1_arr[i]; }); - Kokkos::View iselect2("iselect2", 10); + Kokkos::RangePolicy(0, iselect1.size()), + KOKKOS_LAMBDA(const LO i) { iselect1(i) = iselect1_arr[i]; }); + Kokkos::View iselect2("iselect2", 10); Kokkos::parallel_for( - Kokkos::RangePolicy(0, iselect2.size()), - KOKKOS_LAMBDA(const LO i) { iselect2(i) = iselect2_arr[i]; }); + Kokkos::RangePolicy(0, iselect2.size()), + KOKKOS_LAMBDA(const LO i) { iselect2(i) = iselect2_arr[i]; }); auto zcur_shared = - Rank1View(fspl_l_x.data_handle(), inx * 3); + Rank1View(fspl_l_x.data_handle(), inx * 3); Kokkos::parallel_for( - Kokkos::RangePolicy(0, inx), - KOKKOS_LAMBDA(const LO ix) { - LO ier = 0; - auto zcur = - Rank1View(zcur_shared.data_handle() + ix * 3, 3); - T zdiff1 = 0.0, zdiff2 = 0.0; - auto wk_y = Rank1View(wk_l.data_handle(), iny); - - if (ibcymin == 1) { - zcur[0] = (ix < inx - 1) - ? fspl(0, 1, ix, 0) - : fspl(0, 1, jx, 0) + - zhxn * (fspl(1, 1, jx, 0) + - zhxn * (fspl(2, 1, jx, 0) + - zhxn * fspl(3, 1, jx, 0))); - zdiff1 = bcymin[ix] - zcur[0]; - } else if (ibcymin == 2) { - zcur[0] = (ix < inx - 1) - ? 2.0 * fspl(0, 2, ix, 0) - : 2.0 * (fspl(0, 2, jx, 0) + - zhxn * (fspl(1, 2, jx, 0) + - zhxn * (fspl(2, 2, jx, 0) + - zhxn * fspl(3, 2, jx, 0)))); - zdiff1 = bcymin[ix] - zcur[0]; - } + Kokkos::RangePolicy(0, inx), KOKKOS_LAMBDA(const LO ix) { + LO ier = 0; + auto zcur = + Rank1View(zcur_shared.data_handle() + ix * 3, 3); + T zdiff1 = 0.0, zdiff2 = 0.0; + auto wk_y = Rank1View(wk_l.data_handle(), iny); + + if (ibcymin == 1) { + zcur[0] = + (ix < inx - 1) + ? fspl(0, 1, ix, 0) + : fspl(0, 1, jx, 0) + zhxn * (fspl(1, 1, jx, 0) + + zhxn * (fspl(2, 1, jx, 0) + + zhxn * fspl(3, 1, jx, 0))); + zdiff1 = bcymin[ix] - zcur[0]; + } else if (ibcymin == 2) { + zcur[0] = (ix < inx - 1) + ? 2.0 * fspl(0, 2, ix, 0) + : 2.0 * (fspl(0, 2, jx, 0) + + zhxn * (fspl(1, 2, jx, 0) + + zhxn * (fspl(2, 2, jx, 0) + + zhxn * fspl(3, 2, jx, 0)))); + zdiff1 = bcymin[ix] - zcur[0]; + } - // auto zcur = Rank1View(zcur_vec.data(), 3); - if (ibcymax == 1) { - if (ix < inx - 1) { - zcur(0) = - fspl(0, 1, ix, jy) + zhy * (2.0 * fspl(0, 2, ix, jy) + - zhy * 3.0 * fspl(0, 3, ix, jy)); - } else { - bicubic_eval_explicit(x[inx - 1], y[iny - 1], iselect2, zcur, x, - inx, y, iny, fspl, ier, 4.0e-7); - if (ier != 0) - return; - } - zdiff2 = bcymax[ix] - zcur(0); - } else if (ibcymax == 2) { - if (ix < inx - 1) { - zcur(0) = - 2.0 * fspl(0, 2, ix, jy) + 6.0 * zhy * fspl(0, 3, ix, jy); - } else { - bicubic_eval_explicit(x[inx - 1], y[iny - 1], iselect2, zcur, x, - inx, y, iny, fspl, ier, 4.0e-7); - if (ier != 0) - return; - } - zdiff2 = bcymax[ix] - zcur(0); + // auto zcur = Rank1View(zcur_vec.data(), 3); + if (ibcymax == 1) { + if (ix < inx - 1) { + zcur(0) = + fspl(0, 1, ix, jy) + + zhy * (2.0 * fspl(0, 2, ix, jy) + zhy * 3.0 * fspl(0, 3, ix, jy)); + } else { + bicubic_eval_explicit(x[inx - 1], y[iny - 1], iselect2, zcur, x, + inx, y, iny, fspl, ier, 4.0e-7); + if (ier != 0) + return; } + zdiff2 = bcymax[ix] - zcur(0); + } else if (ibcymax == 2) { + if (ix < inx - 1) { + zcur(0) = 2.0 * fspl(0, 2, ix, jy) + 6.0 * zhy * fspl(0, 3, ix, jy); + } else { + bicubic_eval_explicit(x[inx - 1], y[iny - 1], iselect2, zcur, x, + inx, y, iny, fspl, ier, 4.0e-7); + if (ier != 0) + return; + } + zdiff2 = bcymax[ix] - zcur(0); + } - LO iadr = iasc + ix * iinc; - for (LO iy = 0; iy < iny; ++iy) - fspl_l_y(ix * 4, iy) = 0.0; + LO iadr = iasc + ix * iinc; + for (LO iy = 0; iy < iny; ++iy) + fspl_l_y(ix * 4, iy) = 0.0; - fspl_l_y(1 + ix * 4, 0) = 0.0; - fspl_l_y(2 + ix * 4, 0) = 0.0; - fspl_l_y(1 + ix * 4, iny - 1) = 0.0; - fspl_l_y(2 + ix * 4, iny - 1) = 0.0; + fspl_l_y(1 + ix * 4, 0) = 0.0; + fspl_l_y(2 + ix * 4, 0) = 0.0; + fspl_l_y(1 + ix * 4, iny - 1) = 0.0; + fspl_l_y(2 + ix * 4, iny - 1) = 0.0; - if (ibcymin == 1) - fspl_l_y(1 + ix * 4, 0) = zdiff1; - else if (ibcymin == 2) - fspl_l_y(2 + ix * 4, 0) = zdiff1; + if (ibcymin == 1) + fspl_l_y(1 + ix * 4, 0) = zdiff1; + else if (ibcymin == 2) + fspl_l_y(2 + ix * 4, 0) = zdiff1; - if (ibcymax == 1) - fspl_l_y(1 + ix * 4, iny - 1) = zdiff2; - else if (ibcymax == 2) - fspl_l_y(2 + ix * 4, iny - 1) = zdiff2; + if (ibcymax == 1) + fspl_l_y(1 + ix * 4, iny - 1) = zdiff2; + else if (ibcymax == 2) + fspl_l_y(2 + ix * 4, iny - 1) = zdiff2; - auto fspl_s_y = - Rank2View(fspl_l_y.data_handle() + iadr, 4, iny); - compute_spline_coefficients(ibcymin, ibcymax, iny, y, fspl_s_y, wk_y); - }); + auto fspl_s_y = + Rank2View(fspl_l_y.data_handle() + iadr, 4, iny); + compute_spline_coefficients(ibcymin, ibcymax, iny, y, fspl_s_y, wk_y); + }); Kokkos::parallel_for( - Kokkos::MDRangePolicy>({0, 0}, {inx, iny - 1}), - KOKKOS_LAMBDA(const LO ix, const LO iy) { - // Multiply local coefficients - fspl_l_y(2 + ix * 4, iy) *= xo2; - fspl_l_y(3 + ix * 4, iy) *= xo6; - - // Conditional accumulation LOo global fspl - if (ix < inx - 1) { - fspl(0, 1, ix, iy) += fspl_l_y(1 + ix * 4, iy); - fspl(0, 2, ix, iy) += fspl_l_y(2 + ix * 4, iy); - fspl(0, 3, ix, iy) += fspl_l_y(3 + ix * 4, iy); - } - }); + Kokkos::MDRangePolicy>({0, 0}, {inx, iny - 1}), + KOKKOS_LAMBDA(const LO ix, const LO iy) { + // Multiply local coefficients + fspl_l_y(2 + ix * 4, iy) *= xo2; + fspl_l_y(3 + ix * 4, iy) *= xo6; + + // Conditional accumulation LOo global fspl + if (ix < inx - 1) { + fspl(0, 1, ix, iy) += fspl_l_y(1 + ix * 4, iy); + fspl(0, 2, ix, iy) += fspl_l_y(2 + ix * 4, iy); + fspl(0, 3, ix, iy) += fspl_l_y(3 + ix * 4, iy); + } + }); Kokkos::parallel_for( - Kokkos::TeamPolicy(iny - 1, Kokkos::AUTO), - KOKKOS_LAMBDA(const member_type &team) { - const LO iy = team.league_rank(); - - auto fspl_x_view = Rank2View( - fspl_l_x.data_handle() + 4 * inx * iy, 4, inx); - auto wk_x_view = - Rank1View(wk_l.data_handle() + iy * inx, inx); - - for (LO ic = 1; ic < 4; ++ic) { - Kokkos::parallel_for( - Kokkos::TeamThreadRange(team, inx), - [=](LO ix) { fspl_x_view(0, ix) = fspl_l_y(ic + ix * 4, iy); }); - - if (team.team_rank() == 0) { - fspl_x_view(1, 0) = 0.0; - fspl_x_view(2, 0) = 0.0; - fspl_x_view(1, inx - 1) = 0.0; - fspl_x_view(2, inx - 1) = 0.0; - - compute_spline_coefficients(ibcxmin, ibcxmax, inx, x, fspl_x_view, - wk_x_view); - } - - Kokkos::parallel_for( - Kokkos::TeamThreadRange(team, inx - 1), [=](LO ix) { - fspl(1, ic, ix, iy) += fspl_x_view(1, ix); - fspl(2, ic, ix, iy) += fspl_x_view(2, ix) * xo2; - fspl(3, ic, ix, iy) += fspl_x_view(3, ix) * xo6; - }); + Kokkos::TeamPolicy(iny - 1, Kokkos::AUTO), + KOKKOS_LAMBDA(const member_type& team) { + const LO iy = team.league_rank(); + + auto fspl_x_view = Rank2View( + fspl_l_x.data_handle() + 4 * inx * iy, 4, inx); + auto wk_x_view = + Rank1View(wk_l.data_handle() + iy * inx, inx); + + for (LO ic = 1; ic < 4; ++ic) { + Kokkos::parallel_for(Kokkos::TeamThreadRange(team, inx), [=](LO ix) { + fspl_x_view(0, ix) = fspl_l_y(ic + ix * 4, iy); + }); + + if (team.team_rank() == 0) { + fspl_x_view(1, 0) = 0.0; + fspl_x_view(2, 0) = 0.0; + fspl_x_view(1, inx - 1) = 0.0; + fspl_x_view(2, inx - 1) = 0.0; + + compute_spline_coefficients(ibcxmin, ibcxmax, inx, x, fspl_x_view, + wk_x_view); } - }); + + Kokkos::parallel_for( + Kokkos::TeamThreadRange(team, inx - 1), [=](LO ix) { + fspl(1, ic, ix, iy) += fspl_x_view(1, ix); + fspl(2, ic, ix, iy) += fspl_x_view(2, ix) * xo2; + fspl(3, ic, ix, iy) += fspl_x_view(3, ix) * xo6; + }); + } + }); } } @@ -1464,11 +1480,11 @@ void solve_bicubic_spline_explicit(Rank1View x, LO inx, * \param lookup_tol tolerance for the lookup */ template -KOKKOS_INLINE_FUNCTION void -bicubic_lookup_compact(T xget, T yget, Rank1View x, LO nx, - Rank1View y, LO ny, LO &i, LO &j, - T &xparam, T &yparam, T &hx, T &hxi, T &hy, T &hyi, - LO &ier, T lookup_tol) { +KOKKOS_INLINE_FUNCTION void bicubic_lookup_compact( + T xget, T yget, Rank1View x, LO nx, + Rank1View y, LO ny, LO& i, LO& j, T& xparam, T& yparam, T& hx, + T& hxi, T& hy, T& hyi, LO& ier, T lookup_tol) +{ T zxget = xget; T zyget = yget; @@ -1503,11 +1519,11 @@ bicubic_lookup_compact(T xget, T yget, Rank1View x, LO nx, * \param f bicubic spline coefficients */ template -KOKKOS_INLINE_FUNCTION void -bicubic_evalfn_compact(Kokkos::View ict, LO ivec, LO ivecd, - Rank1View fval, LO i, LO j, T xparam, - T yparam, T hx, T hxi, T hy, T hyi, - Rank3View f) { +KOKKOS_INLINE_FUNCTION void bicubic_evalfn_compact( + Kokkos::View ict, LO ivec, LO ivecd, + Rank1View fval, LO i, LO j, T xparam, T yparam, T hx, T hxi, + T hy, T hyi, Rank3View f) +{ constexpr T sixth = 1.0 / 6.0; const T z36th = sixth * sixth; LO iadr = 0; @@ -1635,8 +1651,8 @@ bicubic_evalfn_compact(Kokkos::View ict, LO ivec, LO ivecd, T cydi = -3.0 * ypi2 + 1.0; T sum = - hxi * hyi * - (f(0, i, j) - f(0, i, j + 1) - f(0, i + 1, j) + f(0, i + 1, j + 1)); + hxi * hyi * + (f(0, i, j) - f(0, i, j + 1) - f(0, i + 1, j) + f(0, i + 1, j + 1)); sum += sixth * hx * hyi * (cxdi * (-f(1, i, j) + f(1, i, j + 1)) + cxd * (-f(1, i + 1, j) + f(1, i + 1, j + 1))); @@ -1727,8 +1743,8 @@ bicubic_evalfn_compact(Kokkos::View ict, LO ivec, LO ivecd, T cyd = 3.0 * yp2 - 1.0; T cydi = -3.0 * ypi2 + 1.0; T sum = - hxi * hyi * - (f(1, i, j) - f(1, i, j + 1) - f(1, i + 1, j) + f(1, i + 1, j + 1)); + hxi * hyi * + (f(1, i, j) - f(1, i, j + 1) - f(1, i + 1, j) + f(1, i + 1, j + 1)); sum += sixth * hy * hxi * (-(cydi * f(3, i, j) + cyd * f(3, i, j + 1)) + (cydi * f(3, i + 1, j) + cyd * f(3, i + 1, j + 1))); @@ -1753,8 +1769,8 @@ bicubic_evalfn_compact(Kokkos::View ict, LO ivec, LO ivecd, T cxd = 3.0 * xp2 - 1.0; T cxdi = -3.0 * xpi2 + 1.0; T sum = - hxi * hyi * - (f(2, i, j) - f(2, i, j + 1) - f(2, i + 1, j) + f(2, i + 1, j + 1)); + hxi * hyi * + (f(2, i, j) - f(2, i, j + 1) - f(2, i + 1, j) + f(2, i + 1, j + 1)); sum += sixth * hx * hyi * (cxdi * (-f(3, i, j) + f(3, i, j + 1)) + cxd * (-f(3, i + 1, j) + f(3, i + 1, j + 1))); @@ -1808,10 +1824,11 @@ bicubic_evalfn_compact(Kokkos::View ict, LO ivec, LO ivecd, */ template KOKKOS_INLINE_FUNCTION void bicubic_eval_compact( - T xget, T yget, Kokkos::View ict, - Rank1View fval, Rank1View x, - LO nx, Rank1View y, LO ny, - Rank3View f, LO &ier, T lookup_tol) { + T xget, T yget, Kokkos::View ict, + Rank1View fval, Rank1View x, LO nx, + Rank1View y, LO ny, Rank3View f, LO& ier, + T lookup_tol) +{ // Local variables LO i = 0, j = 0; T xparam = 0.0, yparam = 0.0; @@ -1838,7 +1855,8 @@ void solve_bicubic_spline_compact(Rank1View x, LO nx, Rank1View bcxmax, LO ibcymin, Rank1View bcymin, LO ibcymax, Rank1View bcymax, - Rank1View wk) { + Rank1View wk) +{ using execution_space = typename MemorySpace::execution_space; using member_type = typename Kokkos::TeamPolicy::member_type; LO iflg2 = 0; @@ -1851,187 +1869,187 @@ void solve_bicubic_spline_compact(Rank1View x, LO nx, auto fspl_l_x = Rank2View(wk.data_handle(), 2 * ny, nx); auto wk_l = - Rank1View(wk.data_handle() + 2 * ny * nx, nx * ny); + Rank1View(wk.data_handle() + 2 * ny * nx, nx * ny); auto fwk4_l_x = - Rank2View(wk.data_handle() + 3 * ny * nx, 4 * ny, nx); + Rank2View(wk.data_handle() + 3 * ny * nx, 4 * ny, nx); Kokkos::parallel_for( - Kokkos::TeamPolicy(ny, Kokkos::AUTO), - KOKKOS_LAMBDA(const member_type &team) { - const LO iy = team.league_rank(); - T zbcmin = 0.0, zbcmax = 0.0; - - auto fwk_x_view = Rank2View( - fspl_l_x.data_handle() + 2 * nx * iy, 2, nx); - auto wk_x_view = - Rank1View(wk_l.data_handle() + nx * iy, nx); - auto fwk4_x_view = Rank2View( - fwk4_l_x.data_handle() + 4 * nx * iy, 4, nx); - - Kokkos::parallel_for(Kokkos::TeamThreadRange(team, nx), - [=](LO ix) { fwk_x_view(0, ix) = f(0, ix, iy); }); + Kokkos::TeamPolicy(ny, Kokkos::AUTO), + KOKKOS_LAMBDA(const member_type& team) { + const LO iy = team.league_rank(); + T zbcmin = 0.0, zbcmax = 0.0; + + auto fwk_x_view = + Rank2View(fspl_l_x.data_handle() + 2 * nx * iy, 2, nx); + auto wk_x_view = + Rank1View(wk_l.data_handle() + nx * iy, nx); + auto fwk4_x_view = + Rank2View(fwk4_l_x.data_handle() + 4 * nx * iy, 4, nx); + + Kokkos::parallel_for(Kokkos::TeamThreadRange(team, nx), + [=](LO ix) { fwk_x_view(0, ix) = f(0, ix, iy); }); + + if (team.team_rank() == 0) { + if (ibcxmin == 1 || ibcxmin == 2) + zbcmin = bcxmin[iy]; + if (ibcxmax == 1 || ibcxmax == 2) + zbcmax = bcxmax[iy]; + + solve_cubic_spline_compact(x, nx, fwk_x_view, fwk4_x_view, ibcxmin, + zbcmin, ibcxmax, zbcmax, wk_x_view); + } - if (team.team_rank() == 0) { - if (ibcxmin == 1 || ibcxmin == 2) - zbcmin = bcxmin[iy]; - if (ibcxmax == 1 || ibcxmax == 2) - zbcmax = bcxmax[iy]; + Kokkos::parallel_for(Kokkos::TeamThreadRange(team, nx), + [=](LO ix) { f(1, ix, iy) = fwk_x_view(1, ix); }); + }); - solve_cubic_spline_compact(x, nx, fwk_x_view, fwk4_x_view, ibcxmin, - zbcmin, ibcxmax, zbcmax, wk_x_view); + Kokkos::parallel_for( + Kokkos::TeamPolicy(nx, Kokkos::AUTO), + KOKKOS_LAMBDA(const member_type& team) { + const LO ix = team.league_rank(); + LO ibcmin = ibcymin, ibcmax = ibcymax; + + auto fwk_y_view = + Rank2View(fspl_l_x.data_handle() + 2 * ny * ix, 2, ny); + auto wk_y_view = + Rank1View(wk_l.data_handle() + ny * ix, ny); + auto fwk4_y_view = + Rank2View(fwk4_l_x.data_handle() + 4 * ny * ix, 4, ny); + + Kokkos::parallel_for(Kokkos::TeamThreadRange(team, ny), + [=](LO iy) { fwk_y_view(0, iy) = f(0, ix, iy); }); + + if (team.team_rank() == 0) { + if (iflg2 == 1) { + if (ibcymin == 1 || ibcymin == 2) + ibcmin = 0; + if (ibcymax == 1 || ibcymax == 2) + ibcmax = 0; } - Kokkos::parallel_for(Kokkos::TeamThreadRange(team, nx), - [=](LO ix) { f(1, ix, iy) = fwk_x_view(1, ix); }); - }); + solve_cubic_spline_compact(y, ny, fwk_y_view, fwk4_y_view, ibcmin, 0.0, + ibcmax, 0.0, wk_y_view); + } + Kokkos::parallel_for(Kokkos::TeamThreadRange(team, ny), + [=](LO iy) { f(2, ix, iy) = fwk_y_view(1, iy); }); + }); Kokkos::parallel_for( - Kokkos::TeamPolicy(nx, Kokkos::AUTO), - KOKKOS_LAMBDA(const member_type &team) { - const LO ix = team.league_rank(); - LO ibcmin = ibcymin, ibcmax = ibcymax; - - auto fwk_y_view = Rank2View( - fspl_l_x.data_handle() + 2 * ny * ix, 2, ny); - auto wk_y_view = - Rank1View(wk_l.data_handle() + ny * ix, ny); - auto fwk4_y_view = Rank2View( - fwk4_l_x.data_handle() + 4 * ny * ix, 4, ny); + Kokkos::TeamPolicy(nx, Kokkos::AUTO), + KOKKOS_LAMBDA(const member_type& team) { + const LO ix = team.league_rank(); + LO ibcmin = ibcymin, ibcmax = ibcymax; + + auto fwk_y_view = + Rank2View(fspl_l_x.data_handle() + 2 * ny * ix, 2, ny); + auto wk_y_view = + Rank1View(wk_l.data_handle() + ny * ix, ny); + auto fwk4_y_view = + Rank2View(fwk4_l_x.data_handle() + 4 * ny * ix, 4, ny); + + Kokkos::parallel_for(Kokkos::TeamThreadRange(team, ny), + [=](LO iy) { fwk_y_view(0, iy) = f(1, ix, iy); }); + + if (team.team_rank() == 0) { + if (iflg2 == 1) { + if (ibcymin == 1 || ibcymin == 2) + ibcmin = 0; + if (ibcymax == 1 || ibcymax == 2) + ibcmax = 0; + } - Kokkos::parallel_for(Kokkos::TeamThreadRange(team, ny), - [=](LO iy) { fwk_y_view(0, iy) = f(0, ix, iy); }); + solve_cubic_spline_compact(y, ny, fwk_y_view, fwk4_y_view, ibcmin, 0.0, + ibcmax, 0.0, wk_y_view); + } + Kokkos::parallel_for(Kokkos::TeamThreadRange(team, ny), + [=](LO iy) { f(3, ix, iy) = fwk_y_view(1, iy); }); + }); - if (team.team_rank() == 0) { - if (iflg2 == 1) { - if (ibcymin == 1 || ibcymin == 2) - ibcmin = 0; - if (ibcymax == 1 || ibcymax == 2) - ibcmax = 0; - } + // Correct for inhomogeneous boundary conditions if needed + if (iflg2 == 1) { + T zbcmin = 0.0; + T zbcmax = 0.0; - solve_cubic_spline_compact(y, ny, fwk_y_view, fwk4_y_view, ibcmin, - 0.0, ibcmax, 0.0, wk_y_view); - } - Kokkos::parallel_for(Kokkos::TeamThreadRange(team, ny), - [=](LO iy) { f(2, ix, iy) = fwk_y_view(1, iy); }); - }); + auto fcorr = + Rank3View(wk.data_handle() + 7 * ny * nx, 2, nx, ny); - Kokkos::parallel_for( + Kokkos::parallel_for( Kokkos::TeamPolicy(nx, Kokkos::AUTO), - KOKKOS_LAMBDA(const member_type &team) { + KOKKOS_LAMBDA(const member_type& team) { const LO ix = team.league_rank(); - LO ibcmin = ibcymin, ibcmax = ibcymax; + T zdiff1 = 0.0, zdiff2 = 0.0; auto fwk_y_view = Rank2View( - fspl_l_x.data_handle() + 2 * ny * ix, 2, ny); + fspl_l_x.data_handle() + 2 * ny * ix, 2, ny); auto wk_y_view = - Rank1View(wk_l.data_handle() + ny * ix, ny); + Rank1View(wk_l.data_handle() + ny * ix, ny); auto fwk4_y_view = Rank2View( - fwk4_l_x.data_handle() + 4 * ny * ix, 4, ny); + fwk4_l_x.data_handle() + 4 * ny * ix, 4, ny); + + if (ibcymin == 1) { + zdiff1 = bcymin[ix] - + ((f(0, ix, 1) - f(0, ix, 0)) / (y[1] - y[0]) + + (y[1] - y[0]) * (-2.0 * f(2, ix, 0) - f(2, ix, 1)) / 6.0); + } else if (ibcymin == 2) { + zdiff1 = bcymin[ix] - f(2, ix, 0); + } else { + zdiff1 = 0.0; + } - Kokkos::parallel_for(Kokkos::TeamThreadRange(team, ny), - [=](LO iy) { fwk_y_view(0, iy) = f(1, ix, iy); }); + if (ibcymax == 1) { + zdiff2 = + bcymax[ix] - + ((f(0, ix, ny - 1) - f(0, ix, ny - 2)) / (y[ny - 1] - y[ny - 2]) + + (y[ny - 1] - y[ny - 2]) * + (2.0 * f(2, ix, ny - 1) + f(2, ix, ny - 2)) / 6.0); + } else if (ibcymax == 2) { + zdiff2 = bcymax[ix] - f(2, ix, ny - 1); + } else { + zdiff2 = 0.0; + } + Kokkos::parallel_for(Kokkos::TeamThreadRange(team, ny), + [=](LO iy) { fwk_y_view(0, iy) = 0.0; }); if (team.team_rank() == 0) { - if (iflg2 == 1) { - if (ibcymin == 1 || ibcymin == 2) - ibcmin = 0; - if (ibcymax == 1 || ibcymax == 2) - ibcmax = 0; - } - - solve_cubic_spline_compact(y, ny, fwk_y_view, fwk4_y_view, ibcmin, - 0.0, ibcmax, 0.0, wk_y_view); + solve_cubic_spline_compact(y, ny, fwk_y_view, fwk4_y_view, ibcymin, + zdiff1, ibcymax, zdiff2, wk_y_view); } - Kokkos::parallel_for(Kokkos::TeamThreadRange(team, ny), - [=](LO iy) { f(3, ix, iy) = fwk_y_view(1, iy); }); + Kokkos::parallel_for(Kokkos::TeamThreadRange(team, ny), [=](LO iy) { + fcorr(0, ix, iy) = fwk_y_view(1, iy); + }); }); - // Correct for inhomogeneous boundary conditions if needed - if (iflg2 == 1) { - T zbcmin = 0.0; - T zbcmax = 0.0; - - auto fcorr = - Rank3View(wk.data_handle() + 7 * ny * nx, 2, nx, ny); - Kokkos::parallel_for( - Kokkos::TeamPolicy(nx, Kokkos::AUTO), - KOKKOS_LAMBDA(const member_type &team) { - const LO ix = team.league_rank(); - T zdiff1 = 0.0, zdiff2 = 0.0; - - auto fwk_y_view = Rank2View( - fspl_l_x.data_handle() + 2 * ny * ix, 2, ny); - auto wk_y_view = - Rank1View(wk_l.data_handle() + ny * ix, ny); - auto fwk4_y_view = Rank2View( - fwk4_l_x.data_handle() + 4 * ny * ix, 4, ny); - - if (ibcymin == 1) { - zdiff1 = bcymin[ix] - - ((f(0, ix, 1) - f(0, ix, 0)) / (y[1] - y[0]) + - (y[1] - y[0]) * (-2.0 * f(2, ix, 0) - f(2, ix, 1)) / 6.0); - } else if (ibcymin == 2) { - zdiff1 = bcymin[ix] - f(2, ix, 0); - } else { - zdiff1 = 0.0; - } - - if (ibcymax == 1) { - zdiff2 = bcymax[ix] - - ((f(0, ix, ny - 1) - f(0, ix, ny - 2)) / - (y[ny - 1] - y[ny - 2]) + - (y[ny - 1] - y[ny - 2]) * - (2.0 * f(2, ix, ny - 1) + f(2, ix, ny - 2)) / 6.0); - } else if (ibcymax == 2) { - zdiff2 = bcymax[ix] - f(2, ix, ny - 1); - } else { - zdiff2 = 0.0; - } + Kokkos::TeamPolicy(ny, Kokkos::AUTO), + KOKKOS_LAMBDA(const member_type& team) { + const LO iy = team.league_rank(); + auto fwk_x_view = Rank2View( + fspl_l_x.data_handle() + 2 * nx * iy, 2, nx); + auto wk_x_view = + Rank1View(wk_l.data_handle() + nx * iy, nx); + auto fwk4_x_view = Rank2View( + fwk4_l_x.data_handle() + 4 * nx * iy, 4, nx); - Kokkos::parallel_for(Kokkos::TeamThreadRange(team, ny), - [=](LO iy) { fwk_y_view(0, iy) = 0.0; }); - if (team.team_rank() == 0) { - solve_cubic_spline_compact(y, ny, fwk_y_view, fwk4_y_view, ibcymin, - zdiff1, ibcymax, zdiff2, wk_y_view); - } - Kokkos::parallel_for(Kokkos::TeamThreadRange(team, ny), [=](LO iy) { - fcorr(0, ix, iy) = fwk_y_view(1, iy); - }); + Kokkos::parallel_for(Kokkos::TeamThreadRange(team, nx), [=](LO ix) { + fwk_x_view(0, ix) = fcorr(0, ix, iy); }); - Kokkos::parallel_for( - Kokkos::TeamPolicy(ny, Kokkos::AUTO), - KOKKOS_LAMBDA(const member_type &team) { - const LO iy = team.league_rank(); - auto fwk_x_view = Rank2View( - fspl_l_x.data_handle() + 2 * nx * iy, 2, nx); - auto wk_x_view = - Rank1View(wk_l.data_handle() + nx * iy, nx); - auto fwk4_x_view = Rank2View( - fwk4_l_x.data_handle() + 4 * nx * iy, 4, nx); - - Kokkos::parallel_for(Kokkos::TeamThreadRange(team, nx), [=](LO ix) { - fwk_x_view(0, ix) = fcorr(0, ix, iy); - }); - - if (team.team_rank() == 0) { - solve_cubic_spline_compact(x, nx, fwk_x_view, fwk4_x_view, ibcxmin, - zbcmin, ibcxmax, zbcmax, wk_x_view); - } + if (team.team_rank() == 0) { + solve_cubic_spline_compact(x, nx, fwk_x_view, fwk4_x_view, ibcxmin, + zbcmin, ibcxmax, zbcmax, wk_x_view); + } - Kokkos::parallel_for(Kokkos::TeamThreadRange(team, nx), [=](LO ix) { - fcorr(1, ix, iy) = fwk_x_view(1, ix); - }); + Kokkos::parallel_for(Kokkos::TeamThreadRange(team, nx), [=](LO ix) { + fcorr(1, ix, iy) = fwk_x_view(1, ix); }); + }); Kokkos::parallel_for( - Kokkos::MDRangePolicy>({0, 0}, {nx, ny}), - KOKKOS_LAMBDA(const LO ix, const LO iy) { - f(2, ix, iy) += fcorr(0, ix, iy); - f(3, ix, iy) += fcorr(1, ix, iy); - }); + Kokkos::MDRangePolicy>({0, 0}, {nx, ny}), + KOKKOS_LAMBDA(const LO ix, const LO iy) { + f(2, ix, iy) += fcorr(0, ix, iy); + f(3, ix, iy) += fcorr(1, ix, iy); + }); } } @@ -2055,7 +2073,8 @@ void solve_bicubic_spline_compact(Rank1View x, LO nx, * difference. THIRD_DIV_DIFF_MATCH | ibcxmin=7 | ibcxmax=7 -- third * derivative matches the third divided difference. */ -enum class BoundaryCondition { +enum class BoundaryCondition +{ PERIODIC = -1, ///< Periodic boundary condition: s'(x(0))=s'(x(-1)) and ///< s''(x(0))=s''(x(-1)) NOT_A_KNOT = 0, ///< Not-a-knot boundary condition @@ -2064,11 +2083,11 @@ enum class BoundaryCondition { FIRST_DERIVATIVE_ZERO = 3, ///< First derivative equal to zero at boundary SECOND_DERIVATIVE_ZERO = 4, ///< Second derivative equal to zero at boundary FIRST_DIV_DIFF_MATCH = - 5, ///< First derivative matches first divided difference + 5, ///< First derivative matches first divided difference SECOND_DIV_DIFF_MATCH = - 6, ///< Second derivative matches second divided difference + 6, ///< Second derivative matches second divided difference THIRD_DIV_DIFF_MATCH = - 7 ///< Third derivative matches third divided difference + 7 ///< Third derivative matches third divided difference }; /** \brief CubicSplineInterpolator class @@ -2077,14 +2096,15 @@ enum class BoundaryCondition { * Original developers: PPPL Computational Plasma Physics Group * Original release: February 5, 1999 */ -template class CubicSplineInterpolator { +template +class CubicSplineInterpolator +{ public: virtual void evaluate(Rank1View xvec, Rank2View fval) = 0; - virtual void evaluate(Kokkos::View selector, + virtual void evaluate(Kokkos::View selector, Rank1View xvec, - Rank2View fval, - T lookup_tol) = 0; + Rank2View fval, T lookup_tol) = 0; }; /** \brief ExplicitCubicSplineInterpolator class @@ -2110,7 +2130,8 @@ template class CubicSplineInterpolator { */ template class ExplicitCubicSplineInterpolator - : public CubicSplineInterpolator { + : public CubicSplineInterpolator +{ public: using execution_space = typename MemorySpace::execution_space; using member_type = typename Kokkos::TeamPolicy::member_type; @@ -2163,13 +2184,13 @@ class ExplicitCubicSplineInterpolator * compute. For example, if selector = {1, 1, 0}, then the function value and * first derivative will be computed. */ - void evaluate(Kokkos::View selector, - Rank1View xvec, - Rank2View fval, T lookup_tol = 4.0e-7) override; + void evaluate(Kokkos::View selector, + Rank1View xvec, Rank2View fval, + T lookup_tol = 4.0e-7) override; private: Rank1View x_; - Kokkos::View coefficients_; + Kokkos::View coefficients_; Rank2View get_coefficients_view(); }; @@ -2190,7 +2211,8 @@ class ExplicitCubicSplineInterpolator */ template class CompactCubicSplineInterpolator - : public CubicSplineInterpolator { + : public CubicSplineInterpolator +{ public: using execution_space = typename MemorySpace::execution_space; using member_type = typename Kokkos::TeamPolicy::member_type; @@ -2236,26 +2258,27 @@ class CompactCubicSplineInterpolator * \details The selector follows the same rules as in * ExplicitCubicSplineInterpolator. */ - void evaluate(Kokkos::View selector, - Rank1View xvec, - Rank2View fval, T lookup_tol = 4.0e-7) override; + void evaluate(Kokkos::View selector, + Rank1View xvec, Rank2View fval, + T lookup_tol = 4.0e-7) override; private: Rank1View x_; - Kokkos::View coefficients_; + Kokkos::View coefficients_; Rank2View get_coefficients_view(); }; -template class BiCubicSplineInterpolator { +template +class BiCubicSplineInterpolator +{ public: virtual void evaluate(Rank1View xvec, Rank1View yvec, Rank2View fval) = 0; - virtual void evaluate(Kokkos::View selector, + virtual void evaluate(Kokkos::View selector, Rank1View xvec, Rank1View yvec, - Rank2View fval, - T lookup_tol) = 0; + Rank2View fval, T lookup_tol) = 0; }; /** \brief BiCubicSplineInterpolator class @@ -2272,7 +2295,8 @@ template class BiCubicSplineInterpolator { */ template class ExplicitBiCubicSplineInterpolator - : public BiCubicSplineInterpolator { + : public BiCubicSplineInterpolator +{ public: using execution_space = typename MemorySpace::execution_space; using member_type = typename Kokkos::TeamPolicy::member_type; @@ -2295,12 +2319,12 @@ class ExplicitBiCubicSplineInterpolator * CubicSplineInterpolator at each direction. */ ExplicitBiCubicSplineInterpolator( - Rank1View x, Rank1View y, - Rank1View values, BoundaryCondition ibcxmin, - Rank1View bcxmin, BoundaryCondition ibcxmax, - Rank1View bcxmax, BoundaryCondition ibcymin, - Rank1View bcymin, BoundaryCondition ibcymax, - Rank1View bcymax); + Rank1View x, Rank1View y, + Rank1View values, BoundaryCondition ibcxmin, + Rank1View bcxmin, BoundaryCondition ibcxmax, + Rank1View bcxmax, BoundaryCondition ibcymin, + Rank1View bcymin, BoundaryCondition ibcymax, + Rank1View bcymax); /** \brief Construct the interpolator object and set up the coefficients with * default boundary conditions @@ -2338,14 +2362,14 @@ class ExplicitBiCubicSplineInterpolator * iselect(5)=1 -- evaluate d2f/dy2 * iselect(6)=1 -- evaluate d2f/dxdy */ - void evaluate(Kokkos::View iselect, + void evaluate(Kokkos::View iselect, Rank1View xvec, Rank1View yvec, Rank2View fval, T lookup_tol = 4.0e-7) override; private: Rank1View x_; Rank1View y_; - Kokkos::View coefficients_; + Kokkos::View coefficients_; Rank4View get_coefficients_view(); }; @@ -2373,7 +2397,8 @@ class ExplicitBiCubicSplineInterpolator */ template class CompactBiCubicSplineInterpolator - : public BiCubicSplineInterpolator { + : public BiCubicSplineInterpolator +{ public: using execution_space = typename MemorySpace::execution_space; using member_type = typename Kokkos::TeamPolicy::member_type; @@ -2396,12 +2421,12 @@ class CompactBiCubicSplineInterpolator * CubicSplineInterpolator at each direction. */ CompactBiCubicSplineInterpolator( - Rank1View x, Rank1View y, - Rank1View values, BoundaryCondition ibcxmin, - Rank1View bcxmin, BoundaryCondition ibcxmax, - Rank1View bcxmax, BoundaryCondition ibcymin, - Rank1View bcymin, BoundaryCondition ibcymax, - Rank1View bcymax); + Rank1View x, Rank1View y, + Rank1View values, BoundaryCondition ibcxmin, + Rank1View bcxmin, BoundaryCondition ibcxmax, + Rank1View bcxmax, BoundaryCondition ibcymin, + Rank1View bcymin, BoundaryCondition ibcymax, + Rank1View bcymax); /** \brief Construct the interpolator object and set up the coefficients with * default boundary conditions \param x input grid points in x direction @@ -2432,44 +2457,50 @@ class CompactBiCubicSplineInterpolator * \details The selector follows the same rules as in * ExplicitBiCubicSplineInterpolator. */ - void evaluate(Kokkos::View iselect, + void evaluate(Kokkos::View iselect, Rank1View xvec, Rank1View yvec, Rank2View fval, T lookup_tol = 4.0e-7) override; private: Rank1View x_; Rank1View y_; - Kokkos::View coefficients_; + Kokkos::View coefficients_; Rank3View get_coefficients_view(); }; template Rank2View -ExplicitCubicSplineInterpolator::get_coefficients_view() { +ExplicitCubicSplineInterpolator::get_coefficients_view() +{ return Rank2View(coefficients_.data(), 4, x_.extent(0)); } template Rank2View -CompactCubicSplineInterpolator::get_coefficients_view() { +CompactCubicSplineInterpolator::get_coefficients_view() +{ return Rank2View(coefficients_.data(), 2, x_.extent(0)); } template Rank4View -ExplicitBiCubicSplineInterpolator::get_coefficients_view() { +ExplicitBiCubicSplineInterpolator::get_coefficients_view() +{ return Rank4View(coefficients_.data(), 4, 4, x_.extent(0), y_.extent(0)); } template Rank3View -CompactBiCubicSplineInterpolator::get_coefficients_view() { +CompactBiCubicSplineInterpolator::get_coefficients_view() +{ return Rank3View(coefficients_.data(), 4, x_.extent(0), y_.extent(0)); } -template struct InitCubicCoeffFunctor { +template +struct InitCubicCoeffFunctor +{ Rank2View fspl; Rank1View values; @@ -2477,14 +2508,17 @@ template struct InitCubicCoeffFunctor { // Constructor to initialize captured variables InitCubicCoeffFunctor(Rank2View fspl_, Rank1View values_) - : fspl(fspl_), values(values_) {} + : fspl(fspl_), values(values_) + { + } KOKKOS_INLINE_FUNCTION void operator()(const LO i) const { fspl(0, i) = values(i); } }; template -struct SolveCompactCubicSplineFunctor { +struct SolveCompactCubicSplineFunctor +{ using execution_space = typename MemorySpace::execution_space; using member_type = typename Kokkos::TeamPolicy::member_type; @@ -2503,11 +2537,21 @@ struct SolveCompactCubicSplineFunctor { Rank2View fspl4_, LO ibcxmin_, T bcxmin_, LO ibcxmax_, T bcxmax_, Rank1View wk_) - : x(x_), nx(nx_), fspl(fspl_), fspl4(fspl4_), ibcxmin(ibcxmin_), - bcxmin(bcxmin_), ibcxmax(ibcxmax_), bcxmax(bcxmax_), wk(wk_) {} + : x(x_), + nx(nx_), + fspl(fspl_), + fspl4(fspl4_), + ibcxmin(ibcxmin_), + bcxmin(bcxmin_), + ibcxmax(ibcxmax_), + bcxmax(bcxmax_), + wk(wk_) + { + } KOKKOS_INLINE_FUNCTION - void operator()(const member_type &team_member) const { + void operator()(const member_type& team_member) const + { Kokkos::single(Kokkos::PerTeam(team_member), [=]() { detail::solve_cubic_spline_compact(x, nx, fspl, fspl4, ibcxmin, bcxmin, ibcxmax, bcxmax, wk); @@ -2516,7 +2560,8 @@ struct SolveCompactCubicSplineFunctor { }; template -struct SolveExplicitCubicSplineFunctor { +struct SolveExplicitCubicSplineFunctor +{ using execution_space = typename MemorySpace::execution_space; using member_type = typename Kokkos::TeamPolicy::member_type; @@ -2533,11 +2578,20 @@ struct SolveExplicitCubicSplineFunctor { Rank2View fspl_, LO ibcxmin_, T bcxmin_, LO ibcxmax_, T bcxmax_, Rank1View wk_) - : x(x_), nx(nx_), fspl(fspl_), ibcxmin(ibcxmin_), bcxmin(bcxmin_), - ibcxmax(ibcxmax_), bcxmax(bcxmax_), wk(wk_) {} + : x(x_), + nx(nx_), + fspl(fspl_), + ibcxmin(ibcxmin_), + bcxmin(bcxmin_), + ibcxmax(ibcxmax_), + bcxmax(bcxmax_), + wk(wk_) + { + } KOKKOS_INLINE_FUNCTION - void operator()(const member_type &team_member) const { + void operator()(const member_type& team_member) const + { Kokkos::single(Kokkos::PerTeam(team_member), [=]() { detail::solve_cubic_spline_explicit(x, nx, fspl, ibcxmin, bcxmin, ibcxmax, bcxmax, wk); @@ -2547,25 +2601,26 @@ struct SolveExplicitCubicSplineFunctor { template ExplicitCubicSplineInterpolator:: - ExplicitCubicSplineInterpolator(Rank1View x, - Rank1View values, - BoundaryCondition ibcxmin, T bcxmin, - BoundaryCondition ibcxmax, T bcxmax) { + ExplicitCubicSplineInterpolator(Rank1View x, + Rank1View values, + BoundaryCondition ibcxmin, T bcxmin, + BoundaryCondition ibcxmax, T bcxmax) +{ detail::grid_valid(x); x_ = x; LO nx = x.extent(0); - Kokkos::View fspl_view("coefficients", 4 * nx); + Kokkos::View fspl_view("coefficients", 4 * nx); coefficients_ = fspl_view; auto fspl = get_coefficients_view(); InitCubicCoeffFunctor init_functor(fspl, values); Kokkos::parallel_for("initialize_coefficients", nx, init_functor); - Kokkos::View wk_view("working space", 10); + Kokkos::View wk_view("working space", 10); auto wk = Rank1View(wk_view.data(), 10); // TODO: pass member type to solve_spline SolveExplicitCubicSplineFunctor functor( - x, nx, fspl, static_cast(ibcxmin), bcxmin, static_cast(ibcxmax), - bcxmax, wk); + x, nx, fspl, static_cast(ibcxmin), bcxmin, static_cast(ibcxmax), + bcxmax, wk); Kokkos::parallel_for("solve_cubic_spline_explicit", Kokkos::TeamPolicy(1, Kokkos::AUTO), functor); @@ -2573,35 +2628,37 @@ ExplicitCubicSplineInterpolator:: template ExplicitCubicSplineInterpolator:: - ExplicitCubicSplineInterpolator(Rank1View x, - Rank1View values) - : ExplicitCubicSplineInterpolator(x, values, BoundaryCondition::NOT_A_KNOT, - 0, BoundaryCondition::NOT_A_KNOT, 0) { + ExplicitCubicSplineInterpolator(Rank1View x, + Rank1View values) + : ExplicitCubicSplineInterpolator(x, values, BoundaryCondition::NOT_A_KNOT, 0, + BoundaryCondition::NOT_A_KNOT, 0) +{ std::cout << "Not a knot boundary condition is applied by default" << std::endl; } template CompactCubicSplineInterpolator::CompactCubicSplineInterpolator( - Rank1View x, Rank1View values, - BoundaryCondition ibcxmin, T bcxmin, BoundaryCondition ibcxmax, T bcxmax) { + Rank1View x, Rank1View values, + BoundaryCondition ibcxmin, T bcxmin, BoundaryCondition ibcxmax, T bcxmax) +{ detail::grid_valid(x); x_ = x; LO nx = x.extent(0); - Kokkos::View fspl_view("coefficients", 2 * nx); + Kokkos::View fspl_view("coefficients", 2 * nx); coefficients_ = fspl_view; auto fspl = get_coefficients_view(); InitCubicCoeffFunctor init_functor(fspl, values); Kokkos::parallel_for("initialize_coefficients", nx, init_functor); - Kokkos::View fspl4_view("explicit coefficients", 4 * nx); + Kokkos::View fspl4_view("explicit coefficients", 4 * nx); auto fspl4 = Rank2View(fspl4_view.data(), 4, nx); - Kokkos::View wk_view("working space", 10); + Kokkos::View wk_view("working space", 10); auto wk = Rank1View(wk_view.data(), 10); SolveCompactCubicSplineFunctor functor( - x, nx, fspl, fspl4, static_cast(ibcxmin), bcxmin, - static_cast(ibcxmax), bcxmax, wk); + x, nx, fspl, fspl4, static_cast(ibcxmin), bcxmin, + static_cast(ibcxmax), bcxmax, wk); Kokkos::parallel_for("solve_cubic_spline_compact", Kokkos::TeamPolicy(1, Kokkos::AUTO), functor); @@ -2609,52 +2666,56 @@ CompactCubicSplineInterpolator::CompactCubicSplineInterpolator( template CompactCubicSplineInterpolator::CompactCubicSplineInterpolator( - Rank1View x, Rank1View fx) - : CompactCubicSplineInterpolator(x, fx, BoundaryCondition::NOT_A_KNOT, 0, - BoundaryCondition::NOT_A_KNOT, 0) { + Rank1View x, Rank1View fx) + : CompactCubicSplineInterpolator(x, fx, BoundaryCondition::NOT_A_KNOT, 0, + BoundaryCondition::NOT_A_KNOT, 0) +{ std::cout << "Not a knot boundary condition is applied by default" << std::endl; } template void ExplicitCubicSplineInterpolator::evaluate( - const Kokkos::View selector, - Rank1View xvec, Rank2View fval, T lookup_tol) { + const Kokkos::View selector, Rank1View xvec, + Rank2View fval, T lookup_tol) +{ LO ivd = fval.extent(1); auto fspl = get_coefficients_view(); Kokkos::parallel_for( - Kokkos::RangePolicy(0, xvec.extent(0)), - KOKKOS_CLASS_LAMBDA(const LO i) { - LO ier = 0; - auto fval_view = - Rank1View(fval.data_handle() + i * ivd, ivd); - detail::cubic_eval_explicit(xvec(i), selector, fval_view, x_, - x_.extent(0), fspl, ier, lookup_tol); - }); + Kokkos::RangePolicy(0, xvec.extent(0)), + KOKKOS_CLASS_LAMBDA(const LO i) { + LO ier = 0; + auto fval_view = + Rank1View(fval.data_handle() + i * ivd, ivd); + detail::cubic_eval_explicit(xvec(i), selector, fval_view, x_, + x_.extent(0), fspl, ier, lookup_tol); + }); } template void ExplicitCubicSplineInterpolator::evaluate( - Rank1View xvec, Rank2View fval) { + Rank1View xvec, Rank2View fval) +{ std::array ict_arr = {1, 0, 0}; - evaluate(Kokkos::View(ict_arr.data(), 3), xvec, fval); + evaluate(Kokkos::View(ict_arr.data(), 3), xvec, fval); }; template void CompactCubicSplineInterpolator::evaluate( - Kokkos::View selector, Rank1View xvec, - Rank2View fval, T lookup_tol) { + Kokkos::View selector, Rank1View xvec, + Rank2View fval, T lookup_tol) +{ LO ivd = fval.extent(1); auto fspl = get_coefficients_view(); Kokkos::parallel_for( - Kokkos::RangePolicy(0, xvec.extent(0)), - KOKKOS_CLASS_LAMBDA(const LO i) { - LO ier = 0; - auto fval_view = - Rank1View(fval.data_handle() + i * ivd, ivd); - detail::cubic_eval_compact(xvec(i), selector, fval_view, x_, - x_.extent(0), fspl, ier, lookup_tol); - }); + Kokkos::RangePolicy(0, xvec.extent(0)), + KOKKOS_CLASS_LAMBDA(const LO i) { + LO ier = 0; + auto fval_view = + Rank1View(fval.data_handle() + i * ivd, ivd); + detail::cubic_eval_compact(xvec(i), selector, fval_view, x_, x_.extent(0), + fspl, ier, lookup_tol); + }); } // TODO: evluation functions are exactly the same, so put them in base class and @@ -2662,117 +2723,132 @@ void CompactCubicSplineInterpolator::evaluate( // need to figure out if this is possible with the Kokkos template void CompactCubicSplineInterpolator::evaluate( - Rank1View xvec, Rank2View fval) { + Rank1View xvec, Rank2View fval) +{ std::array ict_arr = {1, 0, 0}; - evaluate(Kokkos::View(ict_arr.data(), 3), xvec, fval); + evaluate(Kokkos::View(ict_arr.data(), 3), xvec, fval); }; template void ExplicitBiCubicSplineInterpolator::evaluate( - Kokkos::View iselect, Rank1View xvec, - Rank1View yvec, Rank2View fval, T lookup_tol) { + Kokkos::View iselect, Rank1View xvec, + Rank1View yvec, Rank2View fval, T lookup_tol) +{ PCMS_ALWAYS_ASSERT(xvec.extent(0) == yvec.extent(0) && xvec.extent(0) == fval.extent(0)); LO ivd = fval.extent(1); auto fspl = get_coefficients_view(); Kokkos::parallel_for( - Kokkos::RangePolicy(0, xvec.extent(0)), - KOKKOS_CLASS_LAMBDA(const LO i) { - LO ier = 0; - auto fval_view = - Rank1View(fval.data_handle() + i * ivd, ivd); - detail::bicubic_eval_explicit(xvec(i), yvec(i), iselect, fval_view, x_, - x_.extent(0), y_, y_.extent(0), fspl, - ier, lookup_tol); - }); + Kokkos::RangePolicy(0, xvec.extent(0)), + KOKKOS_CLASS_LAMBDA(const LO i) { + LO ier = 0; + auto fval_view = + Rank1View(fval.data_handle() + i * ivd, ivd); + detail::bicubic_eval_explicit(xvec(i), yvec(i), iselect, fval_view, x_, + x_.extent(0), y_, y_.extent(0), fspl, ier, + lookup_tol); + }); } template void ExplicitBiCubicSplineInterpolator::evaluate( - Rank1View xvec, Rank1View yvec, - Rank2View fval) { + Rank1View xvec, Rank1View yvec, + Rank2View fval) +{ LO ict_arr[6] = {1, 0, 0, 0, 0, 0}; - Kokkos::View ict("select", 6); + Kokkos::View ict("select", 6); Kokkos::parallel_for( - Kokkos::RangePolicy(0, ict.size()), - KOKKOS_LAMBDA(const LO i) { ict(i) = ict_arr[i]; }); + Kokkos::RangePolicy(0, ict.size()), + KOKKOS_LAMBDA(const LO i) { ict(i) = ict_arr[i]; }); evaluate(ict, xvec, yvec, fval); } template void CompactBiCubicSplineInterpolator::evaluate( - Kokkos::View iselect, Rank1View xvec, - Rank1View yvec, Rank2View fval, T lookup_tol) { + Kokkos::View iselect, Rank1View xvec, + Rank1View yvec, Rank2View fval, T lookup_tol) +{ PCMS_ALWAYS_ASSERT(xvec.extent(0) == yvec.extent(0) && xvec.extent(0) == fval.extent(0)); LO ivd = fval.extent(1); auto fspl = get_coefficients_view(); Kokkos::parallel_for( - Kokkos::RangePolicy(0, xvec.extent(0)), - KOKKOS_CLASS_LAMBDA(const LO i) { - LO ier = 0; - auto fval_view = - Rank1View(fval.data_handle() + i * ivd, ivd); - detail::bicubic_eval_compact(xvec(i), yvec(i), iselect, fval_view, x_, - x_.extent(0), y_, y_.extent(0), fspl, ier, lookup_tol); - }); + Kokkos::RangePolicy(0, xvec.extent(0)), + KOKKOS_CLASS_LAMBDA(const LO i) { + LO ier = 0; + auto fval_view = + Rank1View(fval.data_handle() + i * ivd, ivd); + detail::bicubic_eval_compact(xvec(i), yvec(i), iselect, fval_view, x_, + x_.extent(0), y_, y_.extent(0), fspl, ier, + lookup_tol); + }); } template void CompactBiCubicSplineInterpolator::evaluate( - Rank1View xvec, Rank1View yvec, - Rank2View fval) { + Rank1View xvec, Rank1View yvec, + Rank2View fval) +{ LO ict_arr[6] = {1, 0, 0, 0, 0, 0}; - Kokkos::View ict("select", 6); + Kokkos::View ict("select", 6); Kokkos::parallel_for( - Kokkos::RangePolicy(0, ict.size()), - KOKKOS_LAMBDA(const LO i) { ict(i) = ict_arr[i]; }); + Kokkos::RangePolicy(0, ict.size()), + KOKKOS_LAMBDA(const LO i) { ict(i) = ict_arr[i]; }); evaluate(ict, xvec, yvec, fval); } template -struct InitExplicitBiCubicCoeffFunctor { +struct InitExplicitBiCubicCoeffFunctor +{ Rank4View fspl; Rank1View values; LO ny; InitExplicitBiCubicCoeffFunctor(Rank4View fspl_, Rank1View values_, LO ny_) - : fspl(fspl_), values(values_), ny(ny_) {} + : fspl(fspl_), values(values_), ny(ny_) + { + } KOKKOS_INLINE_FUNCTION - void operator()(const LO iy, const LO ix) const { + void operator()(const LO iy, const LO ix) const + { fspl(0, 0, ix, iy) = values(ix * ny + iy); } }; template -struct InitCompactBiCubicCoeffFunctor { +struct InitCompactBiCubicCoeffFunctor +{ Rank3View fspl; Rank1View values; LO ny; InitCompactBiCubicCoeffFunctor(Rank3View fspl_, Rank1View values_, LO ny_) - : fspl(fspl_), values(values_), ny(ny_) {} + : fspl(fspl_), values(values_), ny(ny_) + { + } KOKKOS_INLINE_FUNCTION - void operator()(const LO iy, const LO ix) const { + void operator()(const LO iy, const LO ix) const + { fspl(0, ix, iy) = values(ix * ny + iy); } }; template ExplicitBiCubicSplineInterpolator:: - ExplicitBiCubicSplineInterpolator( - Rank1View x, Rank1View y, - Rank1View values, BoundaryCondition ibcxmin, - Rank1View bcxmin, BoundaryCondition ibcxmax, - Rank1View bcxmax, BoundaryCondition ibcymin, - Rank1View bcymin, BoundaryCondition ibcymax, - Rank1View bcymax) { + ExplicitBiCubicSplineInterpolator( + Rank1View x, Rank1View y, + Rank1View values, BoundaryCondition ibcxmin, + Rank1View bcxmin, BoundaryCondition ibcxmax, + Rank1View bcxmax, BoundaryCondition ibcymin, + Rank1View bcymin, BoundaryCondition ibcymax, + Rank1View bcymax) +{ detail::grid_valid(x); detail::grid_valid(y); @@ -2780,7 +2856,7 @@ ExplicitBiCubicSplineInterpolator:: y_ = y; LO ny = y.extent(0); LO nx = x.extent(0); - Kokkos::View fspl_view("fspl view", 4 * 4 * nx * ny); + Kokkos::View fspl_view("fspl view", 4 * 4 * nx * ny); coefficients_ = fspl_view; auto fspl = get_coefficients_view(); InitExplicitBiCubicCoeffFunctor init_functor(fspl, values, @@ -2788,37 +2864,39 @@ ExplicitBiCubicSplineInterpolator:: Kokkos::parallel_for(Kokkos::MDRangePolicy>({0, 0}, {ny, nx}), init_functor); - Kokkos::View wk_view("wk", 9 * nx * ny); + Kokkos::View wk_view("wk", 9 * nx * ny); auto wk = Rank1View(wk_view.data(), 9 * nx * ny); detail::solve_bicubic_spline_explicit( - x, nx, y, ny, fspl, static_cast(ibcxmin), bcxmin, - static_cast(ibcxmax), bcxmax, static_cast(ibcymin), bcymin, - static_cast(ibcymax), bcymax, wk); + x, nx, y, ny, fspl, static_cast(ibcxmin), bcxmin, + static_cast(ibcxmax), bcxmax, static_cast(ibcymin), bcymin, + static_cast(ibcymax), bcymax, wk); } template ExplicitBiCubicSplineInterpolator:: - ExplicitBiCubicSplineInterpolator(Rank1View x, - Rank1View y, - Rank1View values) - : ExplicitBiCubicSplineInterpolator( - x, y, values, BoundaryCondition::NOT_A_KNOT, {}, - BoundaryCondition::NOT_A_KNOT, {}, BoundaryCondition::NOT_A_KNOT, {}, - BoundaryCondition::NOT_A_KNOT, {}) { + ExplicitBiCubicSplineInterpolator(Rank1View x, + Rank1View y, + Rank1View values) + : ExplicitBiCubicSplineInterpolator( + x, y, values, BoundaryCondition::NOT_A_KNOT, {}, + BoundaryCondition::NOT_A_KNOT, {}, BoundaryCondition::NOT_A_KNOT, {}, + BoundaryCondition::NOT_A_KNOT, {}) +{ std::cout << "Not a knot boundary condition is applied by default" << std::endl; } template CompactBiCubicSplineInterpolator:: - CompactBiCubicSplineInterpolator( - Rank1View x, Rank1View y, - Rank1View values, BoundaryCondition ibcxmin, - Rank1View bcxmin, BoundaryCondition ibcxmax, - Rank1View bcxmax, BoundaryCondition ibcymin, - Rank1View bcymin, BoundaryCondition ibcymax, - Rank1View bcymax) { + CompactBiCubicSplineInterpolator( + Rank1View x, Rank1View y, + Rank1View values, BoundaryCondition ibcxmin, + Rank1View bcxmin, BoundaryCondition ibcxmax, + Rank1View bcxmax, BoundaryCondition ibcymin, + Rank1View bcymin, BoundaryCondition ibcymax, + Rank1View bcymax) +{ detail::grid_valid(x); detail::grid_valid(y); @@ -2826,7 +2904,7 @@ CompactBiCubicSplineInterpolator:: y_ = y; LO ny = y.extent(0); LO nx = x.extent(0); - Kokkos::View fspl_view("fspl view", 4 * nx * ny); + Kokkos::View fspl_view("fspl view", 4 * nx * ny); coefficients_ = fspl_view; auto fspl = get_coefficients_view(); @@ -2834,24 +2912,25 @@ CompactBiCubicSplineInterpolator:: Kokkos::parallel_for(Kokkos::MDRangePolicy>({0, 0}, {ny, nx}), init_functor); - Kokkos::View wk_view("wk", 9 * nx * ny); + Kokkos::View wk_view("wk", 9 * nx * ny); auto wk = Rank1View(wk_view.data(), 9 * nx * ny); detail::solve_bicubic_spline_compact( - x, nx, y, ny, fspl, static_cast(ibcxmin), bcxmin, - static_cast(ibcxmax), bcxmax, static_cast(ibcymin), bcymin, - static_cast(ibcymax), bcymax, wk); + x, nx, y, ny, fspl, static_cast(ibcxmin), bcxmin, + static_cast(ibcxmax), bcxmax, static_cast(ibcymin), bcymin, + static_cast(ibcymax), bcymax, wk); } template CompactBiCubicSplineInterpolator:: - CompactBiCubicSplineInterpolator(Rank1View x, - Rank1View y, - Rank1View values) - : CompactBiCubicSplineInterpolator( - x, y, values, BoundaryCondition::NOT_A_KNOT, {}, - BoundaryCondition::NOT_A_KNOT, {}, BoundaryCondition::NOT_A_KNOT, {}, - BoundaryCondition::NOT_A_KNOT, {}) { + CompactBiCubicSplineInterpolator(Rank1View x, + Rank1View y, + Rank1View values) + : CompactBiCubicSplineInterpolator( + x, y, values, BoundaryCondition::NOT_A_KNOT, {}, + BoundaryCondition::NOT_A_KNOT, {}, BoundaryCondition::NOT_A_KNOT, {}, + BoundaryCondition::NOT_A_KNOT, {}) +{ std::cout << "Not a knot boundary condition is applied by default" << std::endl; } diff --git a/test/test_spline_interpolator.cpp b/test/test_spline_interpolator.cpp index 111e17d72..6a6b20ddc 100644 --- a/test/test_spline_interpolator.cpp +++ b/test/test_spline_interpolator.cpp @@ -10,62 +10,65 @@ using namespace pcms; using TestMemorySpace = Kokkos::DefaultExecutionSpace; -bool are_equal(double a, double b, double tolerance = 1e-7) { +bool are_equal(double a, double b, double tolerance = 1e-7) +{ return std::abs(a - b) < tolerance; } void createFlatGrid(Rank1View xvec, Rank1View yvec, - Kokkos::View X_flat, - Kokkos::View Y_flat) { + Kokkos::View X_flat, + Kokkos::View Y_flat) +{ size_t nx = xvec.size(); size_t ny = yvec.size(); Kokkos::parallel_for( - Kokkos::MDRangePolicy>({0, 0}, {ny, nx}), - KOKKOS_LAMBDA(const int i, const int j) { - size_t idx = i * nx + j; - X_flat[idx] = xvec[j]; - Y_flat[idx] = yvec[i]; - }); + Kokkos::MDRangePolicy>({0, 0}, {ny, nx}), + KOKKOS_LAMBDA(const int i, const int j) { + size_t idx = i * nx + j; + X_flat[idx] = xvec[j]; + Y_flat[idx] = yvec[i]; + }); } -void tset(int nth, Kokkos::View th, - Kokkos::View sth, - Kokkos::View cth, double thmin, - double thmax) { +void tset(int nth, Kokkos::View th, + Kokkos::View sth, + Kokkos::View cth, double thmin, + double thmax) +{ Kokkos::parallel_for( - Kokkos::RangePolicy(0, nth), - KOKKOS_LAMBDA(const int ith) { - th[ith] = thmin + static_cast(ith) * (thmax - thmin) / - static_cast(nth - 1); - sth[ith] = 2.0 + std::sin(th[ith]); - cth[ith] = std::cos(th[ith]); - }); + Kokkos::RangePolicy(0, nth), KOKKOS_LAMBDA(const int ith) { + th[ith] = thmin + static_cast(ith) * (thmax - thmin) / + static_cast(nth - 1); + sth[ith] = 2.0 + std::sin(th[ith]); + cth[ith] = std::cos(th[ith]); + }); } -void xset(int nx, Kokkos::View x, - Kokkos::View ex, double xmin, - double xmax) { +void xset(int nx, Kokkos::View x, + Kokkos::View ex, double xmin, double xmax) +{ if (nx < 2) return; // avoid division by zero Kokkos::parallel_for( - Kokkos::RangePolicy(0, nx), KOKKOS_LAMBDA(const int ix) { - x[ix] = xmin + static_cast(ix) * (xmax - xmin) / - static_cast(nx - 1); - ex[ix] = std::exp(2.0 * x[ix] - 1.0); - }); + Kokkos::RangePolicy(0, nx), KOKKOS_LAMBDA(const int ix) { + x[ix] = xmin + static_cast(ix) * (xmax - xmin) / + static_cast(nx - 1); + ex[ix] = std::exp(2.0 * x[ix] - 1.0); + }); } -void ffset(int num, Kokkos::View xf, - Kokkos::View tf, - Kokkos::View f) { +void ffset(int num, Kokkos::View xf, + Kokkos::View tf, + Kokkos::View f) +{ Kokkos::parallel_for( - Kokkos::MDRangePolicy>({0, 0}, {num, num}), - KOKKOS_LAMBDA(const int i, const int j) { - f(i * num + j) = xf[i] * tf[j]; - }); + Kokkos::MDRangePolicy>({0, 0}, {num, num}), + KOKKOS_LAMBDA(const int i, const int j) { + f(i * num + j) = xf[i] * tf[j]; + }); } void bset(Rank1View fx, int nx, @@ -73,47 +76,49 @@ void bset(Rank1View fx, int nx, Rank1View bcx1, Rank1View bcx2, Rank1View bcth1, - Rank1View bcth2) { + Rank1View bcth2) +{ Kokkos::parallel_for( - Kokkos::RangePolicy(0, nth), - KOKKOS_LAMBDA(const int ith) { - bcx1[ith] = 2.0 * fx(0) * fth(ith); // df/dx at x(1) - bcx2[ith] = 2.0 * fx(nx - 1) * fth(ith); // df/dx at x(nx) - }); + Kokkos::RangePolicy(0, nth), KOKKOS_LAMBDA(const int ith) { + bcx1[ith] = 2.0 * fx(0) * fth(ith); // df/dx at x(1) + bcx2[ith] = 2.0 * fx(nx - 1) * fth(ith); // df/dx at x(nx) + }); Kokkos::parallel_for( - Kokkos::RangePolicy(0, nx), KOKKOS_LAMBDA(const int ix) { - bcth1(ix) = fx(ix); // df/dth at th = 0 (th[0]) - bcth2(ix) = fx(ix); // df/dth at th = 2π (th[nth - 1]) - }); + Kokkos::RangePolicy(0, nx), KOKKOS_LAMBDA(const int ix) { + bcth1(ix) = fx(ix); // df/dth at th = 0 (th[0]) + bcth2(ix) = fx(ix); // df/dth at th = 2π (th[nth - 1]) + }); } void generate_gt_2d(Rank1View gt_splinv, Rank1View fxtest, - Rank1View fthtest, int ntest) { + Rank1View fthtest, int ntest) +{ Kokkos::parallel_for( - Kokkos::MDRangePolicy>({0, 0}, {ntest, ntest}), - KOKKOS_LAMBDA(const int j, const int i) { - gt_splinv(j * ntest + i) = fxtest(i) * fthtest(j); - }); + Kokkos::MDRangePolicy>({0, 0}, {ntest, ntest}), + KOKKOS_LAMBDA(const int j, const int i) { + gt_splinv(j * ntest + i) = fxtest(i) * fthtest(j); + }); } void compare(Rank2View splinv, Rank1View gt_splinv, - Rank1View res, std::string label) { + Rank1View res, std::string label) +{ // Compare the output of splinv with gt_splinv double result_fdif = 0.0; double result_fdifr = 0.0; Kokkos::parallel_reduce( - "compare_splinv", splinv.extent(0), - KOKKOS_LAMBDA(const int i, double &max_fdif, double &max_fdifr) { - if (splinv(i, 0) != 0.0) { - double dif = Kokkos::abs(splinv(i, 0) - gt_splinv(i)); - max_fdif = Kokkos::max(max_fdif, dif); - max_fdifr = Kokkos::max(max_fdifr, dif / gt_splinv(i)); - } - }, - Kokkos::Max(result_fdif), Kokkos::Max(result_fdifr)); + "compare_splinv", splinv.extent(0), + KOKKOS_LAMBDA(const int i, double& max_fdif, double& max_fdifr) { + if (splinv(i, 0) != 0.0) { + double dif = Kokkos::abs(splinv(i, 0) - gt_splinv(i)); + max_fdif = Kokkos::max(max_fdif, dif); + max_fdifr = Kokkos::max(max_fdifr, dif / gt_splinv(i)); + } + }, + Kokkos::Max(result_fdif), Kokkos::Max(result_fdifr)); res(0) = result_fdif; res(1) = result_fdifr; std::cout << "2d " << label << " max absolute difference: " << res(0) @@ -122,51 +127,54 @@ void compare(Rank2View splinv, void compare_2d(Rank2View splinv, Rank1View gt_splinv, - Rank1View res, std::string label) { + Rank1View res, std::string label) +{ // Compare the output of splinv with gt_splinv double result_fdif = 0.0; double result_fdifr = 0.0; Kokkos::parallel_reduce( - "compare_splinv", splinv.extent(0), - KOKKOS_LAMBDA(const int i, double &max_fdif, double &max_fdifr) { - if (splinv(i, 0) != 0.0) { - double dif = Kokkos::abs(splinv(i, 0) - gt_splinv(i)); - max_fdif = Kokkos::max(max_fdif, dif); - max_fdifr = Kokkos::max(max_fdifr, - dif / (0.5 * (splinv(i, 0) + gt_splinv(i)))); - } - }, - Kokkos::Max(result_fdif), Kokkos::Max(result_fdifr)); + "compare_splinv", splinv.extent(0), + KOKKOS_LAMBDA(const int i, double& max_fdif, double& max_fdifr) { + if (splinv(i, 0) != 0.0) { + double dif = Kokkos::abs(splinv(i, 0) - gt_splinv(i)); + max_fdif = Kokkos::max(max_fdif, dif); + max_fdifr = + Kokkos::max(max_fdifr, dif / (0.5 * (splinv(i, 0) + gt_splinv(i)))); + } + }, + Kokkos::Max(result_fdif), Kokkos::Max(result_fdifr)); res(0) = result_fdif; res(1) = result_fdifr; std::cout << "2d " << label << " max absolute difference: " << res(0) << ", relative difference: " << res(1) << std::endl; } -void reset_2dspan(Rank2View span) { +void reset_2dspan(Rank2View span) +{ Kokkos::parallel_for( - "zero_init", - Kokkos::MDRangePolicy>({0, 0}, - {span.extent(0), span.extent(1)}), - KOKKOS_LAMBDA(int i, int j) { span(i, j) = 0.0; }); + "zero_init", + Kokkos::MDRangePolicy>({0, 0}, + {span.extent(0), span.extent(1)}), + KOKKOS_LAMBDA(int i, int j) { span(i, j) = 0.0; }); } void dotest1(int ns, Rank1View x, Rank1View f, int nt, Rank1View xt, Rank1View ft, - Kokkos::View res_1d) { + Kokkos::View res_1d) +{ using std::data; using std::size; - Kokkos::View splinv_view("splinv_view", 3 * nt); + Kokkos::View splinv_view("splinv_view", 3 * nt); auto splinv = Rank2View(splinv_view.data(), nt, 3); reset_2dspan(splinv); // interpolator.cspline(x, ns, fspl, 1, 1, 1, 1, wk); ExplicitCubicSplineInterpolator - explicit_interpolator(x, f, BoundaryCondition::FIRST_DERIVATIVE_MATCH, 1, - BoundaryCondition::FIRST_DERIVATIVE_MATCH, 1); + explicit_interpolator(x, f, BoundaryCondition::FIRST_DERIVATIVE_MATCH, 1, + BoundaryCondition::FIRST_DERIVATIVE_MATCH, 1); explicit_interpolator.evaluate(xt, splinv); auto res1 = Rank1View(res_1d.data(), 2); @@ -174,8 +182,8 @@ void dotest1(int ns, Rank1View x, reset_2dspan(splinv); ExplicitCubicSplineInterpolator - explicit_interpolator_periodic(x, f, BoundaryCondition::PERIODIC, 0, - BoundaryCondition::PERIODIC, 0); + explicit_interpolator_periodic(x, f, BoundaryCondition::PERIODIC, 0, + BoundaryCondition::PERIODIC, 0); explicit_interpolator_periodic.evaluate(xt, splinv); auto res2 = Rank1View(res_1d.data() + 2, 2); @@ -183,26 +191,27 @@ void dotest1(int ns, Rank1View x, reset_2dspan(splinv); CompactCubicSplineInterpolator compact_interpolator( - x, f, BoundaryCondition::FIRST_DERIVATIVE_MATCH, 1, - BoundaryCondition::FIRST_DERIVATIVE_MATCH, 1); + x, f, BoundaryCondition::FIRST_DERIVATIVE_MATCH, 1, + BoundaryCondition::FIRST_DERIVATIVE_MATCH, 1); compact_interpolator.evaluate(xt, splinv); auto res3 = Rank1View(res_1d.data() + 4, 2); compare(splinv, ft, res3, "compact_cubic"); } -void pspltest1(Kokkos::View res_1d) { +void pspltest1(Kokkos::View res_1d) +{ const double pi2 = 6.28318530718; const double zero = 0.0; int inum = 10; // Local arrays - Kokkos::View zdum_view("zdum_view", 1000); - Kokkos::View xtest_view("xtest_view", 1000); - Kokkos::View ftest_view("ftest_view", 1000); - Kokkos::View x_view("x_view", 10); - Kokkos::View zcos_view("zcos_view", 10); - Kokkos::View z2sin_view("z2sin_view", 10); + Kokkos::View zdum_view("zdum_view", 1000); + Kokkos::View xtest_view("xtest_view", 1000); + Kokkos::View ftest_view("ftest_view", 1000); + Kokkos::View x_view("x_view", 10); + Kokkos::View zcos_view("zcos_view", 10); + Kokkos::View z2sin_view("z2sin_view", 10); // Prepare test data tset(1000, xtest_view, ftest_view, zdum_view, zero - 0.1, pi2 + 0.1); @@ -211,7 +220,7 @@ void pspltest1(Kokkos::View res_1d) { auto x = Rank1View(x_view.data(), x_view.size()); auto z2sin = - Rank1View(z2sin_view.data(), z2sin_view.size()); + Rank1View(z2sin_view.data(), z2sin_view.size()); auto xtest = Rank1View(xtest_view.data(), 1000); auto ftest = Rank1View(ftest_view.data(), 1000); @@ -234,43 +243,44 @@ void dotest2(Rank1View x, Rank1View fxtest, Rank1View thtest, Rank1View fthtest, int ntest, - Kokkos::View res_2d) { + Kokkos::View res_2d) +{ - Kokkos::View values_view("values_view", nth * nx); + Kokkos::View values_view("values_view", nth * nx); Kokkos::parallel_for( - Kokkos::MDRangePolicy>({0, 0}, {nth, nx}), - KOKKOS_LAMBDA(const int ith, const int ix) { - values_view(ix * nth + ith) = f(0, 0, ix, ith); - }); + Kokkos::MDRangePolicy>({0, 0}, {nth, nx}), + KOKKOS_LAMBDA(const int ith, const int ix) { + values_view(ix * nth + ith) = f(0, 0, ix, ith); + }); auto values = - Rank1View(values_view.data(), nth * nx); + Rank1View(values_view.data(), nth * nx); bset(fx, nx, fth, nth, bcx1, bcx2, bcth1, bcth2); - Kokkos::View splinv_view("splinv_view", 400000); + Kokkos::View splinv_view("splinv_view", 400000); auto splinv = - Rank2View(splinv_view.data(), 40000, 10); + Rank2View(splinv_view.data(), 40000, 10); reset_2dspan(splinv); - Kokkos::View xtest_grid_view("xtest_grid_view", + Kokkos::View xtest_grid_view("xtest_grid_view", + 40000); + Kokkos::View thtest_grid_view("thtest_grid_view", 40000); - Kokkos::View thtest_grid_view("thtest_grid_view", - 40000); createFlatGrid(xtest, thtest, xtest_grid_view, thtest_grid_view); auto xtest_grid = - Rank1View(xtest_grid_view.data(), 40000); + Rank1View(xtest_grid_view.data(), 40000); auto thtest_grid = - Rank1View(thtest_grid_view.data(), 40000); - Kokkos::View splinv_gt_view("splinv_view", 40000); + Rank1View(thtest_grid_view.data(), 40000); + Kokkos::View splinv_gt_view("splinv_view", 40000); auto splinv_gt = - Rank1View(splinv_gt_view.data(), 40000); + Rank1View(splinv_gt_view.data(), 40000); generate_gt_2d(splinv_gt, fxtest, fthtest, ntest); ExplicitBiCubicSplineInterpolator - explicit_interpolator(x, th, values, - BoundaryCondition::FIRST_DERIVATIVE_MATCH, bcx1, - BoundaryCondition::FIRST_DERIVATIVE_MATCH, bcx2, - BoundaryCondition::FIRST_DERIVATIVE_MATCH, bcth1, - BoundaryCondition::FIRST_DERIVATIVE_MATCH, bcth2); + explicit_interpolator(x, th, values, + BoundaryCondition::FIRST_DERIVATIVE_MATCH, bcx1, + BoundaryCondition::FIRST_DERIVATIVE_MATCH, bcx2, + BoundaryCondition::FIRST_DERIVATIVE_MATCH, bcth1, + BoundaryCondition::FIRST_DERIVATIVE_MATCH, bcth2); explicit_interpolator.evaluate(xtest_grid, thtest_grid, splinv); auto res1 = Rank1View(res_2d.data(), 2); @@ -278,11 +288,11 @@ void dotest2(Rank1View x, reset_2dspan(splinv); CompactBiCubicSplineInterpolator - compact_interpolator(x, th, values, - BoundaryCondition::FIRST_DERIVATIVE_MATCH, bcx1, - BoundaryCondition::FIRST_DERIVATIVE_MATCH, bcx2, - BoundaryCondition::FIRST_DERIVATIVE_MATCH, bcth1, - BoundaryCondition::FIRST_DERIVATIVE_MATCH, bcth2); + compact_interpolator(x, th, values, + BoundaryCondition::FIRST_DERIVATIVE_MATCH, bcx1, + BoundaryCondition::FIRST_DERIVATIVE_MATCH, bcx2, + BoundaryCondition::FIRST_DERIVATIVE_MATCH, bcth1, + BoundaryCondition::FIRST_DERIVATIVE_MATCH, bcth2); compact_interpolator.evaluate(xtest_grid, thtest_grid, splinv); auto res2 = Rank1View(res_2d.data() + 2, 2); @@ -292,26 +302,27 @@ void dotest2(Rank1View x, // test_interpolator(x, th, values); } -void pspltest2(Kokkos::View res_2d) { +void pspltest2(Kokkos::View res_2d) +{ const double pi2 = 6.28318530718; const double zero = 0.0; const double one = 1.0; - Kokkos::View x1_view("x1_view", 10); - Kokkos::View ex1_view("ex1_view", 10); - Kokkos::View t1_view("t1_view", 10); - Kokkos::View st1_view("st1_view", 10); - Kokkos::View ct1_view("ct1_view", 10); - Kokkos::View xtest_view("xtest_view", 200); - Kokkos::View extest_view("extest_view", 200); - Kokkos::View ttest_view("ttest_view", 200); - Kokkos::View stest_view("stest_view", 200); - Kokkos::View ctest_view("ctest_view", 200); - Kokkos::View f1_view("f1_view", 1600); - Kokkos::View bcx1_view("bcx1_view", 40); - Kokkos::View bcx2_view("bcx2_view", 40); - Kokkos::View bcth1_view("bcth1_view", 40); - Kokkos::View bcth2_view("bcth2_view", 40); + Kokkos::View x1_view("x1_view", 10); + Kokkos::View ex1_view("ex1_view", 10); + Kokkos::View t1_view("t1_view", 10); + Kokkos::View st1_view("st1_view", 10); + Kokkos::View ct1_view("ct1_view", 10); + Kokkos::View xtest_view("xtest_view", 200); + Kokkos::View extest_view("extest_view", 200); + Kokkos::View ttest_view("ttest_view", 200); + Kokkos::View stest_view("stest_view", 200); + Kokkos::View ctest_view("ctest_view", 200); + Kokkos::View f1_view("f1_view", 1600); + Kokkos::View bcx1_view("bcx1_view", 40); + Kokkos::View bcx2_view("bcx2_view", 40); + Kokkos::View bcth1_view("bcth1_view", 40); + Kokkos::View bcth2_view("bcth2_view", 40); xset(10, x1_view, ex1_view, zero, one); xset(200, xtest_view, extest_view, zero, one); @@ -323,43 +334,44 @@ void pspltest2(Kokkos::View res_2d) { auto x1 = Rank1View(x1_view.data(), x1_view.size()); auto ex1 = - Rank1View(ex1_view.data(), ex1_view.size()); + Rank1View(ex1_view.data(), ex1_view.size()); auto t1 = Rank1View(t1_view.data(), t1_view.size()); auto st1 = - Rank1View(st1_view.data(), st1_view.size()); + Rank1View(st1_view.data(), st1_view.size()); auto ct1 = - Rank1View(ct1_view.data(), ct1_view.size()); + Rank1View(ct1_view.data(), ct1_view.size()); auto f1 = Rank4View(f1_view.data(), Kokkos::extents{4, 4, 10, 10}); auto bcx1 = - Rank1View(bcx1_view.data(), bcx1_view.size()); + Rank1View(bcx1_view.data(), bcx1_view.size()); auto bcx2 = - Rank1View(bcx2_view.data(), bcx2_view.size()); + Rank1View(bcx2_view.data(), bcx2_view.size()); auto bcth1 = - Rank1View(bcth1_view.data(), bcth1_view.size()); + Rank1View(bcth1_view.data(), bcth1_view.size()); auto bcth2 = - Rank1View(bcth2_view.data(), bcth2_view.size()); + Rank1View(bcth2_view.data(), bcth2_view.size()); auto xtest = - Rank1View(xtest_view.data(), xtest_view.size()); - auto extest = Rank1View(extest_view.data(), - extest_view.size()); + Rank1View(xtest_view.data(), xtest_view.size()); + auto extest = + Rank1View(extest_view.data(), extest_view.size()); auto ttest = - Rank1View(ttest_view.data(), ttest_view.size()); + Rank1View(ttest_view.data(), ttest_view.size()); auto stest = - Rank1View(stest_view.data(), stest_view.size()); + Rank1View(stest_view.data(), stest_view.size()); dotest2(x1, ex1, 10, t1, st1, ct1, 10, f1, bcx1, bcx2, bcth1, bcth2, xtest, extest, ttest, stest, 200, res_2d); } -TEST_CASE("test_cubic_spline_interpolator") { +TEST_CASE("test_cubic_spline_interpolator") +{ Kokkos::print_configuration(std::cout); std::cout << "DefaultExecutionSpace: " << Kokkos::DefaultExecutionSpace::name() << std::endl; Kokkos::Timer timer; { - Kokkos::View res_1d("res_1d", 6); + Kokkos::View res_1d("res_1d", 6); double gt_1d[6] = {6.7572E-04, 6.6529E-04, 6.8669E-04, 6.7622E-04, 6.7572E-04, 6.6529E-04}; pspltest1(res_1d); @@ -367,7 +379,7 @@ TEST_CASE("test_cubic_spline_interpolator") { REQUIRE(are_equal(res_1d(i), gt_1d[i])); } - Kokkos::View res_2d("res_2d", 4); + Kokkos::View res_2d("res_2d", 4); double gt_2d[4] = {1.8312E-03, 6.7151E-04, 1.8312E-03, 6.7151E-04}; pspltest2(res_2d); for (int i = 0; i < 4; ++i) { From d13121d2018d7e479f0b71f5f71c1e3baf1292c1 Mon Sep 17 00:00:00 2001 From: Sichao25 Date: Thu, 25 Sep 2025 17:22:59 -0400 Subject: [PATCH 18/18] include iostream --- src/pcms/interpolator/spline_interpolator.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/pcms/interpolator/spline_interpolator.hpp b/src/pcms/interpolator/spline_interpolator.hpp index fb4f06e23..d431d8307 100644 --- a/src/pcms/interpolator/spline_interpolator.hpp +++ b/src/pcms/interpolator/spline_interpolator.hpp @@ -8,6 +8,7 @@ #include "pcms/types.h" #include #include +#include namespace pcms { @@ -2936,4 +2937,4 @@ CompactBiCubicSplineInterpolator:: } } // namespace pcms -#endif \ No newline at end of file +#endif