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