DDC 0.10.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 <cstddef>
8#include <type_traits>
9#include <vector>
10
11#include <ddc/ddc.hpp>
12
13#include <Kokkos_Core.hpp>
14
15#include "bsplines_non_uniform.hpp"
16#include "bsplines_uniform.hpp"
17#include "spline_boundary_conditions.hpp"
18
19namespace ddc {
20
21/**
22 * A class which provides helper functions to initialise the Greville points from a B-Spline definition.
23 *
24 * @tparam BSplines The bspline class relative to which the Greville points will be calculated.
25 * @tparam BcLower The lower boundary condition that will be used to build the splines.
26 * @tparam BcUpper The upper boundary condition that will be used to build the splines.
27 */
28template <class BSplines, ddc::BoundCond BcLower, ddc::BoundCond BcUpper>
30{
31 using continuous_dimension_type = typename BSplines::continuous_dimension_type;
32
33 template <class Sampling>
34 struct IntermediateUniformSampling
36 {
37 };
38
39 template <class Sampling>
40 struct IntermediateNonUniformSampling
42 {
43 };
44
45 template <class Sampling, typename U = BSplines, class = std::enable_if_t<U::is_uniform()>>
46 static auto uniform_greville_points()
47 {
48 using SamplingImpl = typename Sampling::template Impl<Sampling, Kokkos::HostSpace>;
49
50 double constexpr shift = (BSplines::degree() % 2 == 0) ? 0.5 : 0.0;
51 double const dx
52 = (ddc::discrete_space<BSplines>().rmax() - ddc::discrete_space<BSplines>().rmin())
53 / ddc::discrete_space<BSplines>().ncells();
54 return SamplingImpl(
55 ddc::Coordinate<continuous_dimension_type>(
56 ddc::discrete_space<BSplines>().rmin() + shift * dx),
57 ddc::Coordinate<continuous_dimension_type>(dx));
58 }
59
60 template <class Sampling, typename U = BSplines, class = std::enable_if_t<!U::is_uniform()>>
61 static auto non_uniform_greville_points()
62 {
63 using SamplingImpl = typename Sampling::template Impl<Sampling, Kokkos::HostSpace>;
64
65 int n_greville_points = 0;
66 if constexpr (U::is_periodic()) {
67 n_greville_points = ddc::discrete_space<BSplines>().nbasis() + 1;
68 } else {
69 n_greville_points = ddc::discrete_space<BSplines>().nbasis();
70 }
71
72 std::vector<double> greville_points(n_greville_points);
73 ddc::DiscreteDomain<BSplines> const bspline_domain
74 = ddc::discrete_space<BSplines>().full_domain().take_first(
75 ddc::DiscreteVector<BSplines>(ddc::discrete_space<BSplines>().nbasis()));
76
77 ddc::DiscreteVector<NonUniformBsplinesKnots<BSplines>> n_points_in_average(
78 BSplines::degree());
79
80 ddc::DiscreteElement<BSplines> ib0(bspline_domain.front());
81
82 ddc::host_for_each(bspline_domain, [&](ddc::DiscreteElement<BSplines> ib) {
83 // Define the Greville points from the bspline knots
84 greville_points[ib - ib0] = 0.0;
85 ddc::DiscreteDomain<NonUniformBsplinesKnots<BSplines>> const sub_domain(
86 ddc::discrete_space<BSplines>().get_first_support_knot(ib) + 1,
87 n_points_in_average);
88 ddc::host_for_each(sub_domain, [&](auto ik) {
89 greville_points[ib - ib0] += ddc::coordinate(ik);
90 });
91 greville_points[ib - ib0] /= n_points_in_average.value();
92 });
93
94 // Use periodicity to ensure all points are in the domain
95 if constexpr (U::is_periodic()) {
96 std::vector<double> temp_knots(BSplines::degree());
97 int npoints(0);
98 // Count the number of interpolation points that need shifting to preserve the ordering
99 while (greville_points[npoints] < ddc::discrete_space<BSplines>().rmin()) {
100 temp_knots[npoints]
101 = greville_points[npoints] + ddc::discrete_space<BSplines>().length();
102 ++npoints;
103 }
104 // Shift the points
105 for (std::size_t i = 0; i < ddc::discrete_space<BSplines>().nbasis() - npoints; ++i) {
106 greville_points[i] = greville_points[i + npoints];
107 }
108 for (int i = 0; i < npoints; ++i) {
109 greville_points[ddc::discrete_space<BSplines>().nbasis() - npoints + i]
110 = temp_knots[i];
111 }
112
113 // Save a periodic point to initialise the domain size
114 greville_points[n_greville_points - 1]
115 = greville_points[0] + ddc::discrete_space<BSplines>().length();
116 }
117
118 return SamplingImpl(greville_points);
119 }
120
121 static constexpr int N_BE_MIN = n_boundary_equations(BcLower, BSplines::degree());
122 static constexpr int N_BE_MAX = n_boundary_equations(BcUpper, BSplines::degree());
123 template <class U>
124 static constexpr bool is_uniform_discrete_dimension_v
125 = U::is_uniform() && ((N_BE_MIN != 0 && N_BE_MAX != 0) || U::is_periodic());
126
127public:
128 /**
129 * Get the UniformPointSampling defining the Greville points.
130 *
131 * This function is called when the result is a UniformPointSampling. This is the case
132 * when uniform splines are used with an odd degree and with boundary conditions which
133 * do not introduce additional interpolation points.
134 *
135 * @tparam Sampling The discrete dimension supporting the Greville points.
136 *
137 * @returns The mesh of uniform Greville points.
138 */
139 template <
140 class Sampling,
141 typename U = BSplines,
142 std::enable_if_t<
143 is_uniform_discrete_dimension_v<U>,
144 bool>
145 = true> // U must be in condition for SFINAE
146 static auto get_sampling()
147 {
148 return uniform_greville_points<Sampling>();
149 }
150
151 /**
152 * Get the NonUniformPointSampling defining the Greville points.
153 *
154 * @tparam Sampling The discrete dimension supporting the Greville points.
155 *
156 * @returns The mesh of non-uniform Greville points.
157 */
158 template <
159 class Sampling,
160 typename U = BSplines,
161 std::enable_if_t<
162 !is_uniform_discrete_dimension_v<U>,
163 bool>
164 = true> // U must be in condition for SFINAE
165 static auto get_sampling()
166 {
167 using SamplingImpl = typename Sampling::template Impl<Sampling, Kokkos::HostSpace>;
168 if constexpr (U::is_uniform()) {
169 using IntermediateSampling = IntermediateUniformSampling<Sampling>;
170 auto points_wo_bcs = uniform_greville_points<IntermediateSampling>();
171 int const n_break_points = ddc::discrete_space<BSplines>().ncells() + 1;
172 int const npoints = ddc::discrete_space<BSplines>().nbasis() - N_BE_MIN - N_BE_MAX;
173 std::vector<double> points_with_bcs(npoints);
174
175 // Construct Greville-like points at the edge
176 if constexpr (BcLower == ddc::BoundCond::GREVILLE) {
177 for (std::size_t i(0); i < BSplines::degree() / 2 + 1; ++i) {
178 points_with_bcs[i]
179 = (BSplines::degree() - i) * ddc::discrete_space<BSplines>().rmin();
180 ddc::DiscreteElement<BSplines> const spline_idx(i);
181 ddc::DiscreteVector<UniformBsplinesKnots<BSplines>> const n_knots_in_domain(i);
182 ddc::DiscreteDomain<UniformBsplinesKnots<BSplines>> const sub_domain(
183 ddc::discrete_space<BSplines>().get_last_support_knot(spline_idx)
184 - n_knots_in_domain,
185 n_knots_in_domain);
186 ddc::host_for_each(
187 sub_domain,
188 [&](DiscreteElement<UniformBsplinesKnots<BSplines>> ik) {
189 points_with_bcs[i] += ddc::coordinate(ik);
190 });
191 points_with_bcs[i] /= BSplines::degree();
192 }
193 } else {
194 points_with_bcs[0]
195 = points_wo_bcs.coordinate(ddc::DiscreteElement<IntermediateSampling>(0));
196 }
197
198 int const n_start
199 = (BcLower == ddc::BoundCond::GREVILLE) ? BSplines::degree() / 2 + 1 : 1;
200 int const domain_size = n_break_points - 2;
201 ddc::DiscreteElement<IntermediateSampling> domain_start(1);
202 ddc::DiscreteDomain<IntermediateSampling> const
203 domain(domain_start, ddc::DiscreteVector<IntermediateSampling>(domain_size));
204
205 // Copy central points
206 ddc::host_for_each(domain, [&](auto ip) {
207 points_with_bcs[ip - domain_start + n_start] = points_wo_bcs.coordinate(ip);
208 });
209
210 // Construct Greville-like points at the edge
211 if constexpr (BcUpper == ddc::BoundCond::GREVILLE) {
212 for (std::size_t i(0); i < BSplines::degree() / 2 + 1; ++i) {
213 points_with_bcs[npoints - 1 - i]
214 = (BSplines::degree() - i) * ddc::discrete_space<BSplines>().rmax();
215 ddc::DiscreteElement<BSplines> const spline_idx(
216 ddc::discrete_space<BSplines>().nbasis() - 1 - i);
217 ddc::DiscreteVector<UniformBsplinesKnots<BSplines>> const n_knots_in_domain(i);
218 ddc::DiscreteDomain<UniformBsplinesKnots<BSplines>> const sub_domain(
219 ddc::discrete_space<BSplines>().get_first_support_knot(spline_idx) + 1,
220 n_knots_in_domain);
221 ddc::host_for_each(
222 sub_domain,
223 [&](DiscreteElement<UniformBsplinesKnots<BSplines>> ik) {
224 points_with_bcs[npoints - 1 - i] += ddc::coordinate(ik);
225 });
226 points_with_bcs[npoints - 1 - i] /= BSplines::degree();
227 }
228 } else {
229 points_with_bcs[npoints - 1] = points_wo_bcs.coordinate(
230 ddc::DiscreteElement<IntermediateSampling>(
231 ddc::discrete_space<BSplines>().ncells() - 1
232 + BSplines::degree() % 2));
233 }
234 return SamplingImpl(points_with_bcs);
235 } else {
236 using IntermediateSampling = IntermediateNonUniformSampling<Sampling>;
237 if constexpr (N_BE_MIN == 0 && N_BE_MAX == 0) {
238 return non_uniform_greville_points<Sampling>();
239 } else {
240 auto points_wo_bcs = non_uniform_greville_points<IntermediateSampling>();
241 // All points are Greville points. Extract unnecessary points near the boundary
242 std::vector<double> points_with_bcs(points_wo_bcs.size() - N_BE_MIN - N_BE_MAX);
243 int constexpr n_start = N_BE_MIN;
244
245 using length = ddc::DiscreteVector<IntermediateSampling>;
246
247 ddc::DiscreteElement<IntermediateSampling> domain_start(n_start);
248 ddc::DiscreteDomain<IntermediateSampling> const
249 domain(domain_start, length(points_with_bcs.size()));
250
251 points_with_bcs[0] = points_wo_bcs.coordinate(domain.front());
252 ddc::host_for_each(domain.remove(length(1), length(1)), [&](auto ip) {
253 points_with_bcs[ip - domain_start] = points_wo_bcs.coordinate(ip);
254 });
255 points_with_bcs[points_with_bcs.size() - 1]
256 = points_wo_bcs.coordinate(domain.back());
257
258 return SamplingImpl(points_with_bcs);
259 }
260 }
261 }
262
263 /**
264 * The type of the mesh.
265 *
266 * This is either NonUniformPointSampling or UniformPointSampling.
267 */
268 using interpolation_discrete_dimension_type = std::conditional_t<
269 is_uniform_discrete_dimension_v<BSplines>,
270 ddc::UniformPointSampling<continuous_dimension_type>,
271 ddc::NonUniformPointSampling<continuous_dimension_type>>;
272
273 /**
274 * Get the domain which gives us access to all of the Greville points.
275 *
276 * @tparam Sampling The discrete dimension supporting the Greville points.
277 *
278 * @returns The domain of the Greville points.
279 */
280 template <class Sampling>
281 static ddc::DiscreteDomain<Sampling> get_domain()
282 {
283 int const npoints = ddc::discrete_space<BSplines>().nbasis() - N_BE_MIN - N_BE_MAX;
284 return ddc::DiscreteDomain<Sampling>(
285 ddc::DiscreteElement<Sampling>(0),
286 ddc::DiscreteVector<Sampling>(npoints));
287 }
288};
289
290} // namespace ddc
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.
static auto get_sampling()
Get the UniformPointSampling defining the Greville points.
NonUniformPointSampling models a non-uniform discretization of the CDim segment .
UniformPointSampling models a uniform discretization of the provided continuous dimension.
The top-level namespace of DDC.
BoundCond
An enum representing a spline boundary condition.
@ GREVILLE
Use Greville points instead of conditions on derivative for B-Spline interpolation.