DDC 0.14.0
Loading...
Searching...
No Matches
greville_interpolation_points.hpp
1// Copyright (C) The DDC development team, see COPYRIGHT.md file
2//
3// SPDX-License-Identifier: MIT
4
5#pragma once
6
7#include <cassert>
8#include <cstddef>
9#include <type_traits>
10#include <vector>
11
12#include <ddc/ddc.hpp>
13
14#include <Kokkos_Core.hpp>
15
19
20namespace ddc {
21
22/**
23 * A class which provides helper functions to initialise the Greville points from a B-Spline definition.
24 *
25 * @tparam BSplines The bspline class relative to which the Greville points will be calculated.
26 * @tparam BcLower The lower boundary condition that will be used to build the splines.
27 * @tparam BcUpper The upper boundary condition that will be used to build the splines.
28 */
29template <class BSplines, ddc::BoundCond BcLower, ddc::BoundCond BcUpper>
31{
32 using continuous_dimension_type = BSplines::continuous_dimension_type;
33
34 template <class Sampling>
35 struct IntermediateUniformSampling
37 {
38 };
39
40 template <class Sampling>
41 struct IntermediateNonUniformSampling
43 {
44 };
45
46 template <class Sampling>
47 static auto uniform_greville_points()
48 requires(BSplines::is_uniform())
49 {
50 using SamplingImpl = Sampling::template Impl<Sampling, Kokkos::HostSpace>;
51
52 double constexpr shift = (BSplines::degree() % 2 == 0) ? 0.5 : 0.0;
53 double const dx
54 = (ddc::discrete_space<BSplines>().rmax() - ddc::discrete_space<BSplines>().rmin())
55 / ddc::discrete_space<BSplines>().ncells();
56 if constexpr (ddc::is_uniform_point_sampling_v<Sampling>) {
57 return SamplingImpl(
58 ddc::Coordinate<continuous_dimension_type>(
59 ddc::discrete_space<BSplines>().rmin() + shift * dx),
60 ddc::Coordinate<continuous_dimension_type>(dx));
61 } else {
62 std::size_t const npoints = ddc::discrete_space<BSplines>().nbasis() - N_BE;
63 std::vector<ddc::Coordinate<continuous_dimension_type>> grid_points(npoints);
64 for (std::size_t i(0); i < npoints; ++i) {
65 grid_points[i] = ddc::discrete_space<BSplines>().rmin() + (shift + i) * dx;
66 }
67 return SamplingImpl(grid_points);
68 }
69 }
70
71 template <class Sampling>
72 static auto non_uniform_greville_points()
73 requires(!BSplines::is_uniform())
74 {
75 using SamplingImpl = Sampling::template Impl<Sampling, Kokkos::HostSpace>;
76
77 std::size_t n_greville_points = 0;
78 if constexpr (BSplines::is_periodic()) {
79 n_greville_points = ddc::discrete_space<BSplines>().nbasis() + 1;
80 } else {
81 n_greville_points = ddc::discrete_space<BSplines>().nbasis();
82 }
83
84 std::vector<double> greville_points(n_greville_points);
85 ddc::DiscreteDomain<BSplines> const bspline_domain
86 = ddc::discrete_space<BSplines>().full_domain().take_first(
87 ddc::DiscreteVector<BSplines>(ddc::discrete_space<BSplines>().nbasis()));
88
89 ddc::DiscreteVector<NonUniformBsplinesKnots<BSplines>> n_points_in_average(
90 BSplines::degree());
91
92 ddc::DiscreteElement<BSplines> ib0(bspline_domain.front());
93
94 ddc::host_for_each(bspline_domain, [&](ddc::DiscreteElement<BSplines> ib) {
95 // Define the Greville points from the bspline knots
96 greville_points[ib - ib0] = 0.0;
97 ddc::DiscreteDomain<NonUniformBsplinesKnots<BSplines>> const sub_domain(
98 ddc::discrete_space<BSplines>().get_first_support_knot(ib) + 1,
99 n_points_in_average);
100 ddc::host_for_each(sub_domain, [&](auto ik) {
101 greville_points[ib - ib0] += ddc::coordinate(ik);
102 });
103 greville_points[ib - ib0] /= n_points_in_average.value();
104 });
105
106 // Use periodicity to ensure all points are in the domain
107 if constexpr (BSplines::is_periodic()) {
108 std::vector<double> temp_knots(BSplines::degree());
109 std::size_t npoints = 0;
110 // Count the number of interpolation points that need shifting to preserve the ordering
111 while (greville_points[npoints] < ddc::discrete_space<BSplines>().rmin()) {
112 assert(npoints < BSplines::degree());
113 temp_knots[npoints]
114 = greville_points[npoints] + ddc::discrete_space<BSplines>().length();
115 ++npoints;
116 }
117 // Shift the points
118 for (std::size_t i = 0; i < ddc::discrete_space<BSplines>().nbasis() - npoints; ++i) {
119 greville_points[i] = greville_points[i + npoints];
120 }
121 for (std::size_t i = 0; i < npoints; ++i) {
122 greville_points[ddc::discrete_space<BSplines>().nbasis() - npoints + i]
123 = temp_knots[i];
124 }
125
126 // Save a periodic point to initialise the domain size
127 greville_points[n_greville_points - 1]
128 = greville_points[0] + ddc::discrete_space<BSplines>().length();
129 }
130
131 return SamplingImpl(greville_points);
132 }
133
134 static constexpr std::size_t N_BE_MIN = n_boundary_equations(BcLower, BSplines::degree());
135 static constexpr std::size_t N_BE_MAX = n_boundary_equations(BcUpper, BSplines::degree());
136 static constexpr std::size_t N_BE = N_BE_MIN + N_BE_MAX;
137 template <class U>
138 static constexpr bool is_uniform_discrete_dimension_v
139 = U::is_uniform() && ((N_BE_MIN != 0 && N_BE_MAX != 0) || U::is_periodic());
140
141public:
142 /**
143 * Get the UniformPointSampling defining the Greville points.
144 *
145 * This function is called when the result is a UniformPointSampling. This is the case
146 * when uniform splines are used with an odd degree and with boundary conditions which
147 * do not introduce additional interpolation points.
148 *
149 * @tparam Sampling The discrete dimension supporting the Greville points.
150 *
151 * @returns The mesh of uniform Greville points.
152 */
153 template <class Sampling>
154 static auto get_sampling()
155 requires(is_uniform_discrete_dimension_v<BSplines>)
156 {
157 return uniform_greville_points<Sampling>();
158 }
159
160 /**
161 * Get the NonUniformPointSampling defining the Greville points.
162 *
163 * @tparam Sampling The discrete dimension supporting the Greville points.
164 *
165 * @returns The mesh of non-uniform Greville points.
166 */
167 template <class Sampling>
168 static auto get_sampling()
169 requires(!is_uniform_discrete_dimension_v<BSplines>)
170 {
171 using SamplingImpl = Sampling::template Impl<Sampling, Kokkos::HostSpace>;
172 if constexpr (BSplines::is_uniform()) {
173 using IntermediateSampling = IntermediateUniformSampling<Sampling>;
174 auto points_wo_bcs = uniform_greville_points<IntermediateSampling>();
175 std::size_t const n_break_points = ddc::discrete_space<BSplines>().ncells() + 1;
176 if constexpr (N_BE > 0) {
177 assert(ddc::discrete_space<BSplines>().nbasis() >= N_BE);
178 }
179 std::size_t const npoints = ddc::discrete_space<BSplines>().nbasis() - N_BE;
180 std::vector<double> points_with_bcs(npoints);
181
182 // Construct Greville-like points at the edge
183 if constexpr (BcLower == ddc::BoundCond::GREVILLE) {
184 for (std::size_t i(0); i < BSplines::degree() / 2 + 1; ++i) {
185 points_with_bcs[i]
186 = (BSplines::degree() - i) * ddc::discrete_space<BSplines>().rmin();
187 ddc::DiscreteElement<BSplines> const spline_idx(i);
188 ddc::DiscreteVector<UniformBsplinesKnots<BSplines>> const n_knots_in_domain(i);
189 ddc::DiscreteDomain<UniformBsplinesKnots<BSplines>> const sub_domain(
190 ddc::discrete_space<BSplines>().get_last_support_knot(spline_idx)
191 - n_knots_in_domain,
192 n_knots_in_domain);
193 ddc::host_for_each(
194 sub_domain,
195 [&](ddc::DiscreteElement<UniformBsplinesKnots<BSplines>> ik) {
196 points_with_bcs[i] += ddc::coordinate(ik);
197 });
198 points_with_bcs[i] /= BSplines::degree();
199 }
200 } else {
201 points_with_bcs[0]
202 = points_wo_bcs.coordinate(ddc::DiscreteElement<IntermediateSampling>(0));
203 }
204
205 std::size_t const n_start
206 = (BcLower == ddc::BoundCond::GREVILLE) ? BSplines::degree() / 2 + 1 : 1;
207 std::size_t const domain_size = n_break_points - 2;
208 ddc::DiscreteElement<IntermediateSampling> domain_start(1);
209 ddc::DiscreteDomain<IntermediateSampling> const
210 domain(domain_start, ddc::DiscreteVector<IntermediateSampling>(domain_size));
211
212 // Copy central points
213 ddc::host_for_each(domain, [&](auto ip) {
214 points_with_bcs[ip - domain_start + n_start] = points_wo_bcs.coordinate(ip);
215 });
216
217 // Construct Greville-like points at the edge
218 if constexpr (BcUpper == ddc::BoundCond::GREVILLE) {
219 for (std::size_t i(0); i < BSplines::degree() / 2 + 1; ++i) {
220 points_with_bcs[npoints - 1 - i]
221 = (BSplines::degree() - i) * ddc::discrete_space<BSplines>().rmax();
222 ddc::DiscreteElement<BSplines> const spline_idx(
223 ddc::discrete_space<BSplines>().nbasis() - 1 - i);
224 ddc::DiscreteVector<UniformBsplinesKnots<BSplines>> const n_knots_in_domain(i);
225 ddc::DiscreteDomain<UniformBsplinesKnots<BSplines>> const sub_domain(
226 ddc::discrete_space<BSplines>().get_first_support_knot(spline_idx) + 1,
227 n_knots_in_domain);
228 ddc::host_for_each(
229 sub_domain,
230 [&](ddc::DiscreteElement<UniformBsplinesKnots<BSplines>> ik) {
231 points_with_bcs[npoints - 1 - i] += ddc::coordinate(ik);
232 });
233 points_with_bcs[npoints - 1 - i] /= BSplines::degree();
234 }
235 } else {
236 points_with_bcs[npoints - 1] = points_wo_bcs.coordinate(
237 ddc::DiscreteElement<IntermediateSampling>(
238 ddc::discrete_space<BSplines>().ncells() - 1
239 + BSplines::degree() % 2));
240 }
241 return SamplingImpl(points_with_bcs);
242 } else {
243 using IntermediateSampling = IntermediateNonUniformSampling<Sampling>;
244 if constexpr (N_BE == 0) {
245 return non_uniform_greville_points<Sampling>();
246 } else {
247 auto points_wo_bcs = non_uniform_greville_points<IntermediateSampling>();
248 // All points are Greville points. Extract unnecessary points near the boundary
249 std::vector<double> points_with_bcs(points_wo_bcs.size() - N_BE);
250 std::size_t constexpr n_start = N_BE_MIN;
251
252 using length = ddc::DiscreteVector<IntermediateSampling>;
253
254 ddc::DiscreteElement<IntermediateSampling> domain_start(n_start);
255 ddc::DiscreteDomain<IntermediateSampling> const
256 domain(domain_start, length(points_with_bcs.size()));
257
258 points_with_bcs[0] = points_wo_bcs.coordinate(domain.front());
259 ddc::host_for_each(domain.remove(length(1), length(1)), [&](auto ip) {
260 points_with_bcs[ip - domain_start] = points_wo_bcs.coordinate(ip);
261 });
262 points_with_bcs[points_with_bcs.size() - 1]
263 = points_wo_bcs.coordinate(domain.back());
264
265 return SamplingImpl(points_with_bcs);
266 }
267 }
268 }
269
270 /**
271 * The type of the mesh.
272 *
273 * This is either NonUniformPointSampling or UniformPointSampling.
274 */
275 using interpolation_discrete_dimension_type = std::conditional_t<
276 is_uniform_discrete_dimension_v<BSplines>,
277 ddc::UniformPointSampling<continuous_dimension_type>,
278 ddc::NonUniformPointSampling<continuous_dimension_type>>;
279
280 /**
281 * Get the domain which gives us access to all of the Greville points.
282 *
283 * @tparam Sampling The discrete dimension supporting the Greville points.
284 *
285 * @returns The domain of the Greville points.
286 */
287 template <class Sampling>
288 static ddc::DiscreteDomain<Sampling> get_domain()
289 {
290 std::size_t const npoints = ddc::discrete_space<BSplines>().nbasis() - N_BE;
291 return ddc::DiscreteDomain<Sampling>(
292 ddc::DiscreteElement<Sampling>(0),
293 ddc::DiscreteVector<Sampling>(npoints));
294 }
295};
296
297} // namespace ddc
friend class ChunkSpan
friend class DiscreteDomain
KOKKOS_FUNCTION constexpr bool operator!=(DiscreteVector< OTags... > const &rhs) const noexcept
A class which provides helper functions to initialise the Greville points from a B-Spline definition.
static ddc::DiscreteDomain< Sampling > get_domain()
Get the domain which gives us access to all of the Greville points.
Storage class of the static attributes of the discrete dimension.
Impl & operator=(Impl &&x)=default
Move-assigns.
Impl(RandomIt breaks_begin, RandomIt breaks_end)
Constructs an Impl by iterating over a range of break points from begin to end.
KOKKOS_INLINE_FUNCTION ddc::Coordinate< CDim > rmin() const noexcept
Returns the coordinate of the first break point of the domain on which the B-splines are defined.
Impl(std::vector< ddc::Coordinate< CDim > > const &breaks)
Constructs an Impl using a std::vector.
KOKKOS_INLINE_FUNCTION discrete_element_type eval_basis(DSpan1D values, ddc::Coordinate< CDim > const &x) const
Evaluates non-zero B-splines at a given coordinate.
KOKKOS_INLINE_FUNCTION std::size_t size() const noexcept
Returns the number of elements necessary to construct a spline representation of a function.
Impl(Impl< DDim, OriginMemorySpace > const &impl)
Copy-constructs from another Impl with a different Kokkos memory space.
~Impl()=default
Destructs.
KOKKOS_INLINE_FUNCTION ddc::DiscreteDomain< knot_discrete_dimension_type > break_point_domain() const
Returns the discrete domain which describes the break points.
KOKKOS_INLINE_FUNCTION ddc::DiscreteElement< knot_discrete_dimension_type > get_last_support_knot(discrete_element_type const &ix) const
Returns the coordinate of the last support knot associated to a DiscreteElement identifying a B-splin...
Impl(Impl &&x)=default
Move-constructs.
Impl(std::initializer_list< ddc::Coordinate< CDim > > breaks)
Constructs an Impl using a brace-list, i.e.
KOKKOS_INLINE_FUNCTION discrete_element_type eval_basis_and_n_derivs(ddc::DSpan2D derivs, ddc::Coordinate< CDim > const &x, std::size_t n) const
Evaluates non-zero B-spline values and derivatives at a given coordinate.
KOKKOS_INLINE_FUNCTION std::size_t ncells() const noexcept
Returns the number of cells over which the B-splines are defined.
KOKKOS_INLINE_FUNCTION discrete_domain_type full_domain() const
Returns the discrete domain including eventual additional B-splines in the periodic case.
KOKKOS_INLINE_FUNCTION ddc::DiscreteElement< knot_discrete_dimension_type > get_first_support_knot(discrete_element_type const &ix) const
Returns the coordinate of the first support knot associated to a DiscreteElement identifying a B-spli...
KOKKOS_INLINE_FUNCTION std::size_t npoints() const noexcept
The number of break points.
KOKKOS_INLINE_FUNCTION std::size_t nbasis() const noexcept
Returns the number of basis functions.
Impl(Impl const &x)=default
Copy-constructs.
KOKKOS_INLINE_FUNCTION discrete_element_type eval_deriv(DSpan1D derivs, ddc::Coordinate< CDim > const &x) const
Evaluates non-zero B-spline derivatives at a given coordinate.
KOKKOS_INLINE_FUNCTION double length() const noexcept
Returns the length of the domain.
Impl & operator=(Impl const &x)=default
Copy-assigns.
KOKKOS_INLINE_FUNCTION ddc::Coordinate< CDim > rmax() const noexcept
Returns the coordinate of the last break point of the domain on which the B-splines are defined.
The type of a non-uniform 1D spline basis (B-spline).
static constexpr std::size_t degree() noexcept
The degree of B-splines.
static constexpr bool is_periodic() noexcept
Indicates if the B-splines are periodic or not.
static constexpr bool is_uniform() noexcept
Indicates if the B-splines are uniform or not (this is not the case here).
NonUniformPointSampling models a non-uniform discretization of the CDim segment .
Storage class of the static attributes of the discrete dimension.
KOKKOS_INLINE_FUNCTION ddc::DiscreteElement< knot_discrete_dimension_type > get_last_support_knot(discrete_element_type const &ix) const
Returns the coordinate of the last support knot associated to a DiscreteElement identifying a B-splin...
Impl(ddc::Coordinate< CDim > rmin, ddc::Coordinate< CDim > rmax, std::size_t ncells)
Constructs a spline basis (B-splines) with n equidistant knots over .
KOKKOS_INLINE_FUNCTION ddc::Coordinate< CDim > rmax() const noexcept
Returns the coordinate of the upper bound of the domain on which the B-splines are defined.
KOKKOS_INLINE_FUNCTION discrete_element_type eval_basis(DSpan1D values, ddc::Coordinate< CDim > const &x) const
Evaluates non-zero B-splines at a given coordinate.
KOKKOS_INLINE_FUNCTION ddc::DiscreteDomain< knot_discrete_dimension_type > break_point_domain() const
Returns the discrete domain which describes the break points.
KOKKOS_INLINE_FUNCTION ddc::Coordinate< CDim > rmin() const noexcept
Returns the coordinate of the lower bound of the domain on which the B-splines are defined.
~Impl()=default
Destructs.
KOKKOS_INLINE_FUNCTION std::size_t nbasis() const noexcept
Returns the number of basis functions.
Impl(Impl const &x)=default
Copy-constructs.
KOKKOS_INLINE_FUNCTION std::size_t size() const noexcept
Returns the number of elements necessary to construct a spline representation of a function.
Impl(Impl &&x)=default
Move-constructs.
KOKKOS_INLINE_FUNCTION discrete_element_type eval_basis_and_n_derivs(ddc::DSpan2D derivs, ddc::Coordinate< CDim > const &x, std::size_t n) const
Evaluates non-zero B-spline values and derivatives at a given coordinate.
KOKKOS_INLINE_FUNCTION ddc::DiscreteElement< knot_discrete_dimension_type > get_first_support_knot(discrete_element_type const &ix) const
Returns the coordinate of the first support knot associated to a DiscreteElement identifying a B-spli...
KOKKOS_INLINE_FUNCTION double length() const noexcept
Returns the length of the domain.
Impl(Impl< DDim, OriginMemorySpace > const &impl)
Copy-constructs from another Impl with a different Kokkos memory space.
KOKKOS_INLINE_FUNCTION std::size_t ncells() const noexcept
Returns the number of cells over which the B-splines are defined.
KOKKOS_INLINE_FUNCTION discrete_element_type eval_deriv(DSpan1D derivs, ddc::Coordinate< CDim > const &x) const
Evaluates non-zero B-spline derivatives at a given coordinate.
Impl & operator=(Impl &&x)=default
Move-assigns.
KOKKOS_INLINE_FUNCTION discrete_domain_type full_domain() const
Returns the discrete domain including eventual additional B-splines in the periodic case.
Impl & operator=(Impl const &x)=default
Copy-assigns.
The type of a uniform 1D spline basis (B-spline).
static constexpr bool is_uniform() noexcept
Indicates if the B-splines are uniform or not (this is the case here).
static constexpr bool is_periodic() noexcept
Indicates if the B-splines are periodic or not.
static constexpr std::size_t degree() noexcept
The degree of B-splines.
UniformPointSampling models a uniform discretization of the provided continuous dimension.
The top-level namespace of DDC.
constexpr bool is_uniform_bsplines_v
Indicates if a tag corresponds to uniform B-splines or not.
BoundCond
An enum representing a spline boundary condition.
@ GREVILLE
Use Greville points instead of conditions on derivative for B-Spline interpolation.
constexpr bool is_non_uniform_bsplines_v
Indicates if a tag corresponds to non-uniform B-splines or not.
A templated struct representing a discrete dimension storing the derivatives of a function along a co...
Definition deriv.hpp:15
ConstantExtrapolationRule(ddc::Coordinate< DimI > eval_pos, ddc::Coordinate< DimNI > eval_pos_not_interest_min, ddc::Coordinate< DimNI > eval_pos_not_interest_max)
Instantiate a ConstantExtrapolationRule.
KOKKOS_FUNCTION double operator()(CoordType coord_extrap, ddc::ChunkSpan< double const, ddc::DiscreteDomain< BSplines1, BSplines2 >, Layout, MemorySpace > const spline_coef) const
Get the value of the function on B-splines at a coordinate outside the domain.
ConstantExtrapolationRule(ddc::Coordinate< DimI > eval_pos)
Instantiate a ConstantExtrapolationRule.
KOKKOS_FUNCTION double operator()(CoordType pos, ddc::ChunkSpan< double const, ddc::DiscreteDomain< BSplines >, Layout, MemorySpace > const spline_coef) const
Get the value of the function on B-splines at a coordinate outside the domain.
ConstantExtrapolationRule(ddc::Coordinate< DimI > eval_pos)
Instantiate a ConstantExtrapolationRule.