Gyselalib++
non_uniform_interpolation_points.hpp
1 // SPDX-License-Identifier: MIT
2 
3 #pragma once
4 
5 #include <cassert>
6 #include <cmath>
7 
8 #include <ddc/ddc.hpp>
9 #include <ddc/kernels/splines.hpp>
10 
11 #include "ddc_aliases.hpp"
12 
13 namespace ddcHelper {
14 
15 template <class BSplines, ddc::BoundCond BcXmin, ddc::BoundCond BcXmax>
16 class NonUniformInterpolationPoints;
17 
18 template <class T>
19 struct is_non_uniform_interpolation_points : std::false_type
20 {
21 };
22 
23 template <class BSplines, ddc::BoundCond BcXmin, ddc::BoundCond BcXmax>
25  : std::true_type
26 {
27 };
28 
29 template <class T>
30 inline constexpr bool is_non_uniform_interpolation_points_v
32 
42 template <class BSplines, ddc::BoundCond BcXmin, ddc::BoundCond BcXmax>
44 {
45  using Dim = typename BSplines::continuous_dimension_type;
46  using BreakPointsType = std::conditional_t<
47  BSplines::is_uniform(),
48  ddc::UniformBsplinesKnots<BSplines>,
49  ddc::NonUniformBsplinesKnots<BSplines>>;
50  using IdxBreakPoints = Idx<BreakPointsType>;
51 
52 public:
54  static constexpr int N_BE_MIN = n_boundary_equations(BcXmin, BSplines::degree());
56  static constexpr int N_BE_MAX = n_boundary_equations(BcXmax, BSplines::degree());
57 
58 private:
59  static void check_n_points_in_cell(int n_points_in_cell, IdxBreakPoints current_cell_end_idx)
60  {
61  if (n_points_in_cell > BSplines::degree() + 1) {
62  IdxBreakPoints rmin_idx = ddc::discrete_space<BSplines>().break_point_domain().front();
63  int failed_cell = (current_cell_end_idx - rmin_idx).value();
64  throw std::runtime_error(
65  "The spline problem is overconstrained. There are "
66  + std::to_string(n_points_in_cell) + " points in the "
67  + std::to_string(failed_cell) + "-th cell.");
68  }
69  }
70 
71 public:
80  template <typename Sampling, typename U = BSplines>
81  static auto get_sampling(std::vector<Coord<Dim>>& interp_points, double TOL = 2e-14)
82  {
83  int const expected_npoints = ddc::discrete_space<BSplines>().nbasis() - N_BE_MIN - N_BE_MAX;
84  if (interp_points.size() != expected_npoints) {
85  throw std::runtime_error(
86  "Incorrect number of points supplied to NonUniformInterpolationPoints. "
87  "(Received : "
88  + std::to_string(interp_points.size())
89  + ", expected : " + std::to_string(expected_npoints));
90  }
91  if constexpr (BSplines::is_periodic()) {
92  double domain_len = ddc::discrete_space<BSplines>().rmax()
93  - ddc::discrete_space<BSplines>().rmin();
94  // Insert final periodic point to ensure all cell sizes are known
95  interp_points.push_back(interp_points.back() + domain_len);
96  }
97  int n_points_in_cell = 0;
98  IdxBreakPoints current_cell_end_idx
99  = ddc::discrete_space<BSplines>().break_point_domain().front() + 1;
100  for (Coord<Dim> point : interp_points) {
101  if (point == ddc::coordinate(current_cell_end_idx)) {
102  check_n_points_in_cell(n_points_in_cell + 1, current_cell_end_idx);
103  n_points_in_cell = 1;
104  } else if (point > ddc::coordinate(current_cell_end_idx)) {
105  check_n_points_in_cell(n_points_in_cell, current_cell_end_idx);
106  n_points_in_cell = 1;
107  } else {
108  n_points_in_cell += 1;
109  }
110  }
111  check_n_points_in_cell(n_points_in_cell, current_cell_end_idx);
112 
113  if constexpr (ddc::is_non_uniform_point_sampling_v<Sampling>) {
114  using SamplingImpl = typename Sampling::template Impl<Sampling, Kokkos::HostSpace>;
115  return SamplingImpl(interp_points);
116  } else {
117  using SamplingImpl = typename Sampling::template Impl<Sampling, Kokkos::HostSpace>;
118  SamplingImpl result(interp_points[0], interp_points[1] - interp_points[0]);
119  IdxRange<Sampling> idx_range(get_domain<Sampling>());
120  bool same_points = ddc::transform_reduce(
121  idx_range,
122  true,
123  ddc::reducer::land<bool>(),
124  [&](Idx<Sampling> idx) {
125  return fabs(result.coordinate(idx) - interp_points[idx - idx_range.front()])
126  < TOL;
127  });
128  if (!same_points) {
129  throw std::runtime_error("Provided points are not uniform");
130  }
131  return result;
132  }
133  }
134 
135 
141  template <typename Sampling>
142  static IdxRange<Sampling> get_domain()
143  {
144  int const npoints = ddc::discrete_space<BSplines>().nbasis() - N_BE_MIN - N_BE_MAX;
145  return IdxRange<Sampling>(Idx<Sampling>(0), IdxStep<Sampling>(npoints));
146  }
147 
153  using interpolation_discrete_dimension_type = NonUniformGridBase<Dim>;
154 };
155 } // namespace ddcHelper
Helper class for the initialisation of the mesh of interpolation points.
Definition: non_uniform_interpolation_points.hpp:44
static IdxRange< Sampling > get_domain()
Get the domain which can be used to access the interpolation points in the sampling.
Definition: non_uniform_interpolation_points.hpp:142
static constexpr int N_BE_MIN
The number of boundary equations at the lower bound in a spline interpolation.
Definition: non_uniform_interpolation_points.hpp:54
static constexpr int N_BE_MAX
The number of boundary equations at the upper bound in a spline interpolation.
Definition: non_uniform_interpolation_points.hpp:56
static auto get_sampling(std::vector< Coord< Dim >> &interp_points, double TOL=2e-14)
Get the sampling of interpolation points.
Definition: non_uniform_interpolation_points.hpp:81
NonUniformGridBase< Dim > interpolation_discrete_dimension_type
The type of the mesh.
Definition: non_uniform_interpolation_points.hpp:153
Definition: non_uniform_interpolation_points.hpp:20