From 31cac54fcbe3f789e86915a2baba263fb7510877 Mon Sep 17 00:00:00 2001 From: Thomas Padioleau Date: Thu, 18 Jan 2024 14:16:39 +0000 Subject: [PATCH] Synchronize DDC --- .../spline_interpolator_batched.hpp | 2 +- vendor/ddc/benchmarks/splines.cpp | 2 +- .../examples/characteristics_advection.cpp | 2 +- vendor/ddc/include/ddc/chunk_common.hpp | 2 +- vendor/ddc/include/ddc/kernels/splines.hpp | 3 + .../kernels/splines/bsplines_non_uniform.hpp | 5 +- .../ddc/kernels/splines/bsplines_uniform.hpp | 5 +- .../ddc/include/ddc/kernels/splines/deriv.hpp | 10 + .../ddc/kernels/splines/matrix_sparse.hpp | 2 +- .../ddc/kernels/splines/spline_builder.hpp | 9 +- .../splines/spline_builder_2d_batched.hpp | 279 +++++++ .../splines/spline_builder_batched.hpp | 104 ++- .../splines/spline_evaluator_2d_batched.hpp | 502 ++++++++++++ .../splines/spline_evaluator_batched.hpp | 14 +- vendor/ddc/include/ddc/pdi.hpp | 8 +- vendor/ddc/tests/splines/CMakeLists.txt | 69 +- .../splines/batched_2d_spline_builder.cpp | 761 ++++++++++++++++++ .../tests/splines/batched_spline_builder.cpp | 229 ++++-- vendor/ddc/tests/splines/evaluator_2d.hpp | 85 ++ .../splines/non_periodic_spline_builder.cpp | 189 +++++ .../tests/splines/periodic_spline_builder.cpp | 2 +- .../splines/periodicity_spline_builder.cpp | 6 +- .../tests/splines/polynomial_evaluator.hpp | 15 +- 23 files changed, 2187 insertions(+), 118 deletions(-) create mode 100644 vendor/ddc/include/ddc/kernels/splines/deriv.hpp create mode 100644 vendor/ddc/include/ddc/kernels/splines/spline_builder_2d_batched.hpp create mode 100644 vendor/ddc/include/ddc/kernels/splines/spline_evaluator_2d_batched.hpp create mode 100644 vendor/ddc/tests/splines/batched_2d_spline_builder.cpp create mode 100644 vendor/ddc/tests/splines/evaluator_2d.hpp create mode 100644 vendor/ddc/tests/splines/non_periodic_spline_builder.cpp diff --git a/src/interpolation/spline_interpolator_batched.hpp b/src/interpolation/spline_interpolator_batched.hpp index 09390bef2..b34966d44 100644 --- a/src/interpolation/spline_interpolator_batched.hpp +++ b/src/interpolation/spline_interpolator_batched.hpp @@ -87,7 +87,7 @@ class SplineInterpolatorBatched : public IInterpolatorBatched derivs_max = ddc::CDSpan1D(m_derivs_max_alloc.data(), m_derivs_max_alloc.size()); } // m_builder(m_coefs.span_view(), inout_data, derivs_min, derivs_max); - m_builder(m_coefs.span_view(), inout_data); + m_builder(m_coefs.span_view(), inout_data.span_cview()); m_evaluator(inout_data, coordinates, m_coefs.span_cview()); return inout_data; } diff --git a/vendor/ddc/benchmarks/splines.cpp b/vendor/ddc/benchmarks/splines.cpp index 810f0bceb..501dbf6ed 100644 --- a/vendor/ddc/benchmarks/splines.cpp +++ b/vendor/ddc/benchmarks/splines.cpp @@ -148,7 +148,7 @@ static void characteristics_advection(benchmark::State& state) }); Kokkos::Profiling::popRegion(); Kokkos::Profiling::pushRegion("SplineBuilder"); - spline_builder(coef, density); + spline_builder(coef, density.span_cview()); Kokkos::Profiling::popRegion(); Kokkos::Profiling::pushRegion("SplineEvaluator"); spline_evaluator(density, feet_coords.span_cview(), coef.span_cview()); diff --git a/vendor/ddc/examples/characteristics_advection.cpp b/vendor/ddc/examples/characteristics_advection.cpp index 693c266ca..36fb29870 100644 --- a/vendor/ddc/examples/characteristics_advection.cpp +++ b/vendor/ddc/examples/characteristics_advection.cpp @@ -271,7 +271,7 @@ int main(int argc, char** argv) vx * ddc::step()); }); // Interpolate the values at feets on the grid - spline_builder(coef, last_density); + spline_builder(coef, last_density.span_cview()); spline_evaluator( next_density, feet_coords.span_cview(), diff --git a/vendor/ddc/include/ddc/chunk_common.hpp b/vendor/ddc/include/ddc/chunk_common.hpp index 6b91ddf22..00e22ba0f 100644 --- a/vendor/ddc/include/ddc/chunk_common.hpp +++ b/vendor/ddc/include/ddc/chunk_common.hpp @@ -59,7 +59,7 @@ inline constexpr bool is_writable_chunk_v * @return the domain of view in the queried dimensions */ template -auto get_domain(ChunkType const& chunk) noexcept +KOKKOS_FUNCTION auto get_domain(ChunkType const& chunk) noexcept { static_assert(is_chunk_v, "Not a chunk span type"); return chunk.template domain(); diff --git a/vendor/ddc/include/ddc/kernels/splines.hpp b/vendor/ddc/include/ddc/kernels/splines.hpp index e58374a54..bac9e0315 100644 --- a/vendor/ddc/include/ddc/kernels/splines.hpp +++ b/vendor/ddc/include/ddc/kernels/splines.hpp @@ -3,6 +3,7 @@ #include "splines/bspline.hpp" #include "splines/bsplines_non_uniform.hpp" #include "splines/bsplines_uniform.hpp" +#include "splines/deriv.hpp" #include "splines/greville_interpolation_points.hpp" #include "splines/knots_as_interpolation_points.hpp" #include "splines/math_tools.hpp" @@ -13,7 +14,9 @@ #include "splines/spline_boundary_conditions.hpp" #include "splines/spline_boundary_value.hpp" #include "splines/spline_builder.hpp" +#include "splines/spline_builder_2d_batched.hpp" #include "splines/spline_builder_batched.hpp" #include "splines/spline_evaluator.hpp" +#include "splines/spline_evaluator_2d_batched.hpp" #include "splines/spline_evaluator_batched.hpp" #include "splines/view.hpp" diff --git a/vendor/ddc/include/ddc/kernels/splines/bsplines_non_uniform.hpp b/vendor/ddc/include/ddc/kernels/splines/bsplines_non_uniform.hpp index d17b878e8..24c1848c4 100644 --- a/vendor/ddc/include/ddc/kernels/splines/bsplines_non_uniform.hpp +++ b/vendor/ddc/include/ddc/kernels/splines/bsplines_non_uniform.hpp @@ -449,7 +449,10 @@ KOKKOS_INLINE_FUNCTION ddc::DiscreteElement> NonUnifo d += a(k, s2) * ndu(pk, r); } derivs(r, k) = d; - std::swap(s1, s2); + // swap s1 <-> s2; + auto tmp = s1; + s1 = s2; + s2 = tmp; } } diff --git a/vendor/ddc/include/ddc/kernels/splines/bsplines_uniform.hpp b/vendor/ddc/include/ddc/kernels/splines/bsplines_uniform.hpp index b901e6554..2f8a4fee8 100644 --- a/vendor/ddc/include/ddc/kernels/splines/bsplines_uniform.hpp +++ b/vendor/ddc/include/ddc/kernels/splines/bsplines_uniform.hpp @@ -377,7 +377,10 @@ KOKKOS_INLINE_FUNCTION ddc::DiscreteElement> UniformBSpl d += a(k, s2) * ndu(pk, r); } derivs(r, k) = d; - std::swap(s1, s2); + // swap s1 <-> s2 + auto tmp = s1; + s1 = s2; + s2 = tmp; } } diff --git a/vendor/ddc/include/ddc/kernels/splines/deriv.hpp b/vendor/ddc/include/ddc/kernels/splines/deriv.hpp new file mode 100644 index 000000000..c864b5efa --- /dev/null +++ b/vendor/ddc/include/ddc/kernels/splines/deriv.hpp @@ -0,0 +1,10 @@ +#pragma once + +namespace ddc { + +template +struct Deriv +{ +}; + +} // namespace ddc diff --git a/vendor/ddc/include/ddc/kernels/splines/matrix_sparse.hpp b/vendor/ddc/include/ddc/kernels/splines/matrix_sparse.hpp index eab26aa87..3a79b2f38 100644 --- a/vendor/ddc/include/ddc/kernels/splines/matrix_sparse.hpp +++ b/vendor/ddc/include/ddc/kernels/splines/matrix_sparse.hpp @@ -148,7 +148,7 @@ class Matrix_Sparse : public Matrix std::shared_ptr const gko_exec = m_matrix_sparse->get_executor(); // Create the solver factory std::shared_ptr const residual_criterion - = gko::stop::ResidualNorm::build().with_reduction_factor(1e-20).on( + = gko::stop::ResidualNorm::build().with_reduction_factor(1e-19).on( gko_exec); std::shared_ptr const iterations_criterion diff --git a/vendor/ddc/include/ddc/kernels/splines/spline_builder.hpp b/vendor/ddc/include/ddc/kernels/splines/spline_builder.hpp index 2a524d851..7ff2e4c6c 100644 --- a/vendor/ddc/include/ddc/kernels/splines/spline_builder.hpp +++ b/vendor/ddc/include/ddc/kernels/splines/spline_builder.hpp @@ -128,7 +128,7 @@ class SplineBuilder template void operator()( ddc::ChunkSpan, Layout, MemorySpace> spline, - ddc::ChunkSpan vals, + ddc::ChunkSpan vals, std::optional const derivs_xmin = std::nullopt, std::optional const derivs_xmax = std::nullopt) const; @@ -137,6 +137,11 @@ class SplineBuilder return m_interpolation_domain; } + double dx() const noexcept + { + return m_dx; + } + int offset() const noexcept { return m_offset; @@ -271,7 +276,7 @@ void SplineBuilder< Solver>:: operator()( ddc::ChunkSpan, Layout, MemorySpace> spline, - ddc::ChunkSpan vals, + ddc::ChunkSpan vals, [[maybe_unused]] std::optional const derivs_xmin, [[maybe_unused]] std::optional const derivs_xmax) const { diff --git a/vendor/ddc/include/ddc/kernels/splines/spline_builder_2d_batched.hpp b/vendor/ddc/include/ddc/kernels/splines/spline_builder_2d_batched.hpp new file mode 100644 index 000000000..73e839c77 --- /dev/null +++ b/vendor/ddc/include/ddc/kernels/splines/spline_builder_2d_batched.hpp @@ -0,0 +1,279 @@ +#pragma once + +#include "spline_builder.hpp" +#include "spline_builder_batched.hpp" + +namespace ddc { + +template < + class ExecSpace, + class MemorySpace, + class BSpline1, + class BSpline2, + class IDimI1, + class IDimI2, + ddc::BoundCond BcXmin1, + ddc::BoundCond BcXmax1, + ddc::BoundCond BcXmin2, + ddc::BoundCond BcXmax2, + class... IDimX> +class SplineBuilder2DBatched +{ +public: + using exec_space = ExecSpace; + + using memory_space = MemorySpace; + + using builder_type1 = ddc::SplineBuilderBatched< + ddc::SplineBuilder, + IDimX...>; + using builder_type2 = ddc::SplineBuilderBatched< + ddc::SplineBuilder, + std::conditional_t, BSpline1, IDimX>...>; + using builder_deriv_type1 = ddc::SplineBuilderBatched< + ddc::SplineBuilder, + std::conditional_t< + std::is_same_v, + typename builder_type2::deriv_type, + IDimX>...>; + +private: + using tag_type1 = typename builder_type1::bsplines_type::tag_type; + using tag_type2 = typename builder_type2::bsplines_type::tag_type; + +public: + using bsplines_type1 = typename builder_type1::bsplines_type; + using bsplines_type2 = typename builder_type2::bsplines_type; + + using deriv_type1 = typename builder_type1::deriv_type; + using deriv_type2 = typename builder_type2::deriv_type; + + using interpolation_mesh_type1 = typename builder_type1::interpolation_mesh_type; + using interpolation_mesh_type2 = typename builder_type2::interpolation_mesh_type; + + using interpolation_domain_type1 = typename builder_type1::interpolation_mesh_type; + using interpolation_domain_type2 = typename builder_type2::interpolation_mesh_type; + using interpolation_domain_type + = ddc::DiscreteDomain; + + using vals_domain_type = ddc::DiscreteDomain; + + using batch_domain_type + = ddc::detail::convert_type_seq_to_discrete_domain, + ddc::detail::TypeSeq>>; + + using spline_domain_type + = ddc::detail::convert_type_seq_to_discrete_domain, + ddc::detail::TypeSeq, + ddc::detail::TypeSeq>>; + + using derivs_domain_type1 = typename builder_type1::derivs_domain_type; + using derivs_domain_type2 + = ddc::detail::convert_type_seq_to_discrete_domain, + ddc::detail::TypeSeq, + ddc::detail::TypeSeq>>; + using derivs_domain_type + = ddc::detail::convert_type_seq_to_discrete_domain, + ddc::detail::TypeSeq, + ddc::detail::TypeSeq>>; + +private: + builder_type1 m_spline_builder1; + builder_deriv_type1 m_spline_builder_deriv1; + builder_type2 m_spline_builder2; + +public: + explicit SplineBuilder2DBatched( + vals_domain_type const& vals_domain, + std::optional cols_per_chunk = std::nullopt, + std::optional preconditionner_max_block_size = std::nullopt) + : m_spline_builder1(vals_domain, cols_per_chunk, preconditionner_max_block_size) + , m_spline_builder_deriv1(ddc::replace_dim_of( + m_spline_builder1.vals_domain(), + ddc::DiscreteDomain( + ddc::DiscreteElement(1), + ddc::DiscreteVector(bsplines_type2::degree() / 2)))) + , m_spline_builder2( + m_spline_builder1.spline_domain(), + cols_per_chunk, + preconditionner_max_block_size) + { + } + + SplineBuilder2DBatched(SplineBuilder2DBatched const& x) = delete; + + SplineBuilder2DBatched(SplineBuilder2DBatched&& x) = default; + + ~SplineBuilder2DBatched() = default; + + SplineBuilder2DBatched& operator=(SplineBuilder2DBatched const& x) = delete; + + SplineBuilder2DBatched& operator=(SplineBuilder2DBatched&& x) = default; + + vals_domain_type vals_domain() const noexcept + { + return m_spline_builder1.vals_domain(); + } + + interpolation_domain_type interpolation_domain() const noexcept + { + return ddc::DiscreteDomain( + m_spline_builder1.interpolation_domain(), + m_spline_builder2.interpolation_domain()); + } + + batch_domain_type batch_domain() const noexcept + { + return ddc::remove_dims_of(vals_domain(), interpolation_domain()); + } + + ddc::DiscreteDomain bsplines_domain() + const noexcept // TODO : clarify name + { + return ddc::DiscreteDomain( + ddc::discrete_space().full_domain(), + ddc::discrete_space().full_domain()); + } + + spline_domain_type spline_domain() const noexcept + { + return ddc::replace_dim_of( + ddc::replace_dim_of< + interpolation_mesh_type2, + bsplines_type2>(vals_domain(), bsplines_domain()), + bsplines_domain()); + } + + template + void operator()( + ddc::ChunkSpan spline, + ddc::ChunkSpan vals, + std::optional< + ddc::ChunkSpan> const + derivs_min1 + = std::nullopt, + std::optional< + ddc::ChunkSpan> const + derivs_max1 + = std::nullopt, + std::optional< + ddc::ChunkSpan> const + derivs_min2 + = std::nullopt, + std::optional< + ddc::ChunkSpan> const + derivs_max2 + = std::nullopt, + std::optional< + ddc::ChunkSpan> const + mixed_derivs_min1_min2 + = std::nullopt, + std::optional< + ddc::ChunkSpan> const + mixed_derivs_max1_min2 + = std::nullopt, + std::optional< + ddc::ChunkSpan> const + mixed_derivs_min1_max2 + = std::nullopt, + std::optional< + ddc::ChunkSpan> const + mixed_derivs_max1_max2 + = std::nullopt) const; +}; + + +template < + class ExecSpace, + class MemorySpace, + class BSpline1, + class BSpline2, + class IDimI1, + class IDimI2, + ddc::BoundCond BcXmin1, + ddc::BoundCond BcXmax1, + ddc::BoundCond BcXmin2, + ddc::BoundCond BcXmax2, + class... IDimX> +template +void SplineBuilder2DBatched< + ExecSpace, + MemorySpace, + BSpline1, + BSpline2, + IDimI1, + IDimI2, + BcXmin1, + BcXmax1, + BcXmin2, + BcXmax2, + IDimX...>:: +operator()( + ddc::ChunkSpan spline, + ddc::ChunkSpan vals, + std::optional> const + derivs_min1, + std::optional> const + derivs_max1, + std::optional> const + derivs_min2, + std::optional> const + derivs_max2, + std::optional> const + mixed_derivs_min1_min2, + std::optional> const + mixed_derivs_max1_min2, + std::optional> const + mixed_derivs_min1_max2, + std::optional> const + mixed_derivs_max1_max2) const +{ + // TODO: perform computations along dimension 1 on different streams ? + // Spline1-transform derivs_min2 (to spline1_deriv_min) + ddc::Chunk spline1_deriv_min_alloc( + m_spline_builder_deriv1.spline_domain(), + ddc::KokkosAllocator()); + auto spline1_deriv_min = spline1_deriv_min_alloc.span_view(); + auto spline1_deriv_min_opt = std::optional(spline1_deriv_min.span_cview()); + if constexpr (BcXmin1 == ddc::BoundCond::HERMITE) { + m_spline_builder_deriv1( + spline1_deriv_min, + *derivs_min2, + mixed_derivs_min1_min2, + mixed_derivs_max1_min2); + } else { + spline1_deriv_min_opt = std::nullopt; + } + + // Spline1-transform vals (to spline1) + ddc::Chunk spline1_alloc( + m_spline_builder1.spline_domain(), + ddc::KokkosAllocator()); + ddc::ChunkSpan spline1 = spline1_alloc.span_view(); + + m_spline_builder1(spline1, vals, derivs_min1, derivs_max1); + + // Spline1-transform derivs_max2 (to spline1_deriv_max) + ddc::Chunk spline1_deriv_max_alloc( + m_spline_builder_deriv1.spline_domain(), + ddc::KokkosAllocator()); + auto spline1_deriv_max = spline1_deriv_max_alloc.span_view(); + auto spline1_deriv_max_opt = std::optional(spline1_deriv_max.span_cview()); + if constexpr (BcXmax1 == ddc::BoundCond::HERMITE) { + m_spline_builder_deriv1( + spline1_deriv_max, + *derivs_max2, + mixed_derivs_min1_max2, + mixed_derivs_max1_max2); + } else { + spline1_deriv_max_opt = std::nullopt; + } + + // Spline2-transform spline1 + m_spline_builder2(spline, spline1.span_cview(), spline1_deriv_min_opt, spline1_deriv_max_opt); +} +} // namespace ddc diff --git a/vendor/ddc/include/ddc/kernels/splines/spline_builder_batched.hpp b/vendor/ddc/include/ddc/kernels/splines/spline_builder_batched.hpp index 0578be1dd..12f1771c5 100644 --- a/vendor/ddc/include/ddc/kernels/splines/spline_builder_batched.hpp +++ b/vendor/ddc/include/ddc/kernels/splines/spline_builder_batched.hpp @@ -4,6 +4,7 @@ #include "ddc/discrete_domain.hpp" #include "ddc/kokkos_allocator.hpp" +#include "deriv.hpp" #include "spline_builder.hpp" namespace ddc { @@ -20,6 +21,8 @@ class SplineBuilderBatched using bsplines_type = typename SplineBuilder::bsplines_type; + using deriv_type = ddc::Deriv; + using builder_type = SplineBuilder; using interpolation_mesh_type = typename SplineBuilder::mesh_type; @@ -50,15 +53,24 @@ class SplineBuilderBatched ddc::detail::TypeSeq, ddc::detail::TypeSeq>>>; + using derivs_domain_type = + typename ddc::detail::convert_type_seq_to_discrete_domain, + ddc::detail::TypeSeq, + ddc::detail::TypeSeq>>; + static constexpr ddc::BoundCond BcXmin = SplineBuilder::s_bc_xmin; static constexpr ddc::BoundCond BcXmax = SplineBuilder::s_bc_xmax; + static constexpr int s_nbc_xmin = builder_type::s_nbc_xmin; + static constexpr int s_nbc_xmax = builder_type::s_nbc_xmax; + private: builder_type spline_builder; const vals_domain_type m_vals_domain; public: - SplineBuilderBatched( + explicit SplineBuilderBatched( vals_domain_type const& vals_domain, std::optional cols_per_chunk = std::nullopt, std::optional preconditionner_max_block_size = std::nullopt) @@ -69,10 +81,9 @@ class SplineBuilderBatched , m_vals_domain(vals_domain) { static_assert( - BcXmin == BoundCond::PERIODIC && BcXmax == BoundCond::PERIODIC, - "Boundary conditions other than PERIODIC are not supported yet in " - "SpSplineBuilderBatched"); - }; + ((BcXmin == BoundCond::PERIODIC) == (BcXmax == BoundCond::PERIODIC)), + "Incompatible boundary conditions"); + } SplineBuilderBatched(SplineBuilderBatched const& x) = delete; @@ -84,34 +95,34 @@ class SplineBuilderBatched SplineBuilderBatched& operator=(SplineBuilderBatched&& x) = default; - vals_domain_type const vals_domain() const noexcept + vals_domain_type vals_domain() const noexcept { return m_vals_domain; } - interpolation_domain_type const interpolation_domain() const noexcept + interpolation_domain_type interpolation_domain() const noexcept { return spline_builder.interpolation_domain(); } - batch_domain_type const batch_domain() const noexcept + batch_domain_type batch_domain() const noexcept { return ddc::remove_dims_of(vals_domain(), interpolation_domain()); } - ddc::DiscreteDomain const bsplines_domain() const noexcept // TODO : clarify name + ddc::DiscreteDomain bsplines_domain() const noexcept // TODO : clarify name { return ddc::discrete_space().full_domain(); } - spline_domain_type const spline_domain() const noexcept + spline_domain_type spline_domain() const noexcept { return ddc::replace_dim_of< interpolation_mesh_type, bsplines_type>(vals_domain(), bsplines_domain()); } - spline_tr_domain_type const spline_tr_domain() const noexcept + spline_tr_domain_type spline_tr_domain() const noexcept { return spline_tr_domain_type(bsplines_domain(), batch_domain()); } @@ -124,16 +135,65 @@ class SplineBuilderBatched template void operator()( ddc::ChunkSpan spline, - ddc::ChunkSpan vals) const; + ddc::ChunkSpan vals, + std::optional< + ddc::ChunkSpan> const + derivs_xmin + = std::nullopt, + std::optional< + ddc::ChunkSpan> const + derivs_xmax + = std::nullopt) const; }; template template void SplineBuilderBatched::operator()( ddc::ChunkSpan spline, - ddc::ChunkSpan vals) const + ddc::ChunkSpan vals, + std::optional> const + derivs_xmin, + std::optional> const + derivs_xmax) const { + assert(vals.template extent() + == ddc::discrete_space().nbasis() - spline_builder.s_nbe_xmin + - spline_builder.s_nbe_xmax); + + const bool odd = spline_builder.s_odd; + const std::size_t nbc_xmin = spline_builder.s_nbc_xmin; + const std::size_t nbc_xmax = spline_builder.s_nbc_xmax; + + assert((BcXmin == ddc::BoundCond::HERMITE) + != (!derivs_xmin.has_value() || derivs_xmin->template extent() == 0)); + assert((BcXmax == ddc::BoundCond::HERMITE) + != (!derivs_xmax.has_value() || derivs_xmax->template extent() == 0)); + if constexpr (BcXmin == BoundCond::HERMITE) { + assert(ddc::DiscreteElement(derivs_xmin->domain().front()).uid() == 1); + } + if constexpr (BcXmax == BoundCond::HERMITE) { + assert(ddc::DiscreteElement(derivs_xmax->domain().front()).uid() == 1); + } + + // Hermite boundary conditions at xmin, if any + // NOTE: For consistency with the linear system, the i-th derivative + // provided by the user must be multiplied by dx^i + if constexpr (BcXmin == BoundCond::HERMITE) { + assert(derivs_xmin->template extent() == nbc_xmin); + auto derivs_xmin_values = *derivs_xmin; + auto const dx_proxy = spline_builder.dx(); + ddc::for_each( + ddc::policies::policy(exec_space()), + batch_domain(), + KOKKOS_LAMBDA(typename batch_domain_type::discrete_element_type j) { + for (int i = nbc_xmin; i > 0; --i) { + spline(ddc::DiscreteElement(nbc_xmin - i), j) + = derivs_xmin_values(ddc::DiscreteElement(i), j) + * ddc::detail::ipow(dx_proxy, i + odd - 1); + } + }); + } // TODO : Consider optimizing // Fill spline with vals (to work in spline afterward and preserve vals) @@ -152,6 +212,24 @@ void SplineBuilderBatched::operator()( = vals(ddc::DiscreteElement(i), j); } }); + // Hermite boundary conditions at xmax, if any + // NOTE: For consistency with the linear system, the i-th derivative + // provided by the user must be multiplied by dx^i + if constexpr (BcXmax == BoundCond::HERMITE) { + assert(derivs_xmax->template extent() == nbc_xmax); + auto derivs_xmax_values = *derivs_xmax; + auto const dx_proxy = spline_builder.dx(); + ddc::for_each( + ddc::policies::policy(exec_space()), + batch_domain(), + KOKKOS_LAMBDA(typename batch_domain_type::discrete_element_type j) { + for (int i = 0; i < nbc_xmax; ++i) { + spline(ddc::DiscreteElement(nbasis_proxy - nbc_xmax - i), j) + = derivs_xmax_values(ddc::DiscreteElement(i + 1), j) + * ddc::detail::ipow(dx_proxy, i + odd); + } + }); + } // TODO : Consider optimizing // Allocate and fill a transposed version of spline in order to get dimension of interest as last dimension (optimal for GPU, necessary for Ginkgo) diff --git a/vendor/ddc/include/ddc/kernels/splines/spline_evaluator_2d_batched.hpp b/vendor/ddc/include/ddc/kernels/splines/spline_evaluator_2d_batched.hpp new file mode 100644 index 000000000..822b8862e --- /dev/null +++ b/vendor/ddc/include/ddc/kernels/splines/spline_evaluator_2d_batched.hpp @@ -0,0 +1,502 @@ +#pragma once + +#include + +#include + +#include "Kokkos_Macros.hpp" +#include "spline_boundary_value.hpp" +#include "spline_evaluator.hpp" +#include "view.hpp" + +namespace ddc { + +template < + class ExecSpace, + class MemorySpace, + class BSplinesType1, + class BSplinesType2, + class interpolation_mesh_type1, + class interpolation_mesh_type2, + class... IDimX> +class SplineEvaluator2DBatched +{ +private: + // Tags to determine what to evaluate + struct eval_type + { + }; + + struct eval_deriv_type + { + }; + +public: + using exec_space = ExecSpace; + + using memory_space = MemorySpace; + + using evaluator_type1 + = ddc::SplineEvaluator; + using evaluator_type2 + = ddc::SplineEvaluator; + + using bsplines_type1 = typename evaluator_type1::bsplines_type; + using bsplines_type2 = typename evaluator_type2::bsplines_type; + + using interpolation_domain_type1 = ddc::DiscreteDomain; + using interpolation_domain_type2 = ddc::DiscreteDomain; + using interpolation_domain_type + = ddc::DiscreteDomain; + + using vals_domain_type = ddc::DiscreteDomain; + + using bsplines_domain_type1 = ddc::DiscreteDomain; + using bsplines_domain_type2 = ddc::DiscreteDomain; + using bsplines_domain_type = ddc::DiscreteDomain; + + using batch_domain_type = + typename ddc::detail::convert_type_seq_to_discrete_domain, + ddc::detail::TypeSeq>>; + + template + using spline_dim_type = std::conditional_t< + std::is_same_v, + bsplines_type1, + std::conditional_t, bsplines_type2, Tag>>; + + using spline_domain_type = + typename ddc::detail::convert_type_seq_to_discrete_domain, + ddc::detail::TypeSeq, + ddc::detail::TypeSeq>>; + + +private: + spline_domain_type m_spline_domain; + + +public: + explicit SplineEvaluator2DBatched( + spline_domain_type const& spline_domain, + [[maybe_unused]] SplineBoundaryValue const& + left1_bc, // Unused, to be restored in next MR + [[maybe_unused]] SplineBoundaryValue const& right1_bc, + [[maybe_unused]] SplineBoundaryValue const& left2_bc, + [[maybe_unused]] SplineBoundaryValue const& right2_bc) + : m_spline_domain(spline_domain) + { + } + + SplineEvaluator2DBatched(SplineEvaluator2DBatched const& x) = default; + + SplineEvaluator2DBatched(SplineEvaluator2DBatched&& x) = default; + + ~SplineEvaluator2DBatched() = default; + + SplineEvaluator2DBatched& operator=(SplineEvaluator2DBatched const& x) = default; + + SplineEvaluator2DBatched& operator=(SplineEvaluator2DBatched&& x) = default; + + + + KOKKOS_FUNCTION spline_domain_type spline_domain() const noexcept + { + return m_spline_domain; + } + + KOKKOS_FUNCTION bsplines_domain_type bsplines_domain() const noexcept // TODO : clarify name + { + return bsplines_domain_type( + ddc::discrete_space().full_domain(), + ddc::discrete_space().full_domain()); + } + + KOKKOS_FUNCTION batch_domain_type batch_domain() const noexcept + { + return ddc::remove_dims_of(spline_domain(), bsplines_domain()); + } + + template + KOKKOS_FUNCTION double operator()( + ddc::Coordinate const& coord_eval, + ddc::ChunkSpan const + spline_coef) const + { + return eval(coord_eval, spline_coef); + } + + template + void operator()( + ddc::ChunkSpan const spline_eval, + ddc::ChunkSpan< + ddc::Coordinate const, + vals_domain_type, + Layout2, + memory_space> const coords_eval, + ddc::ChunkSpan const + spline_coef) const + { + interpolation_domain_type1 const interpolation_domain1(spline_eval.domain()); + interpolation_domain_type2 const interpolation_domain2(spline_eval.domain()); + ddc::for_each( + ddc::policies::policy(exec_space()), + batch_domain(), + KOKKOS_CLASS_LAMBDA(typename batch_domain_type::discrete_element_type const j) { + const auto spline_eval_2D = spline_eval[j]; + const auto coords_eval_2D = coords_eval[j]; + const auto spline_coef_2D = spline_coef[j]; + for (auto const i1 : interpolation_domain1) { + for (auto const i2 : interpolation_domain2) { + spline_eval_2D(i1, i2) = eval(coords_eval_2D(i1, i2), spline_coef_2D); + } + } + }); + } + + template + KOKKOS_FUNCTION double deriv_dim_1( + ddc::Coordinate const& coord_eval, + ddc::ChunkSpan const + spline_coef) const + { + return eval_no_bc(coord_eval, spline_coef); + } + + template + KOKKOS_FUNCTION double deriv_dim_2( + ddc::Coordinate const& coord_eval, + ddc::ChunkSpan const + spline_coef) const + { + return eval_no_bc(coord_eval, spline_coef); + } + + template + KOKKOS_FUNCTION double deriv_1_and_2( + ddc::Coordinate const& coord_eval, + ddc::ChunkSpan const + spline_coef) const + { + return eval_no_bc(coord_eval, spline_coef); + } + + template + KOKKOS_FUNCTION double deriv( + ddc::Coordinate const& coord_eval, + ddc::ChunkSpan const + spline_coef) const + { + static_assert( + std::is_same_v< + InterestDim, + typename interpolation_mesh_type1:: + continuous_dimension_type> || std::is_same_v); + if constexpr (std::is_same_v< + InterestDim, + typename interpolation_mesh_type1::continuous_dimension_type>) { + return deriv_dim_1(coord_eval, spline_coef); + } else if constexpr (std::is_same_v< + InterestDim, + typename interpolation_mesh_type2:: + continuous_dimension_type>) { + return deriv_dim_2(coord_eval, spline_coef); + } + } + + template + KOKKOS_FUNCTION double deriv2( + ddc::Coordinate const& coord_eval, + ddc::ChunkSpan const + spline_coef) const + { + static_assert( + (std::is_same_v< + InterestDim1, + typename interpolation_mesh_type1:: + continuous_dimension_type> && std::is_same_v) + || (std::is_same_v< + InterestDim2, + typename interpolation_mesh_type1:: + continuous_dimension_type> && std::is_same_v)); + return deriv_1_and_2(coord_eval, spline_coef); + } + + template + void deriv_dim_1( + ddc::ChunkSpan const spline_eval, + ddc::ChunkSpan< + ddc::Coordinate const, + vals_domain_type, + Layout2, + memory_space> const coords_eval, + ddc::ChunkSpan const + spline_coef) const + { + interpolation_domain_type1 const interpolation_domain1(spline_eval.domain()); + interpolation_domain_type2 const interpolation_domain2(spline_eval.domain()); + ddc::for_each( + ddc::policies::policy(exec_space()), + batch_domain(), + KOKKOS_CLASS_LAMBDA(typename batch_domain_type::discrete_element_type const j) { + const auto spline_eval_2D = spline_eval[j]; + const auto coords_eval_2D = coords_eval[j]; + const auto spline_coef_2D = spline_coef[j]; + for (auto const i1 : interpolation_domain1) { + for (auto const i2 : interpolation_domain2) { + spline_eval_2D(i1, i2) = eval_no_bc< + eval_deriv_type, + eval_type>(coords_eval_2D(i1, i2), spline_coef_2D); + } + } + }); + } + + template + void deriv_dim_2( + ddc::ChunkSpan const spline_eval, + ddc::ChunkSpan< + ddc::Coordinate const, + vals_domain_type, + Layout2, + memory_space> const coords_eval, + ddc::ChunkSpan const + spline_coef) const + { + interpolation_domain_type1 const interpolation_domain1(spline_eval.domain()); + interpolation_domain_type2 const interpolation_domain2(spline_eval.domain()); + ddc::for_each( + ddc::policies::policy(exec_space()), + batch_domain(), + KOKKOS_CLASS_LAMBDA(typename batch_domain_type::discrete_element_type const j) { + const auto spline_eval_2D = spline_eval[j]; + const auto coords_eval_2D = coords_eval[j]; + const auto spline_coef_2D = spline_coef[j]; + for (auto const i1 : interpolation_domain1) { + for (auto const i2 : interpolation_domain2) { + spline_eval_2D(i1, i2) = eval_no_bc< + eval_type, + eval_deriv_type>(coords_eval_2D(i1, i2), spline_coef_2D); + } + } + }); + } + + template + void deriv_1_and_2( + ddc::ChunkSpan const spline_eval, + ddc::ChunkSpan< + ddc::Coordinate const, + vals_domain_type, + Layout2, + memory_space> const coords_eval, + ddc::ChunkSpan const + spline_coef) const + { + interpolation_domain_type1 const interpolation_domain1(spline_eval.domain()); + interpolation_domain_type2 const interpolation_domain2(spline_eval.domain()); + ddc::for_each( + ddc::policies::policy(exec_space()), + batch_domain(), + KOKKOS_CLASS_LAMBDA(typename batch_domain_type::discrete_element_type const j) { + const auto spline_eval_2D = spline_eval[j]; + const auto coords_eval_2D = coords_eval[j]; + const auto spline_coef_2D = spline_coef[j]; + for (auto const i1 : interpolation_domain1) { + for (auto const i2 : interpolation_domain2) { + spline_eval_2D(i1, i2) = eval_no_bc< + eval_deriv_type, + eval_deriv_type>(coords_eval_2D(i1, i2), spline_coef_2D); + } + } + }); + } + + template + void deriv( + ddc::ChunkSpan const spline_eval, + ddc::ChunkSpan< + ddc::Coordinate const, + vals_domain_type, + Layout2, + memory_space> const coords_eval, + ddc::ChunkSpan const + spline_coef) const + { + static_assert( + std::is_same_v< + InterestDim, + typename interpolation_mesh_type1:: + continuous_dimension_type> || std::is_same_v); + if constexpr (std::is_same_v< + InterestDim, + typename interpolation_mesh_type1::continuous_dimension_type>) { + return deriv_dim_1(spline_eval, coords_eval, spline_coef); + } else if constexpr (std::is_same_v< + InterestDim, + typename interpolation_mesh_type2:: + continuous_dimension_type>) { + return deriv_dim_2(spline_eval, coords_eval, spline_coef); + } + } + + template < + class InterestDim1, + class InterestDim2, + class Layout1, + class Layout2, + class Layout3, + class... CoordsDims> + void deriv2( + ddc::ChunkSpan const spline_eval, + ddc::ChunkSpan< + ddc::Coordinate const, + vals_domain_type, + Layout2, + memory_space> const coords_eval, + ddc::ChunkSpan const + spline_coef) const + { + static_assert( + (std::is_same_v< + InterestDim1, + typename interpolation_mesh_type1:: + continuous_dimension_type> && std::is_same_v) + || (std::is_same_v< + InterestDim2, + typename interpolation_mesh_type1:: + continuous_dimension_type> && std::is_same_v)); + return deriv_1_and_2(spline_eval, coords_eval, spline_coef); + } + + template + void integrate( + ddc::ChunkSpan const integrals, + ddc::ChunkSpan const + spline_coef) const + { + ddc::Chunk values1_alloc( + ddc::DiscreteDomain(spline_coef.domain()), + ddc::KokkosAllocator()); + ddc::ChunkSpan values1 = values1_alloc.span_view(); + ddc::Chunk values2_alloc( + ddc::DiscreteDomain(spline_coef.domain()), + ddc::KokkosAllocator()); + ddc::ChunkSpan values2 = values2_alloc.span_view(); + Kokkos::parallel_for( + Kokkos::RangePolicy(0, 1), + KOKKOS_LAMBDA(int) { + ddc::discrete_space().integrals(values1); + ddc::discrete_space().integrals(values2); + }); + + ddc::for_each( + ddc::policies::policy(exec_space()), + batch_domain(), + KOKKOS_LAMBDA(typename batch_domain_type::discrete_element_type const j) { + integrals(j) = 0; + for (typename bsplines_domain_type1::discrete_element_type const i1 : + values1.domain()) { + for (typename bsplines_domain_type2::discrete_element_type const i2 : + values2.domain()) { + integrals(j) += spline_coef(i1, i2, j) * values1(i1) * values2(i2); + } + } + }); + } + +private: + template + KOKKOS_INLINE_FUNCTION double eval( + ddc::Coordinate const& coord_eval, + ddc::ChunkSpan const + spline_coef) const + { + ddc::Coordinate + coord_eval_interpolation1(coord_eval); + ddc::Coordinate + coord_eval_interpolation2(coord_eval); + if constexpr (bsplines_type1::is_periodic()) { + if (coord_eval_interpolation1 < ddc::discrete_space().rmin() + || coord_eval_interpolation1 > ddc::discrete_space().rmax()) { + coord_eval_interpolation1 + -= Kokkos::floor( + (coord_eval_interpolation1 + - ddc::discrete_space().rmin()) + / ddc::discrete_space().length()) + * ddc::discrete_space().length(); + } + } + if constexpr (bsplines_type2::is_periodic()) { + if (coord_eval_interpolation2 < ddc::discrete_space().rmin() + || coord_eval_interpolation2 > ddc::discrete_space().rmax()) { + coord_eval_interpolation2 + -= Kokkos::floor( + (coord_eval_interpolation2 + - ddc::discrete_space().rmin()) + / ddc::discrete_space().length()) + * ddc::discrete_space().length(); + } + } + return eval_no_bc( + ddc::Coordinate< + typename interpolation_mesh_type1::continuous_dimension_type, + typename interpolation_mesh_type2::continuous_dimension_type>( + coord_eval_interpolation1, + coord_eval_interpolation2), + spline_coef); + } + + template + KOKKOS_INLINE_FUNCTION double eval_no_bc( + ddc::Coordinate const& coord_eval, + ddc::ChunkSpan const + spline_coef) const + { + static_assert( + std::is_same_v || std::is_same_v); + static_assert( + std::is_same_v || std::is_same_v); + ddc::DiscreteElement jmin1; + ddc::DiscreteElement jmin2; + + std::array vals1; + std::array vals2; + ddc::Coordinate + coord_eval_interpolation1 + = ddc::select( + coord_eval); + ddc::Coordinate + coord_eval_interpolation2 + = ddc::select( + coord_eval); + + if constexpr (std::is_same_v) { + jmin1 = ddc::discrete_space() + .eval_basis(vals1, coord_eval_interpolation1); + } else if constexpr (std::is_same_v) { + jmin1 = ddc::discrete_space() + .eval_deriv(vals1, coord_eval_interpolation1); + } + if constexpr (std::is_same_v) { + jmin2 = ddc::discrete_space() + .eval_basis(vals2, coord_eval_interpolation2); + } else if constexpr (std::is_same_v) { + jmin2 = ddc::discrete_space() + .eval_deriv(vals2, coord_eval_interpolation2); + } + + double y = 0.0; + for (std::size_t i = 0; i < bsplines_type1::degree() + 1; ++i) { + for (std::size_t j = 0; j < bsplines_type2::degree() + 1; ++j) { + y += spline_coef(ddc::DiscreteElement< + bsplines_type1, + bsplines_type2>(jmin1 + i, jmin2 + j)) + * vals1[i] * vals2[j]; + } + } + return y; + } +}; +} // namespace ddc diff --git a/vendor/ddc/include/ddc/kernels/splines/spline_evaluator_batched.hpp b/vendor/ddc/include/ddc/kernels/splines/spline_evaluator_batched.hpp index fd4971427..ca95c43d7 100644 --- a/vendor/ddc/include/ddc/kernels/splines/spline_evaluator_batched.hpp +++ b/vendor/ddc/include/ddc/kernels/splines/spline_evaluator_batched.hpp @@ -60,19 +60,15 @@ class SplineEvaluatorBatched private: - SplineEvaluator spline_evaluator; - const spline_domain_type m_spline_domain; // Necessary ? + const spline_domain_type m_spline_domain; public: - SplineEvaluatorBatched() = delete; - explicit SplineEvaluatorBatched( spline_domain_type const& spline_domain, - SplineBoundaryValue const& left_bc, + SplineBoundaryValue const& left_bc, // Unused, to be restored in next MR SplineBoundaryValue const& right_bc) - : spline_evaluator(left_bc, right_bc) - , m_spline_domain(spline_domain) // Necessary ? + : m_spline_domain(spline_domain) { } @@ -104,7 +100,7 @@ class SplineEvaluatorBatched } template - double operator()( + KOKKOS_FUNCTION double operator()( ddc::Coordinate const& coord_eval, ddc::ChunkSpan const spline_coef) const @@ -138,7 +134,7 @@ class SplineEvaluatorBatched } template - double deriv( + KOKKOS_FUNCTION double deriv( ddc::Coordinate const& coord_eval, ddc::ChunkSpan const spline_coef) const diff --git a/vendor/ddc/include/ddc/pdi.hpp b/vendor/ddc/include/ddc/pdi.hpp index 21144f94f..7a8a7e30a 100644 --- a/vendor/ddc/include/ddc/pdi.hpp +++ b/vendor/ddc/include/ddc/pdi.hpp @@ -75,7 +75,13 @@ class PdiEvent !(access & PDI_IN) || (default_access_v & PDI_IN), "Invalid access for constant data"); using value_type = std::remove_cv_t>; - PDI_share(name.c_str(), const_cast(&data), access); + value_type* data_ptr = const_cast(&data); + // for read-only data, we share a copy instead of the data itself in case we received a ref on a temporary, + if constexpr (!(access & PDI_IN)) { + data_ptr = std::pmr::polymorphic_allocator(&m_metadata).allocate(1); + *data_ptr = data; + } + PDI_share(name.c_str(), data_ptr, access); m_names.push_back(name); return *this; } diff --git a/vendor/ddc/tests/splines/CMakeLists.txt b/vendor/ddc/tests/splines/CMakeLists.txt index aaf35554f..f20c12124 100644 --- a/vendor/ddc/tests/splines/CMakeLists.txt +++ b/vendor/ddc/tests/splines/CMakeLists.txt @@ -56,19 +56,42 @@ foreach(DEGREE_X RANGE "${SPLINES_TEST_DEGREE_MIN}" "${SPLINES_TEST_DEGREE_MAX}" endforeach() endforeach() -foreach(DEGREE_X RANGE "${SPLINES_TEST_DEGREE_MIN}" "${SPLINES_TEST_DEGREE_MAX}") - foreach(BSPLINES_TYPE "BSPLINES_TYPE_UNIFORM" "BSPLINES_TYPE_NON_UNIFORM") - set(test_name "splines_tests_BATCHED_DEGREE_X_${DEGREE_X}_${BSPLINES_TYPE}") - add_executable("${test_name}" ../main.cpp batched_spline_builder.cpp) - target_compile_features("${test_name}" PUBLIC cxx_std_17) - target_link_libraries("${test_name}" - PUBLIC - GTest::gtest - DDC::DDC - ) - target_compile_definitions("${test_name}" PUBLIC -DDEGREE_X=${DEGREE_X} -D${BSPLINES_TYPE}) - # add_test("${test_name}" "${test_name}") - gtest_discover_tests("${test_name}") +foreach(BCL "BCL_GREVILLE" "BCL_HERMITE") + foreach(BCR "BCR_GREVILLE" "BCR_HERMITE") + foreach(EVALUATOR "EVALUATOR_COSINE" "EVALUATOR_POLYNOMIAL") + foreach(DEGREE_X RANGE "${SPLINES_TEST_DEGREE_MIN}" "${SPLINES_TEST_DEGREE_MAX}") + foreach(BSPLINES_TYPE "BSPLINES_TYPE_UNIFORM" "BSPLINES_TYPE_NON_UNIFORM") + set(test_name "splines_tests_DEGREE_X_${DEGREE_X}_${BSPLINES_TYPE}_${EVALUATOR}_bcl_${BCL}_bcr_${BCR}") + add_executable("${test_name}" ../main.cpp non_periodic_spline_builder.cpp) + target_compile_features("${test_name}" PUBLIC cxx_std_17) + target_link_libraries("${test_name}" + PUBLIC + GTest::gtest + DDC::DDC + ) + target_compile_definitions("${test_name}" PUBLIC -DDEGREE_X=${DEGREE_X} -D${BSPLINES_TYPE} -D${EVALUATOR} -D${BCL} -D${BCR}) + add_test("${test_name}" "${test_name}") + endforeach() + endforeach() + endforeach() + endforeach() +endforeach() + +foreach(BC "BC_PERIODIC" "BC_GREVILLE" "BC_HERMITE") + foreach(DEGREE_X RANGE "${SPLINES_TEST_DEGREE_MIN}" "${SPLINES_TEST_DEGREE_MAX}") + foreach(BSPLINES_TYPE "BSPLINES_TYPE_UNIFORM" "BSPLINES_TYPE_NON_UNIFORM") + set(test_name "splines_tests_BATCHED_DEGREE_X_${DEGREE_X}_${BSPLINES_TYPE}_bc_${BC}") + add_executable("${test_name}" ../main.cpp batched_spline_builder.cpp) + target_compile_features("${test_name}" PUBLIC cxx_std_17) + target_link_libraries("${test_name}" + PUBLIC + GTest::gtest + DDC::DDC + ) + target_compile_definitions("${test_name}" PUBLIC -DDEGREE_X=${DEGREE_X} -D${BSPLINES_TYPE} -D${BC}) + # add_test("${test_name}" "${test_name}") + gtest_discover_tests("${test_name}") + endforeach() endforeach() endforeach() @@ -100,3 +123,23 @@ foreach(DEGREE_X RANGE "${SPLINES_TEST_DEGREE_MIN}" "${SPLINES_TEST_DEGREE_MAX}" gtest_discover_tests("${test_name}") endforeach() endforeach() + +foreach(BC "BC_PERIODIC" "BC_GREVILLE" "BC_HERMITE") + foreach(EVALUATOR "EVALUATOR_POLYNOMIAL") + foreach(DEGREE RANGE "${SPLINES_TEST_DEGREE_MIN}" "${SPLINES_TEST_DEGREE_MAX}") + foreach(BSPLINES_TYPE "BSPLINES_TYPE_UNIFORM" "BSPLINES_TYPE_NON_UNIFORM") + set(test_name "2d_splines_tests_BATCHED_DEGREE_${DEGREE}_${BSPLINES_TYPE}_${EVALUATOR}_${BC}") + add_executable("${test_name}" ../main.cpp batched_2d_spline_builder.cpp) + target_compile_features("${test_name}" PUBLIC cxx_std_17) + target_link_libraries("${test_name}" + PUBLIC + GTest::gtest + DDC::DDC + ) + target_compile_definitions("${test_name}" PUBLIC -DDEGREE=${DEGREE} -D${BSPLINES_TYPE} -D${EVALUATOR} -D${BC}) + # add_test("${test_name}" "${test_name}") + gtest_discover_tests("${test_name}") + endforeach() + endforeach() + endforeach() +endforeach() diff --git a/vendor/ddc/tests/splines/batched_2d_spline_builder.cpp b/vendor/ddc/tests/splines/batched_2d_spline_builder.cpp new file mode 100644 index 000000000..d42e21fd4 --- /dev/null +++ b/vendor/ddc/tests/splines/batched_2d_spline_builder.cpp @@ -0,0 +1,761 @@ +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include + +#include "ddc/coordinate.hpp" +#include "ddc/detail/macros.hpp" +#include "ddc/discrete_domain.hpp" +#include "ddc/for_each.hpp" +#include "ddc/uniform_point_sampling.hpp" + +#include "cosine_evaluator.hpp" +#include "evaluator_2d.hpp" +#include "polynomial_evaluator.hpp" +#include "spline_error_bounds.hpp" + +#if defined(BC_PERIODIC) +struct DimX +{ + static constexpr bool PERIODIC = true; +}; + +struct DimY +{ + static constexpr bool PERIODIC = true; +}; + +struct DimZ +{ + static constexpr bool PERIODIC = true; +}; + +struct DimT +{ + static constexpr bool PERIODIC = true; +}; +#else + +struct DimX +{ + static constexpr bool PERIODIC = false; +}; + +struct DimY +{ + static constexpr bool PERIODIC = false; +}; + +struct DimZ +{ + static constexpr bool PERIODIC = false; +}; + +struct DimT +{ + static constexpr bool PERIODIC = false; +}; +#endif + +static constexpr std::size_t s_degree = DEGREE; + +#if defined(BC_PERIODIC) +static constexpr ddc::BoundCond s_bcl = ddc::BoundCond::PERIODIC; +static constexpr ddc::BoundCond s_bcr = ddc::BoundCond::PERIODIC; +#elif defined(BC_GREVILLE) +static constexpr ddc::BoundCond s_bcl = ddc::BoundCond::GREVILLE; +static constexpr ddc::BoundCond s_bcr = ddc::BoundCond::GREVILLE; +#elif defined(BC_HERMITE) +static constexpr ddc::BoundCond s_bcl = ddc::BoundCond::HERMITE; +static constexpr ddc::BoundCond s_bcr = ddc::BoundCond::HERMITE; +#endif + +template +using GrevillePoints = ddc::GrevilleInterpolationPoints; + +#if defined(BSPLINES_TYPE_UNIFORM) +template +using BSplines = ddc::UniformBSplines; + +// Gives discrete dimension. In the dimension of interest, it is deduced from the BSplines type. In the other dimensions, it has to be newly defined. In practice both types coincide in the test, but it may not be the case. +template +using IDim = std::conditional_t< + std::disjunction_v, std::is_same>, + typename GrevillePoints>::interpolation_mesh_type, + ddc::UniformPointSampling>; + +#elif defined(BSPLINES_TYPE_NON_UNIFORM) +template +using BSplines = ddc::NonUniformBSplines; + +template +using IDim = std::conditional_t< + std::disjunction_v, std::is_same>, + typename GrevillePoints>::interpolation_mesh_type, + ddc::NonUniformPointSampling>; +#endif + +#if defined(BC_PERIODIC) +template +using evaluator_type = Evaluator2D:: + Evaluator, CosineEvaluator::Evaluator>; +#else +template +using evaluator_type = Evaluator2D::Evaluator< + PolynomialEvaluator::Evaluator, + PolynomialEvaluator::Evaluator>; +#endif + +template +using Index = ddc::DiscreteElement; +template +using DVect = ddc::DiscreteVector; +template +using Coord = ddc::Coordinate; + +// Extract batch dimensions from IDim (remove dimension of interest). Usefull +template +using BatchDims = ddc::type_seq_remove_t, ddc::detail::TypeSeq>; + +// Templated function giving first coordinate of the mesh in given dimension. +template +static constexpr Coord x0() +{ + return Coord(0.); +} + +// Templated function giving last coordinate of the mesh in given dimension. +template +static constexpr Coord xN() +{ + return Coord(1.); +} + +// Templated function giving step of the mesh in given dimension. +template +static constexpr double dx(std::size_t ncells) +{ + return (xN() - x0()) / ncells; +} + +// Templated function giving break points of mesh in given dimension for non-uniform case. +template +static constexpr std::vector> breaks(std::size_t ncells) +{ + std::vector> out(ncells + 1); + for (int i(0); i < ncells + 1; ++i) { + out[i] = x0() + i * dx(ncells); + } + return out; +} + +// Helper to initialize space +template +struct DimsInitializer; + +template +struct DimsInitializer> +{ + void operator()(std::size_t const ncells) + { +#if defined(BSPLINES_TYPE_UNIFORM) + (ddc::init_discrete_space(IDimX:: + init(x0(), + xN(), + DVect(ncells))), + ...); + ddc::init_discrete_space>( + x0(), + xN(), + ncells); + ddc::init_discrete_space>( + x0(), + xN(), + ncells); +#elif defined(BSPLINES_TYPE_NON_UNIFORM) + (ddc::init_discrete_space(breaks(ncells)), + ...); + ddc::init_discrete_space>( + breaks(ncells)); + ddc::init_discrete_space>( + breaks(ncells)); +#endif + ddc::init_discrete_space( + GrevillePoints< + BSplines>::get_sampling()); + ddc::init_discrete_space( + GrevillePoints< + BSplines>::get_sampling()); + } +}; + +// Checks that when evaluating the spline at interpolation points one +// recovers values that were used to build the spline +template +static void Batched2dSplineTest() +{ + // Instantiate execution spaces and initialize spaces + Kokkos::DefaultHostExecutionSpace host_exec_space = Kokkos::DefaultHostExecutionSpace(); + ExecSpace exec_space = ExecSpace(); + std::size_t constexpr ncells = 10; + DimsInitializer< + IDim, + IDim, + BatchDims, IDim, IDim...>> + dims_initializer; + dims_initializer(ncells); + + // Create the values domain (mesh) +#if defined(BC_HERMITE) + auto interpolation_domain1 + = ddc::DiscreteDomain>(GrevillePoints>::get_domain()); + auto interpolation_domain2 + = ddc::DiscreteDomain>(GrevillePoints>::get_domain()); +#endif + auto interpolation_domain = ddc::DiscreteDomain, IDim>( + GrevillePoints>::get_domain(), + GrevillePoints>::get_domain()); + ddc::DiscreteDomain...> const dom_vals_tmp = ddc::DiscreteDomain< + IDim...>( + ddc::DiscreteDomain>(Index>(0), DVect>(ncells))...); + ddc::DiscreteDomain...> const dom_vals + = ddc::replace_dim_of, IDim>( + ddc::replace_dim_of< + IDim, + IDim>(dom_vals_tmp, interpolation_domain), + interpolation_domain); + +#if defined(BC_HERMITE) + // Create the derivs domain + ddc::DiscreteDomain> const derivs_domain1 = ddc::DiscreteDomain< + ddc::Deriv>(Index>(1), DVect>(s_degree / 2)); + ddc::DiscreteDomain> const derivs_domain2 = ddc::DiscreteDomain< + ddc::Deriv>(Index>(1), DVect>(s_degree / 2)); + ddc::DiscreteDomain, ddc::Deriv> const derivs_domain + = ddc::DiscreteDomain, ddc::Deriv>(derivs_domain1, derivs_domain2); + + auto const dom_derivs1 + = ddc::replace_dim_of, ddc::Deriv>(dom_vals, derivs_domain1); + auto const dom_derivs2 + = ddc::replace_dim_of, ddc::Deriv>(dom_vals, derivs_domain2); + auto const dom_derivs + = ddc::replace_dim_of, ddc::Deriv>(dom_derivs1, derivs_domain2); +#endif + + // Create a SplineBuilderBatched over BSplines and batched along other dimensions using some boundary conditions + ddc::SplineBuilder2DBatched< + ExecSpace, + MemorySpace, + BSplines, + BSplines, + IDim, + IDim, + s_bcl, + s_bcr, + s_bcl, + s_bcr, + IDim...> + spline_builder(dom_vals); + + // Compute usefull domains (dom_interpolation, dom_batch, dom_bsplines and dom_spline) + ddc::DiscreteDomain, IDim> const dom_interpolation + = spline_builder.interpolation_domain(); + auto const dom_spline = spline_builder.spline_domain(); + + // Allocate and fill a chunk containing values to be passed as input to spline_builder. Those are values of cosine along interest dimension duplicated along batch dimensions + ddc::Chunk vals1_cpu_alloc( + dom_interpolation, + ddc::KokkosAllocator()); + ddc::ChunkSpan vals1_cpu = vals1_cpu_alloc.span_view(); + evaluator_type, IDim> evaluator(dom_interpolation); + evaluator(vals1_cpu); + ddc::Chunk vals1_alloc(dom_interpolation, ddc::KokkosAllocator()); + ddc::ChunkSpan vals1 = vals1_alloc.span_view(); + ddc::deepcopy(vals1, vals1_cpu); + + ddc::Chunk vals_alloc(dom_vals, ddc::KokkosAllocator()); + ddc::ChunkSpan vals = vals_alloc.span_view(); + ddc::for_each( + ddc::policies::policy(exec_space), + vals.domain(), + KOKKOS_LAMBDA(Index...> const e) { + vals(e) = vals1(ddc::select, IDim>(e)); + }); + +#if defined(BC_HERMITE) + // Allocate and fill a chunk containing derivs to be passed as input to spline_builder. + int constexpr shift = s_degree % 2; // shift = 0 for even order, 1 for odd order + ddc::Chunk Sderiv1_lhs_alloc(dom_derivs1, ddc::KokkosAllocator()); + ddc::ChunkSpan Sderiv1_lhs = Sderiv1_lhs_alloc.span_view(); + if (s_bcl == ddc::BoundCond::HERMITE) { + ddc::Chunk Sderiv1_lhs1_cpu_alloc( + ddc::DiscreteDomain< + ddc::Deriv, + IDim>(derivs_domain1, interpolation_domain2), + ddc::HostAllocator()); + ddc::ChunkSpan Sderiv1_lhs1_cpu = Sderiv1_lhs1_cpu_alloc.span_view(); + ddc::for_each( + Sderiv1_lhs1_cpu.domain(), + KOKKOS_LAMBDA(ddc::DiscreteElement, IDim> const e) { + auto deriv_idx = ddc::DiscreteElement>(e).uid(); + auto x2 = ddc::coordinate(ddc::DiscreteElement>(e)); + Sderiv1_lhs1_cpu(e) = evaluator.deriv(x0(), x2, deriv_idx + shift - 1, 0); + }); + ddc::Chunk Sderiv1_lhs1_alloc( + ddc::DiscreteDomain< + ddc::Deriv, + IDim>(derivs_domain1, interpolation_domain2), + ddc::KokkosAllocator()); + ddc::ChunkSpan Sderiv1_lhs1 = Sderiv1_lhs1_alloc.span_view(); + ddc::deepcopy(Sderiv1_lhs1, Sderiv1_lhs1_cpu); + + ddc::for_each( + ddc::policies::policy(exec_space), + Sderiv1_lhs.domain(), + KOKKOS_LAMBDA( + typename decltype(Sderiv1_lhs.domain())::discrete_element_type const e) { + Sderiv1_lhs(e) = Sderiv1_lhs1(ddc::select, IDim>(e)); + }); + } + + ddc::Chunk Sderiv1_rhs_alloc(dom_derivs1, ddc::KokkosAllocator()); + ddc::ChunkSpan Sderiv1_rhs = Sderiv1_rhs_alloc.span_view(); + if (s_bcl == ddc::BoundCond::HERMITE) { + ddc::Chunk Sderiv1_rhs1_cpu_alloc( + ddc::DiscreteDomain< + ddc::Deriv, + IDim>(derivs_domain1, interpolation_domain2), + ddc::HostAllocator()); + ddc::ChunkSpan Sderiv1_rhs1_cpu = Sderiv1_rhs1_cpu_alloc.span_view(); + ddc::for_each( + Sderiv1_rhs1_cpu.domain(), + KOKKOS_LAMBDA(ddc::DiscreteElement, IDim> const e) { + auto deriv_idx = ddc::DiscreteElement>(e).uid(); + auto x2 = ddc::coordinate(ddc::DiscreteElement>(e)); + Sderiv1_rhs1_cpu(e) = evaluator.deriv(xN(), x2, deriv_idx + shift - 1, 0); + }); + ddc::Chunk Sderiv1_rhs1_alloc( + ddc::DiscreteDomain< + ddc::Deriv, + IDim>(derivs_domain1, interpolation_domain2), + ddc::KokkosAllocator()); + ddc::ChunkSpan Sderiv1_rhs1 = Sderiv1_rhs1_alloc.span_view(); + ddc::deepcopy(Sderiv1_rhs1, Sderiv1_rhs1_cpu); + + ddc::for_each( + ddc::policies::policy(exec_space), + Sderiv1_rhs.domain(), + KOKKOS_LAMBDA( + typename decltype(Sderiv1_rhs.domain())::discrete_element_type const e) { + Sderiv1_rhs(e) = Sderiv1_rhs1(ddc::select, IDim>(e)); + }); + } + + ddc::Chunk Sderiv2_lhs_alloc(dom_derivs2, ddc::KokkosAllocator()); + ddc::ChunkSpan Sderiv2_lhs = Sderiv2_lhs_alloc.span_view(); + if (s_bcl == ddc::BoundCond::HERMITE) { + ddc::Chunk Sderiv2_lhs1_cpu_alloc( + ddc::DiscreteDomain< + IDim, + ddc::Deriv>(interpolation_domain1, derivs_domain2), + ddc::HostAllocator()); + ddc::ChunkSpan Sderiv2_lhs1_cpu = Sderiv2_lhs1_cpu_alloc.span_view(); + ddc::for_each( + Sderiv2_lhs1_cpu.domain(), + KOKKOS_LAMBDA(ddc::DiscreteElement, ddc::Deriv> const e) { + auto x1 = ddc::coordinate(ddc::DiscreteElement>(e)); + auto deriv_idx = ddc::DiscreteElement>(e).uid(); + Sderiv2_lhs1_cpu(e) = evaluator.deriv(x1, x0(), 0, deriv_idx + shift - 1); + }); + + ddc::Chunk Sderiv2_lhs1_alloc( + ddc::DiscreteDomain< + IDim, + ddc::Deriv>(interpolation_domain1, derivs_domain2), + ddc::KokkosAllocator()); + ddc::ChunkSpan Sderiv2_lhs1 = Sderiv2_lhs1_alloc.span_view(); + ddc::deepcopy(Sderiv2_lhs1, Sderiv2_lhs1_cpu); + + ddc::for_each( + ddc::policies::policy(exec_space), + Sderiv2_lhs.domain(), + KOKKOS_LAMBDA( + typename decltype(Sderiv2_lhs.domain())::discrete_element_type const e) { + Sderiv2_lhs(e) = Sderiv2_lhs1(ddc::select, ddc::Deriv>(e)); + }); + } + + ddc::Chunk Sderiv2_rhs_alloc(dom_derivs2, ddc::KokkosAllocator()); + ddc::ChunkSpan Sderiv2_rhs = Sderiv2_rhs_alloc.span_view(); + if (s_bcl == ddc::BoundCond::HERMITE) { + ddc::Chunk Sderiv2_rhs1_cpu_alloc( + ddc::DiscreteDomain< + IDim, + ddc::Deriv>(interpolation_domain1, derivs_domain2), + ddc::HostAllocator()); + ddc::ChunkSpan Sderiv2_rhs1_cpu = Sderiv2_rhs1_cpu_alloc.span_view(); + ddc::for_each( + Sderiv2_rhs1_cpu.domain(), + KOKKOS_LAMBDA(ddc::DiscreteElement, ddc::Deriv> const e) { + auto x1 = ddc::coordinate(ddc::DiscreteElement>(e)); + auto deriv_idx = ddc::DiscreteElement>(e).uid(); + Sderiv2_rhs1_cpu(e) = evaluator.deriv(x1, xN(), 0, deriv_idx + shift - 1); + }); + + ddc::Chunk Sderiv2_rhs1_alloc( + ddc::DiscreteDomain< + IDim, + ddc::Deriv>(interpolation_domain1, derivs_domain2), + ddc::KokkosAllocator()); + ddc::ChunkSpan Sderiv2_rhs1 = Sderiv2_rhs1_alloc.span_view(); + ddc::deepcopy(Sderiv2_rhs1, Sderiv2_rhs1_cpu); + + ddc::for_each( + ddc::policies::policy(exec_space), + Sderiv2_rhs.domain(), + KOKKOS_LAMBDA( + typename decltype(Sderiv2_rhs.domain())::discrete_element_type const e) { + Sderiv2_rhs(e) = Sderiv2_rhs1(ddc::select, ddc::Deriv>(e)); + }); + } + + ddc::Chunk Sderiv_mixed_lhs_lhs_alloc(dom_derivs, ddc::KokkosAllocator()); + ddc::ChunkSpan Sderiv_mixed_lhs_lhs = Sderiv_mixed_lhs_lhs_alloc.span_view(); + ddc::Chunk Sderiv_mixed_rhs_lhs_alloc(dom_derivs, ddc::KokkosAllocator()); + ddc::ChunkSpan Sderiv_mixed_rhs_lhs = Sderiv_mixed_rhs_lhs_alloc.span_view(); + ddc::Chunk Sderiv_mixed_lhs_rhs_alloc(dom_derivs, ddc::KokkosAllocator()); + ddc::ChunkSpan Sderiv_mixed_lhs_rhs = Sderiv_mixed_lhs_rhs_alloc.span_view(); + ddc::Chunk Sderiv_mixed_rhs_rhs_alloc(dom_derivs, ddc::KokkosAllocator()); + ddc::ChunkSpan Sderiv_mixed_rhs_rhs = Sderiv_mixed_rhs_rhs_alloc.span_view(); + + if (s_bcl == ddc::BoundCond::HERMITE) { + ddc::Chunk Sderiv_mixed_lhs_lhs1_cpu_alloc(derivs_domain, ddc::HostAllocator()); + ddc::ChunkSpan Sderiv_mixed_lhs_lhs1_cpu = Sderiv_mixed_lhs_lhs1_cpu_alloc.span_view(); + ddc::Chunk Sderiv_mixed_rhs_lhs1_cpu_alloc(derivs_domain, ddc::HostAllocator()); + ddc::ChunkSpan Sderiv_mixed_rhs_lhs1_cpu = Sderiv_mixed_rhs_lhs1_cpu_alloc.span_view(); + ddc::Chunk Sderiv_mixed_lhs_rhs1_cpu_alloc(derivs_domain, ddc::HostAllocator()); + ddc::ChunkSpan Sderiv_mixed_lhs_rhs1_cpu = Sderiv_mixed_lhs_rhs1_cpu_alloc.span_view(); + ddc::Chunk Sderiv_mixed_rhs_rhs1_cpu_alloc(derivs_domain, ddc::HostAllocator()); + ddc::ChunkSpan Sderiv_mixed_rhs_rhs1_cpu = Sderiv_mixed_rhs_rhs1_cpu_alloc.span_view(); + + for (int ii = 1; ii < derivs_domain.template extent>() + 1; ++ii) { + for (std::size_t jj = 1; jj < derivs_domain.template extent>() + 1; + ++jj) { + Sderiv_mixed_lhs_lhs1_cpu( + typename decltype(derivs_domain)::discrete_element_type(ii, jj)) + = evaluator.deriv(x0(), x0(), ii + shift - 1, jj + shift - 1); + Sderiv_mixed_rhs_lhs1_cpu( + typename decltype(derivs_domain)::discrete_element_type(ii, jj)) + = evaluator.deriv(xN(), x0(), ii + shift - 1, jj + shift - 1); + Sderiv_mixed_lhs_rhs1_cpu( + typename decltype(derivs_domain)::discrete_element_type(ii, jj)) + = evaluator.deriv(x0(), xN(), ii + shift - 1, jj + shift - 1); + Sderiv_mixed_rhs_rhs1_cpu( + typename decltype(derivs_domain)::discrete_element_type(ii, jj)) + = evaluator.deriv(xN(), xN(), ii + shift - 1, jj + shift - 1); + } + } + ddc::Chunk Sderiv_mixed_lhs_lhs1_alloc( + derivs_domain, + ddc::KokkosAllocator()); + ddc::ChunkSpan Sderiv_mixed_lhs_lhs1 = Sderiv_mixed_lhs_lhs1_alloc.span_view(); + ddc::deepcopy(Sderiv_mixed_lhs_lhs1, Sderiv_mixed_lhs_lhs1_cpu); + ddc::Chunk Sderiv_mixed_rhs_lhs1_alloc( + derivs_domain, + ddc::KokkosAllocator()); + ddc::ChunkSpan Sderiv_mixed_rhs_lhs1 = Sderiv_mixed_rhs_lhs1_alloc.span_view(); + ddc::deepcopy(Sderiv_mixed_rhs_lhs1, Sderiv_mixed_rhs_lhs1_cpu); + ddc::Chunk Sderiv_mixed_lhs_rhs1_alloc( + derivs_domain, + ddc::KokkosAllocator()); + ddc::ChunkSpan Sderiv_mixed_lhs_rhs1 = Sderiv_mixed_lhs_rhs1_alloc.span_view(); + ddc::deepcopy(Sderiv_mixed_lhs_rhs1, Sderiv_mixed_lhs_rhs1_cpu); + ddc::Chunk Sderiv_mixed_rhs_rhs1_alloc( + derivs_domain, + ddc::KokkosAllocator()); + ddc::ChunkSpan Sderiv_mixed_rhs_rhs1 = Sderiv_mixed_rhs_rhs1_alloc.span_view(); + ddc::deepcopy(Sderiv_mixed_rhs_rhs1, Sderiv_mixed_rhs_rhs1_cpu); + + ddc::for_each( + ddc::policies::policy(exec_space), + dom_derivs, + KOKKOS_LAMBDA(typename decltype(dom_derivs)::discrete_element_type const e) { + Sderiv_mixed_lhs_lhs(e) + = Sderiv_mixed_lhs_lhs1(ddc::select, ddc::Deriv>(e)); + Sderiv_mixed_rhs_lhs(e) + = Sderiv_mixed_rhs_lhs1(ddc::select, ddc::Deriv>(e)); + Sderiv_mixed_lhs_rhs(e) + = Sderiv_mixed_lhs_rhs1(ddc::select, ddc::Deriv>(e)); + Sderiv_mixed_rhs_rhs(e) + = Sderiv_mixed_rhs_rhs1(ddc::select, ddc::Deriv>(e)); + }); + } +#endif + + // Instantiate chunk of spline coefs to receive output of spline_builder + ddc::Chunk coef_alloc(dom_spline, ddc::KokkosAllocator()); + ddc::ChunkSpan coef = coef_alloc.span_view(); + + // Finally compute the spline by filling `coef` +#if defined(BC_HERMITE) + spline_builder( + coef, + vals.span_cview(), + std::optional(Sderiv1_lhs.span_cview()), + std::optional(Sderiv1_rhs.span_cview()), + std::optional(Sderiv2_lhs.span_cview()), + std::optional(Sderiv2_rhs.span_cview()), + std::optional(Sderiv_mixed_lhs_lhs.span_cview()), + std::optional(Sderiv_mixed_rhs_lhs.span_cview()), + std::optional(Sderiv_mixed_lhs_rhs.span_cview()), + std::optional(Sderiv_mixed_rhs_rhs.span_cview())); +#else + spline_builder(coef, vals.span_cview()); +#endif + // Instantiate a SplineEvaluator over interest dimension and batched along other dimensions + ddc::SplineEvaluator2DBatched< + ExecSpace, + MemorySpace, + BSplines, + BSplines, + IDim, + IDim, + IDim...> + spline_evaluator_batched( + coef.domain(), + ddc::g_null_boundary>, + ddc::g_null_boundary>, + ddc::g_null_boundary>, + ddc::g_null_boundary>); + + // Instantiate chunk of coordinates of dom_interpolation + ddc::Chunk coords_eval_alloc(dom_vals, ddc::KokkosAllocator, MemorySpace>()); + ddc::ChunkSpan coords_eval = coords_eval_alloc.span_view(); + ddc::for_each( + ddc::policies::policy(exec_space), + coords_eval.domain(), + KOKKOS_LAMBDA(Index...> const e) { + coords_eval(e) = ddc::coordinate(e); + }); + + + // Instantiate chunks to receive outputs of spline_evaluator + ddc::Chunk spline_eval_alloc(dom_vals, ddc::KokkosAllocator()); + ddc::ChunkSpan spline_eval = spline_eval_alloc.span_view(); + ddc::Chunk spline_eval_deriv1_alloc(dom_vals, ddc::KokkosAllocator()); + ddc::ChunkSpan spline_eval_deriv1 = spline_eval_deriv1_alloc.span_view(); + ddc::Chunk spline_eval_deriv2_alloc(dom_vals, ddc::KokkosAllocator()); + ddc::ChunkSpan spline_eval_deriv2 = spline_eval_deriv2_alloc.span_view(); + ddc::Chunk spline_eval_deriv12_alloc(dom_vals, ddc::KokkosAllocator()); + ddc::ChunkSpan spline_eval_deriv12 = spline_eval_deriv12_alloc.span_view(); + + // Call spline_evaluator on the same mesh we started with + spline_evaluator_batched(spline_eval, coords_eval.span_cview(), coef.span_cview()); + spline_evaluator_batched + .template deriv(spline_eval_deriv1, coords_eval.span_cview(), coef.span_cview()); + spline_evaluator_batched + .template deriv(spline_eval_deriv2, coords_eval.span_cview(), coef.span_cview()); + spline_evaluator_batched.template deriv2< + I1, + I2>(spline_eval_deriv12, coords_eval.span_cview(), coef.span_cview()); + + // Checking errors (we recover the initial values) + double max_norm_error = ddc::transform_reduce( + ddc::policies::policy(exec_space), + spline_eval.domain(), + 0., + ddc::reducer::max(), + KOKKOS_LAMBDA(Index...> const e) { + return Kokkos::abs(spline_eval(e) - vals(e)); + }); + double max_norm_error_diff1 = ddc::transform_reduce( + ddc::policies::policy(exec_space), + spline_eval_deriv1.domain(), + 0., + ddc::reducer::max(), + KOKKOS_LAMBDA(Index...> const e) { + Coord const x = ddc::coordinate(ddc::select>(e)); + Coord const y = ddc::coordinate(ddc::select>(e)); + return Kokkos::abs(spline_eval_deriv1(e) - evaluator.deriv(x, y, 1, 0)); + }); + double max_norm_error_diff2 = ddc::transform_reduce( + ddc::policies::policy(exec_space), + spline_eval_deriv2.domain(), + 0., + ddc::reducer::max(), + KOKKOS_LAMBDA(Index...> const e) { + Coord const x = ddc::coordinate(ddc::select>(e)); + Coord const y = ddc::coordinate(ddc::select>(e)); + return Kokkos::abs(spline_eval_deriv2(e) - evaluator.deriv(x, y, 0, 1)); + }); + double max_norm_error_diff12 = ddc::transform_reduce( + ddc::policies::policy(exec_space), + spline_eval_deriv1.domain(), + 0., + ddc::reducer::max(), + KOKKOS_LAMBDA(Index...> const e) { + Coord const x = ddc::coordinate(ddc::select>(e)); + Coord const y = ddc::coordinate(ddc::select>(e)); + return Kokkos::abs(spline_eval_deriv12(e) - evaluator.deriv(x, y, 1, 1)); + }); + + + double const max_norm = evaluator.max_norm(); + double const max_norm_diff1 = evaluator.max_norm(1, 0); + double const max_norm_diff2 = evaluator.max_norm(0, 1); + double const max_norm_diff12 = evaluator.max_norm(1, 1); + + SplineErrorBounds, IDim>> error_bounds(evaluator); + EXPECT_LE( + max_norm_error, + std:: + max(error_bounds + .error_bound(dx(ncells), dx(ncells), s_degree, s_degree), + 1.0e-14 * max_norm)); + EXPECT_LE( + max_norm_error_diff1, + std:: + max(error_bounds.error_bound_on_deriv_1( + dx(ncells), + dx(ncells), + s_degree, + s_degree), + 1e-12 * max_norm_diff1)); + EXPECT_LE( + max_norm_error_diff2, + std:: + max(error_bounds.error_bound_on_deriv_2( + dx(ncells), + dx(ncells), + s_degree, + s_degree), + 1e-12 * max_norm_diff2)); + EXPECT_LE( + max_norm_error_diff12, + std:: + max(error_bounds.error_bound_on_deriv_12( + dx(ncells), + dx(ncells), + s_degree, + s_degree), + 1e-12 * max_norm_diff12)); +} + +#if defined(BC_PERIODIC) && defined(BSPLINES_TYPE_UNIFORM) +#define SUFFIX(name) name##Periodic##Uniform +#elif defined(BC_PERIODIC) && defined(BSPLINES_TYPE_NON_UNIFORM) +#define SUFFIX(name) name##Periodic##NonUniform +#elif defined(BC_GREVILLE) && defined(BSPLINES_TYPE_UNIFORM) +#define SUFFIX(name) name##Greville##Uniform +#elif defined(BC_GREVILLE) && defined(BSPLINES_TYPE_NON_UNIFORM) +#define SUFFIX(name) name##Greville##NonUniform +#elif defined(BC_HERMITE) && defined(BSPLINES_TYPE_UNIFORM) +#define SUFFIX(name) name##Hermite##Uniform +#elif defined(BC_HERMITE) && defined(BSPLINES_TYPE_NON_UNIFORM) +#define SUFFIX(name) name##Hermite##NonUniform +#endif + +TEST(SUFFIX(Batched2dSplineHost), 2DXY) +{ + Batched2dSplineTest< + Kokkos::DefaultHostExecutionSpace, + Kokkos::DefaultHostExecutionSpace::memory_space, + DimX, + DimY, + DimX, + DimY>(); +} + +TEST(SUFFIX(Batched2dSplineDevice), 2DXY) +{ + Batched2dSplineTest< + Kokkos::DefaultExecutionSpace, + Kokkos::DefaultExecutionSpace::memory_space, + DimX, + DimY, + DimX, + DimY>(); +} + +TEST(SUFFIX(Batched2dSplineHost), 3DXY) +{ + Batched2dSplineTest< + Kokkos::DefaultHostExecutionSpace, + Kokkos::DefaultHostExecutionSpace::memory_space, + DimX, + DimY, + DimX, + DimY, + DimZ>(); +} + +TEST(SUFFIX(Batched2dSplineHost), 3DXZ) +{ + Batched2dSplineTest< + Kokkos::DefaultHostExecutionSpace, + Kokkos::DefaultHostExecutionSpace::memory_space, + DimX, + DimZ, + DimX, + DimY, + DimZ>(); +} + +TEST(SUFFIX(Batched2dSplineHost), 3DYZ) +{ + Batched2dSplineTest< + Kokkos::DefaultHostExecutionSpace, + Kokkos::DefaultHostExecutionSpace::memory_space, + DimY, + DimZ, + DimX, + DimY, + DimZ>(); +} + +TEST(SUFFIX(Batched2dSplineDevice), 3DXY) +{ + Batched2dSplineTest< + Kokkos::DefaultExecutionSpace, + Kokkos::DefaultExecutionSpace::memory_space, + DimX, + DimY, + DimX, + DimY, + DimZ>(); +} + +TEST(SUFFIX(Batched2dSplineDevice), 3DXZ) +{ + Batched2dSplineTest< + Kokkos::DefaultExecutionSpace, + Kokkos::DefaultExecutionSpace::memory_space, + DimX, + DimZ, + DimX, + DimY, + DimZ>(); +} + +TEST(SUFFIX(Batched2dSplineDevice), 3DYZ) +{ + Batched2dSplineTest< + Kokkos::DefaultExecutionSpace, + Kokkos::DefaultExecutionSpace::memory_space, + DimY, + DimZ, + DimX, + DimY, + DimZ>(); +} diff --git a/vendor/ddc/tests/splines/batched_spline_builder.cpp b/vendor/ddc/tests/splines/batched_spline_builder.cpp index 637daf16a..dccc724f0 100644 --- a/vendor/ddc/tests/splines/batched_spline_builder.cpp +++ b/vendor/ddc/tests/splines/batched_spline_builder.cpp @@ -21,6 +21,7 @@ #include "polynomial_evaluator.hpp" #include "spline_error_bounds.hpp" +#if defined(BC_PERIODIC) struct DimX { static constexpr bool PERIODIC = true; @@ -40,12 +41,44 @@ struct DimT { static constexpr bool PERIODIC = true; }; +#else + +struct DimX +{ + static constexpr bool PERIODIC = false; +}; + +struct DimY +{ + static constexpr bool PERIODIC = false; +}; + +struct DimZ +{ + static constexpr bool PERIODIC = false; +}; + +struct DimT +{ + static constexpr bool PERIODIC = false; +}; +#endif static constexpr std::size_t s_degree_x = DEGREE_X; +#if defined(BC_PERIODIC) +static constexpr ddc::BoundCond s_bcl = ddc::BoundCond::PERIODIC; +static constexpr ddc::BoundCond s_bcr = ddc::BoundCond::PERIODIC; +#elif defined(BC_GREVILLE) +static constexpr ddc::BoundCond s_bcl = ddc::BoundCond::GREVILLE; +static constexpr ddc::BoundCond s_bcr = ddc::BoundCond::GREVILLE; +#elif defined(BC_HERMITE) +static constexpr ddc::BoundCond s_bcl = ddc::BoundCond::HERMITE; +static constexpr ddc::BoundCond s_bcr = ddc::BoundCond::HERMITE; +#endif + template -using GrevillePoints = ddc:: - GrevilleInterpolationPoints; +using GrevillePoints = ddc::GrevilleInterpolationPoints; #if defined(BSPLINES_TYPE_UNIFORM) template @@ -63,11 +96,9 @@ template using BSplines = ddc::NonUniformBSplines; template -using IDim = std::conditional_t< - std::is_same_v, - typename GrevillePoints>::interpolation_mesh_type, - ddc::NonUniformPointSampling>; +using IDim = ddc::NonUniformPointSampling; #endif + template using evaluator_type = CosineEvaluator::Evaluator; @@ -98,14 +129,14 @@ static constexpr Coord xN() // Templated function giving step of the mesh in given dimension. template -static constexpr double dx(double ncells) +static constexpr double dx(std::size_t ncells) { return (xN() - x0()) / ncells; } // Templated function giving break points of mesh in given dimension for non-uniform case. template -static constexpr std::vector> breaks(double ncells) +static std::vector> breaks(std::size_t ncells) { std::vector> out(ncells + 1); for (int i(0); i < ncells + 1; ++i) { @@ -148,7 +179,7 @@ struct DimsInitializer> // Checks that when evaluating the spline at interpolation points one // recovers values that were used to build the spline template -static void BatchedPeriodicSplineTest() +static void BatchedSplineTest() { // Instantiate execution spaces and initialize spaces Kokkos::DefaultHostExecutionSpace host_exec_space = Kokkos::DefaultHostExecutionSpace(); @@ -159,21 +190,25 @@ static void BatchedPeriodicSplineTest() dims_initializer(ncells); // Create the values domain (mesh) - ddc::DiscreteDomain...> const dom_vals = ddc::DiscreteDomain...>( - (std::is_same_v - ? GrevillePoints>::get_domain() - : ddc::DiscreteDomain< - IDim>(Index>(0), DVect>(ncells)))...); + ddc::DiscreteDomain> interpolation_domain + = GrevillePoints>::get_domain(); + ddc::DiscreteDomain...> const dom_vals_tmp = ddc::DiscreteDomain< + IDim...>( + ddc::DiscreteDomain< + IDim>(Index>(0), DVect>(ncells))...); + ddc::DiscreteDomain...> const dom_vals + = ddc::replace_dim_of, IDim>(dom_vals_tmp, interpolation_domain); + +#if defined(BC_HERMITE) + // Create the derivs domain + ddc::DiscreteDomain> const derivs_domain = ddc::DiscreteDomain< + ddc::Deriv>(Index>(1), DVect>(s_degree_x / 2)); + auto const dom_derivs = ddc::replace_dim_of, ddc::Deriv>(dom_vals, derivs_domain); +#endif // Create a SplineBuilderBatched over BSplines and batched along other dimensions using some boundary conditions ddc::SplineBuilderBatched< - ddc::SplineBuilder< - ExecSpace, - MemorySpace, - BSplines, - IDim, - ddc::BoundCond::PERIODIC, - ddc::BoundCond::PERIODIC>, + ddc::SplineBuilder, IDim, s_bcl, s_bcr>, IDim...> spline_builder(dom_vals); @@ -202,12 +237,68 @@ static void BatchedPeriodicSplineTest() vals(e) = vals1(ddc::select>(e)); }); +#if defined(BC_HERMITE) + // Allocate and fill a chunk containing derivs to be passed as input to spline_builder. + int constexpr shift = s_degree_x % 2; // shift = 0 for even order, 1 for odd order + ddc::Chunk Sderiv_lhs_alloc(dom_derivs, ddc::KokkosAllocator()); + ddc::ChunkSpan Sderiv_lhs = Sderiv_lhs_alloc.span_view(); + if (s_bcl == ddc::BoundCond::HERMITE) { + ddc::Chunk Sderiv_lhs1_cpu_alloc(derivs_domain, ddc::HostAllocator()); + ddc::ChunkSpan Sderiv_lhs1_cpu = Sderiv_lhs1_cpu_alloc.span_view(); + for (int ii = 1; ii < Sderiv_lhs1_cpu.domain().template extent>() + 1; ++ii) { + Sderiv_lhs1_cpu(typename decltype(Sderiv_lhs1_cpu.domain())::discrete_element_type(ii)) + = evaluator.deriv(x0(), ii + shift - 1); + } + ddc::Chunk Sderiv_lhs1_alloc(derivs_domain, ddc::KokkosAllocator()); + ddc::ChunkSpan Sderiv_lhs1 = Sderiv_lhs1_alloc.span_view(); + ddc::deepcopy(Sderiv_lhs1, Sderiv_lhs1_cpu); + + ddc::for_each( + ddc::policies::policy(exec_space), + Sderiv_lhs.domain(), + KOKKOS_LAMBDA( + typename decltype(Sderiv_lhs.domain())::discrete_element_type const e) { + Sderiv_lhs(e) = Sderiv_lhs1(ddc::select>(e)); + }); + } + + ddc::Chunk Sderiv_rhs_alloc(dom_derivs, ddc::KokkosAllocator()); + ddc::ChunkSpan Sderiv_rhs = Sderiv_rhs_alloc.span_view(); + if (s_bcr == ddc::BoundCond::HERMITE) { + ddc::Chunk Sderiv_rhs1_cpu_alloc(derivs_domain, ddc::HostAllocator()); + ddc::ChunkSpan Sderiv_rhs1_cpu = Sderiv_rhs1_cpu_alloc.span_view(); + for (int ii = 1; ii < Sderiv_rhs1_cpu.domain().template extent>() + 1; ++ii) { + Sderiv_rhs1_cpu(typename decltype(Sderiv_rhs1_cpu.domain())::discrete_element_type(ii)) + = evaluator.deriv(xN(), ii + shift - 1); + } + ddc::Chunk Sderiv_rhs1_alloc(derivs_domain, ddc::KokkosAllocator()); + ddc::ChunkSpan Sderiv_rhs1 = Sderiv_rhs1_alloc.span_view(); + ddc::deepcopy(Sderiv_rhs1, Sderiv_rhs1_cpu); + + ddc::for_each( + ddc::policies::policy(exec_space), + Sderiv_rhs.domain(), + KOKKOS_LAMBDA( + typename decltype(Sderiv_rhs.domain())::discrete_element_type const e) { + Sderiv_rhs(e) = Sderiv_rhs1(ddc::select>(e)); + }); + } +#endif + // Instantiate chunk of spline coefs to receive output of spline_builder ddc::Chunk coef_alloc(dom_spline, ddc::KokkosAllocator()); ddc::ChunkSpan coef = coef_alloc.span_view(); // Finally compute the spline by filling `coef` - spline_builder(coef, vals); +#if defined(BC_HERMITE) + spline_builder( + coef, + vals.span_cview(), + std::optional(Sderiv_lhs.span_cview()), + std::optional(Sderiv_rhs.span_cview())); +#else + spline_builder(coef, vals.span_cview()); +#endif // Instantiate a SplineEvaluator over interest dimension and batched along other dimensions ddc::SplineEvaluatorBatched< @@ -291,27 +382,41 @@ static void BatchedPeriodicSplineTest() 1.0e-14 * max_norm_int)); } -TEST(BatchedPeriodicSplineHost, 1DX) +#if defined(BC_PERIODIC) && defined(BSPLINES_TYPE_UNIFORM) +#define SUFFIX(name) name##Periodic##Uniform +#elif defined(BC_PERIODIC) && defined(BSPLINES_TYPE_NON_UNIFORM) +#define SUFFIX(name) name##Periodic##NonUniform +#elif defined(BC_GREVILLE) && defined(BSPLINES_TYPE_UNIFORM) +#define SUFFIX(name) name##Greville##Uniform +#elif defined(BC_GREVILLE) && defined(BSPLINES_TYPE_NON_UNIFORM) +#define SUFFIX(name) name##Greville##NonUniform +#elif defined(BC_HERMITE) && defined(BSPLINES_TYPE_UNIFORM) +#define SUFFIX(name) name##Hermite##Uniform +#elif defined(BC_HERMITE) && defined(BSPLINES_TYPE_NON_UNIFORM) +#define SUFFIX(name) name##Hermite##NonUniform +#endif + +TEST(SUFFIX(BatchedSplineHost), 1DX) { - BatchedPeriodicSplineTest< + BatchedSplineTest< Kokkos::DefaultHostExecutionSpace, Kokkos::DefaultHostExecutionSpace::memory_space, DimX, DimX>(); } -TEST(BatchedPeriodicSplineDevice, 1DX) +TEST(SUFFIX(BatchedSplineDevice), 1DX) { - BatchedPeriodicSplineTest< + BatchedSplineTest< Kokkos::DefaultExecutionSpace, Kokkos::DefaultExecutionSpace::memory_space, DimX, DimX>(); } -TEST(BatchedPeriodicSplineHost, 2DX) +TEST(SUFFIX(BatchedSplineHost), 2DX) { - BatchedPeriodicSplineTest< + BatchedSplineTest< Kokkos::DefaultHostExecutionSpace, Kokkos::DefaultHostExecutionSpace::memory_space, DimX, @@ -319,9 +424,9 @@ TEST(BatchedPeriodicSplineHost, 2DX) DimY>(); } -TEST(BatchedPeriodicSplineHost, 2DY) +TEST(SUFFIX(BatchedSplineHost), 2DY) { - BatchedPeriodicSplineTest< + BatchedSplineTest< Kokkos::DefaultHostExecutionSpace, Kokkos::DefaultHostExecutionSpace::memory_space, DimY, @@ -329,9 +434,9 @@ TEST(BatchedPeriodicSplineHost, 2DY) DimY>(); } -TEST(BatchedPeriodicSplineDevice, 2DX) +TEST(SUFFIX(BatchedSplineDevice), 2DX) { - BatchedPeriodicSplineTest< + BatchedSplineTest< Kokkos::DefaultExecutionSpace, Kokkos::DefaultExecutionSpace::memory_space, DimX, @@ -339,9 +444,9 @@ TEST(BatchedPeriodicSplineDevice, 2DX) DimY>(); } -TEST(BatchedPeriodicSplineDevice, 2DY) +TEST(SUFFIX(BatchedSplineDevice), 2DY) { - BatchedPeriodicSplineTest< + BatchedSplineTest< Kokkos::DefaultExecutionSpace, Kokkos::DefaultExecutionSpace::memory_space, DimY, @@ -349,9 +454,9 @@ TEST(BatchedPeriodicSplineDevice, 2DY) DimY>(); } -TEST(BatchedPeriodicSplineHost, 3DX) +TEST(SUFFIX(BatchedSplineHost), 3DX) { - BatchedPeriodicSplineTest< + BatchedSplineTest< Kokkos::DefaultHostExecutionSpace, Kokkos::DefaultHostExecutionSpace::memory_space, DimX, @@ -360,9 +465,9 @@ TEST(BatchedPeriodicSplineHost, 3DX) DimZ>(); } -TEST(BatchedPeriodicSplineHost, 3DY) +TEST(SUFFIX(BatchedSplineHost), 3DY) { - BatchedPeriodicSplineTest< + BatchedSplineTest< Kokkos::DefaultHostExecutionSpace, Kokkos::DefaultHostExecutionSpace::memory_space, DimY, @@ -371,9 +476,9 @@ TEST(BatchedPeriodicSplineHost, 3DY) DimZ>(); } -TEST(BatchedPeriodicSplineHost, 3DZ) +TEST(SUFFIX(BatchedSplineHost), 3DZ) { - BatchedPeriodicSplineTest< + BatchedSplineTest< Kokkos::DefaultHostExecutionSpace, Kokkos::DefaultHostExecutionSpace::memory_space, DimZ, @@ -382,9 +487,9 @@ TEST(BatchedPeriodicSplineHost, 3DZ) DimZ>(); } -TEST(BatchedPeriodicSplineDevice, 3DX) +TEST(SUFFIX(BatchedSplineDevice), 3DX) { - BatchedPeriodicSplineTest< + BatchedSplineTest< Kokkos::DefaultExecutionSpace, Kokkos::DefaultExecutionSpace::memory_space, DimX, @@ -393,9 +498,9 @@ TEST(BatchedPeriodicSplineDevice, 3DX) DimZ>(); } -TEST(BatchedPeriodicSplineDevice, 3DY) +TEST(SUFFIX(BatchedSplineDevice), 3DY) { - BatchedPeriodicSplineTest< + BatchedSplineTest< Kokkos::DefaultExecutionSpace, Kokkos::DefaultExecutionSpace::memory_space, DimY, @@ -404,9 +509,9 @@ TEST(BatchedPeriodicSplineDevice, 3DY) DimZ>(); } -TEST(BatchedPeriodicSplineDevice, 3DZ) +TEST(SUFFIX(BatchedSplineDevice), 3DZ) { - BatchedPeriodicSplineTest< + BatchedSplineTest< Kokkos::DefaultExecutionSpace, Kokkos::DefaultExecutionSpace::memory_space, DimZ, @@ -416,9 +521,9 @@ TEST(BatchedPeriodicSplineDevice, 3DZ) } -TEST(BatchedPeriodicSplineHost, 4DX) +TEST(SUFFIX(BatchedSplineHost), 4DX) { - BatchedPeriodicSplineTest< + BatchedSplineTest< Kokkos::DefaultHostExecutionSpace, Kokkos::DefaultHostExecutionSpace::memory_space, DimX, @@ -428,9 +533,9 @@ TEST(BatchedPeriodicSplineHost, 4DX) DimT>(); } -TEST(BatchedPeriodicSplineHost, 4DY) +TEST(SUFFIX(BatchedSplineHost), 4DY) { - BatchedPeriodicSplineTest< + BatchedSplineTest< Kokkos::DefaultHostExecutionSpace, Kokkos::DefaultHostExecutionSpace::memory_space, DimY, @@ -440,9 +545,9 @@ TEST(BatchedPeriodicSplineHost, 4DY) DimT>(); } -TEST(BatchedPeriodicSplineHost, 4DZ) +TEST(SUFFIX(BatchedSplineHost), 4DZ) { - BatchedPeriodicSplineTest< + BatchedSplineTest< Kokkos::DefaultHostExecutionSpace, Kokkos::DefaultHostExecutionSpace::memory_space, DimZ, @@ -452,9 +557,9 @@ TEST(BatchedPeriodicSplineHost, 4DZ) DimT>(); } -TEST(BatchedPeriodicSplineHost, 4DT) +TEST(SUFFIX(BatchedSplineHost), 4DT) { - BatchedPeriodicSplineTest< + BatchedSplineTest< Kokkos::DefaultHostExecutionSpace, Kokkos::DefaultHostExecutionSpace::memory_space, DimT, @@ -464,9 +569,9 @@ TEST(BatchedPeriodicSplineHost, 4DT) DimT>(); } -TEST(BatchedPeriodicSplineDevice, 4DX) +TEST(SUFFIX(BatchedSplineDevice), 4DX) { - BatchedPeriodicSplineTest< + BatchedSplineTest< Kokkos::DefaultExecutionSpace, Kokkos::DefaultExecutionSpace::memory_space, DimX, @@ -476,9 +581,9 @@ TEST(BatchedPeriodicSplineDevice, 4DX) DimT>(); } -TEST(BatchedPeriodicSplineDevice, 4DY) +TEST(SUFFIX(BatchedSplineDevice), 4DY) { - BatchedPeriodicSplineTest< + BatchedSplineTest< Kokkos::DefaultExecutionSpace, Kokkos::DefaultExecutionSpace::memory_space, DimY, @@ -488,9 +593,9 @@ TEST(BatchedPeriodicSplineDevice, 4DY) DimT>(); } -TEST(BatchedPeriodicSplineDevice, 4DZ) +TEST(SUFFIX(BatchedSplineDevice), 4DZ) { - BatchedPeriodicSplineTest< + BatchedSplineTest< Kokkos::DefaultExecutionSpace, Kokkos::DefaultExecutionSpace::memory_space, DimZ, @@ -500,9 +605,9 @@ TEST(BatchedPeriodicSplineDevice, 4DZ) DimT>(); } -TEST(BatchedPeriodicSplineDevice, 4DT) +TEST(SUFFIX(BatchedSplineDevice), 4DT) { - BatchedPeriodicSplineTest< + BatchedSplineTest< Kokkos::DefaultExecutionSpace, Kokkos::DefaultExecutionSpace::memory_space, DimT, diff --git a/vendor/ddc/tests/splines/evaluator_2d.hpp b/vendor/ddc/tests/splines/evaluator_2d.hpp new file mode 100644 index 000000000..50bf30ca0 --- /dev/null +++ b/vendor/ddc/tests/splines/evaluator_2d.hpp @@ -0,0 +1,85 @@ +#pragma once + +#include + +struct Evaluator2D +{ + template + class Evaluator + { + private: + Eval1 eval_func1; + Eval2 eval_func2; + + public: + template + explicit Evaluator(Domain domain) + : eval_func1(ddc::select(domain)) + , eval_func2(ddc::select(domain)) + { + } + + KOKKOS_FUNCTION double operator()(double const x, double const y) const noexcept + { + return eval_func1(x) * eval_func2(y); + } + + template + KOKKOS_FUNCTION double operator()(ddc::Coordinate const x) const noexcept + { + return eval_func1(ddc::get(x)) * eval_func2(ddc::get(x)); + } + + template + void operator()(ddc::ChunkSpan> chunk) const + { + auto const& domain = chunk.domain(); + + for (ddc::DiscreteElement const i : ddc::select(domain)) { + for (ddc::DiscreteElement const j : ddc::select(domain)) { + chunk(i, j) = eval_func1(ddc::coordinate(i)) * eval_func2(ddc::coordinate(j)); + } + } + } + + KOKKOS_FUNCTION double deriv( + double const x, + double const y, + int const derivative_x, + int const derivative_y) const noexcept + { + return eval_func1.deriv(x, derivative_x) * eval_func2.deriv(y, derivative_y); + } + + template + KOKKOS_FUNCTION double deriv( + ddc::Coordinate const x, + int const derivative_x, + int const derivative_y) const noexcept + { + return eval_func1.deriv(ddc::get(x), derivative_x) + * eval_func2.deriv(ddc::get(x), derivative_y); + } + + template + void deriv( + ddc::ChunkSpan> chunk, + int const derivative_x, + int const derivative_y) const + { + auto const& domain = chunk.domain(); + + for (ddc::DiscreteElement const i : ddc::select(domain)) { + for (ddc::DiscreteElement const j : ddc::select(domain)) { + chunk(i, j) = eval_func1.deriv(ddc::coordinate(i), derivative_x) + * eval_func2.deriv(ddc::coordinate(j), derivative_y); + } + } + } + + KOKKOS_FUNCTION double max_norm(int diff1 = 0, int diff2 = 0) const + { + return eval_func1.max_norm(diff1) * eval_func2.max_norm(diff2); + } + }; +}; diff --git a/vendor/ddc/tests/splines/non_periodic_spline_builder.cpp b/vendor/ddc/tests/splines/non_periodic_spline_builder.cpp new file mode 100644 index 000000000..8ebfdd779 --- /dev/null +++ b/vendor/ddc/tests/splines/non_periodic_spline_builder.cpp @@ -0,0 +1,189 @@ +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include + +#include "cosine_evaluator.hpp" +#include "polynomial_evaluator.hpp" +#include "spline_error_bounds.hpp" + +struct DimX +{ + static constexpr bool PERIODIC = false; +}; + +static constexpr std::size_t s_degree_x = DEGREE_X; + +#if defined(BCL_GREVILLE) +static constexpr ddc::BoundCond s_bcl = ddc::BoundCond::GREVILLE; +#elif defined(BCL_HERMITE) +static constexpr ddc::BoundCond s_bcl = ddc::BoundCond::HERMITE; +#endif + +#if defined(BCR_GREVILLE) +static constexpr ddc::BoundCond s_bcr = ddc::BoundCond::GREVILLE; +#elif defined(BCR_HERMITE) +static constexpr ddc::BoundCond s_bcr = ddc::BoundCond::HERMITE; +#endif + +#if defined(BSPLINES_TYPE_UNIFORM) +using BSplinesX = ddc::UniformBSplines; +#elif defined(BSPLINES_TYPE_NON_UNIFORM) +using BSplinesX = ddc::NonUniformBSplines; +#endif + +using GrevillePoints = ddc::GrevilleInterpolationPoints; + +using IDimX = GrevillePoints::interpolation_mesh_type; + +#if defined(EVALUATOR_COSINE) +using evaluator_type = CosineEvaluator::Evaluator; +#elif defined(EVALUATOR_POLYNOMIAL) +using evaluator_type = PolynomialEvaluator::Evaluator; +#endif + +using IndexX = ddc::DiscreteElement; +using DVectX = ddc::DiscreteVector; +using BsplIndexX = ddc::DiscreteElement; +using SplineX = ddc::Chunk>; +using FieldX = ddc::Chunk>; +using CoordX = ddc::Coordinate; + +// Checks that when evaluating the spline at interpolation points one +// recovers values that were used to build the spline +TEST(NonPeriodicSplineBuilderTest, Identity) +{ + CoordX constexpr x0(0.); + CoordX constexpr xN(1.); + std::size_t constexpr ncells = 100; + + // 1. Create BSplines + { +#if defined(BSPLINES_TYPE_UNIFORM) + ddc::init_discrete_space(x0, xN, ncells); +#elif defined(BSPLINES_TYPE_NON_UNIFORM) + DVectX constexpr npoints(ncells + 1); + std::vector breaks(npoints); + double dx = (xN - x0) / ncells; + for (int i(0); i < npoints; ++i) { + breaks[i] = CoordX(x0 + i * dx); + } + ddc::init_discrete_space(breaks); +#endif + } + ddc::DiscreteDomain const dom_bsplines_x( + ddc::discrete_space().full_domain()); + + // 2. Create a Spline represented by a chunk over BSplines + // The chunk is filled with garbage data, we need to initialize it + ddc::Chunk coef(dom_bsplines_x, ddc::KokkosAllocator()); + + // 3. Create the interpolation domain + ddc::init_discrete_space(GrevillePoints::get_sampling()); + ddc::DiscreteDomain interpolation_domain(GrevillePoints::get_domain()); + + // 4. Create a SplineBuilder over BSplines using some boundary conditions + ddc::SplineBuilder< + Kokkos::DefaultHostExecutionSpace, + Kokkos::HostSpace, + BSplinesX, + IDimX, + s_bcl, + s_bcr> + spline_builder(interpolation_domain); + + // 5. Allocate and fill a chunk over the interpolation domain + ddc::Chunk yvals(interpolation_domain, ddc::KokkosAllocator()); + evaluator_type evaluator(interpolation_domain); + evaluator(yvals.span_view()); + + int constexpr shift = s_degree_x % 2; // shift = 0 for even order, 1 for odd order + std::array Sderiv_lhs_data; + ddc::DSpan1D Sderiv_lhs(Sderiv_lhs_data.data(), Sderiv_lhs_data.size()); + std::optional deriv_l; + if (s_bcl == ddc::BoundCond::HERMITE) { + for (std::size_t ii = 0; ii < Sderiv_lhs.extent(0); ++ii) { + Sderiv_lhs(ii) = evaluator.deriv(x0, ii + shift); + } + deriv_l = Sderiv_lhs; + } + + std::array Sderiv_rhs_data; + ddc::DSpan1D Sderiv_rhs(Sderiv_rhs_data.data(), Sderiv_rhs_data.size()); + std::optional deriv_r; + if (s_bcr == ddc::BoundCond::HERMITE) { + for (std::size_t ii = 0; ii < Sderiv_rhs.extent(0); ++ii) { + Sderiv_rhs(ii) = evaluator.deriv(xN, ii + shift); + } + deriv_r = Sderiv_rhs; + } + + // 6. Finally build the spline by filling `coef` + spline_builder(coef.span_view(), yvals.span_cview(), deriv_l, deriv_r); + + // 7. Create a SplineEvaluator to evaluate the spline at any point in the domain of the BSplines + ddc::SplineEvaluator + spline_evaluator(ddc::g_null_boundary, ddc::g_null_boundary); + + ddc::Chunk, ddc::DiscreteDomain> coords_eval(interpolation_domain); + for (IndexX const ix : interpolation_domain) { + coords_eval(ix) = ddc::coordinate(ix); + } + + ddc::Chunk spline_eval(interpolation_domain, ddc::KokkosAllocator()); + spline_evaluator(spline_eval.span_view(), coords_eval.span_cview(), coef.span_cview()); + + ddc::Chunk spline_eval_deriv( + interpolation_domain, + ddc::KokkosAllocator()); + spline_evaluator + .deriv(spline_eval_deriv.span_view(), coords_eval.span_cview(), coef.span_cview()); + + // 8. Checking errors + double max_norm_error = 0.; + double max_norm_error_diff = 0.; + for (IndexX const ix : interpolation_domain) { + CoordX const x = ddc::coordinate(ix); + + // Compute error + double const error = spline_eval(ix) - yvals(ix); + max_norm_error = std::fmax(max_norm_error, std::fabs(error)); + + // Compute error + double const error_deriv = spline_eval_deriv(ix) - evaluator.deriv(x, 1); + max_norm_error_diff = std::fmax(max_norm_error_diff, std::fabs(error_deriv)); + } + double const max_norm_error_integ = std::fabs( + spline_evaluator.integrate(coef.span_cview()) - evaluator.deriv(xN, -1) + + evaluator.deriv(x0, -1)); + double const max_norm = evaluator.max_norm(); + double const max_norm_diff = evaluator.max_norm(1); + double const max_norm_int = evaluator.max_norm(-1); + if constexpr (std::is_same_v< + evaluator_type, + PolynomialEvaluator::Evaluator>) { + EXPECT_LE(max_norm_error / max_norm, 1.0e-14); + EXPECT_LE(max_norm_error_diff / max_norm_diff, 1.0e-12); + EXPECT_LE(max_norm_error_integ / max_norm_int, 1.0e-14); + } else { + SplineErrorBounds error_bounds(evaluator); + const double h = (xN - x0) / ncells; + EXPECT_LE( + max_norm_error, + std::max(error_bounds.error_bound(h, s_degree_x), 1.0e-14 * max_norm)); + EXPECT_LE( + max_norm_error_diff, + std::max(error_bounds.error_bound_on_deriv(h, s_degree_x), 1e-12 * max_norm_diff)); + EXPECT_LE( + max_norm_error_integ, + std::max(error_bounds.error_bound_on_int(h, s_degree_x), 1.0e-14 * max_norm_int)); + } +} diff --git a/vendor/ddc/tests/splines/periodic_spline_builder.cpp b/vendor/ddc/tests/splines/periodic_spline_builder.cpp index bb29c9066..91d63d67d 100644 --- a/vendor/ddc/tests/splines/periodic_spline_builder.cpp +++ b/vendor/ddc/tests/splines/periodic_spline_builder.cpp @@ -89,7 +89,7 @@ TEST(PeriodicSplineBuilderTest, Identity) evaluator(yvals); // 6. Finally build the spline by filling `coef` - spline_builder(coef.span_view(), yvals.span_view()); + spline_builder(coef.span_view(), yvals.span_cview()); // 7. Create a SplineEvaluator to evaluate the spline at any point in the domain of the BSplines ddc::SplineEvaluator diff --git a/vendor/ddc/tests/splines/periodicity_spline_builder.cpp b/vendor/ddc/tests/splines/periodicity_spline_builder.cpp index 69f8f630a..d9f1e9f59 100644 --- a/vendor/ddc/tests/splines/periodicity_spline_builder.cpp +++ b/vendor/ddc/tests/splines/periodicity_spline_builder.cpp @@ -68,14 +68,14 @@ static constexpr Coord xN() // Templated function giving step of the mesh in given dimension. template -static constexpr double dx(double ncells) +static constexpr double dx(std::size_t ncells) { return (xN() - x0()) / ncells; } // Templated function giving break points of mesh in given dimension for non-uniform case. template -static constexpr std::vector> breaks(double ncells) +static std::vector> breaks(std::size_t ncells) { std::vector> out(ncells + 1); for (int i(0); i < ncells + 1; ++i) { @@ -153,7 +153,7 @@ static void PeriodicitySplineBuilderTest() ddc::ChunkSpan coef = coef_alloc.span_view(); // Finally compute the spline by filling `coef` - spline_builder(coef, vals); + spline_builder(coef, vals.span_cview()); // Instantiate a SplineEvaluator over interest dimension and batched along other dimensions ddc::SplineEvaluatorBatched< diff --git a/vendor/ddc/tests/splines/polynomial_evaluator.hpp b/vendor/ddc/tests/splines/polynomial_evaluator.hpp index 32e0fa447..dbc789fcb 100644 --- a/vendor/ddc/tests/splines/polynomial_evaluator.hpp +++ b/vendor/ddc/tests/splines/polynomial_evaluator.hpp @@ -32,7 +32,7 @@ struct PolynomialEvaluator } } - double operator()(double const x) const noexcept + KOKKOS_FUNCTION double operator()(double const x) const noexcept { return eval(x, 0); } @@ -46,7 +46,7 @@ struct PolynomialEvaluator } } - double deriv(double const x, int const derivative) const noexcept + KOKKOS_FUNCTION double deriv(double const x, int const derivative) const noexcept { return eval(x, derivative); } @@ -61,24 +61,25 @@ struct PolynomialEvaluator } } - double max_norm(int diff = 0) const + KOKKOS_FUNCTION double max_norm(int diff = 0) const { - return std::abs(deriv(m_xN, diff)); + return Kokkos::abs(deriv(m_xN, diff)); } private: - double eval(double const x, int const derivative) const + KOKKOS_FUNCTION double eval(double const x, int const derivative) const { double result(0.0); int start = derivative < 0 ? 0 : derivative; for (int i(start); i < m_degree + 1; ++i) { - double v = double(falling_factorial(i, derivative)) * std::pow(x, i - derivative); + double v + = double(falling_factorial(i, derivative)) * Kokkos::pow(x, i - derivative); result += m_coeffs[i] * v; } return result; } - double falling_factorial(int i, int d) const + KOKKOS_FUNCTION double falling_factorial(int i, int d) const { double c = 1.0; if (d >= 0) {