DDC 0.1.0
Loading...
Searching...
No Matches
bsplines_uniform.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 <array>
8#include <cassert>
9#include <memory>
10
11#include <ddc/ddc.hpp>
12
13#include "math_tools.hpp"
14#include "view.hpp"
15
16namespace ddc {
17
18namespace detail {
19
20struct UniformBSplinesBase
21{
22};
23
24template <class ExecSpace, class ODDim, class Layout, class OMemorySpace>
25void uniform_bsplines_integrals(
26 ExecSpace const& execution_space,
27 ddc::ChunkSpan<double, ddc::DiscreteDomain<ODDim>, Layout, OMemorySpace> int_vals);
28
29} // namespace detail
30
31template <class T>
33{
34};
35
36/**
37 * The type of a uniform 1D spline basis (B-spline).
38 *
39 * Knots for uniform B-splines are uniformly distributed (the associated discrete dimension
40 * is a UniformPointSampling).
41 *
42 * @tparam CDim The tag identifying the continuous dimension on which the support of the B-spline functions are defined.
43 * @tparam D The degree of the B-splines.
44 */
45template <class CDim, std::size_t D>
46class UniformBSplines : detail::UniformBSplinesBase
47{
48 static_assert(D > 0, "Parameter `D` must be positive");
49
50public:
51 /// @brief The tag identifying the continuous dimension on which the support of the B-splines are defined.
52 using continuous_dimension_type = CDim;
53
54 /// @brief The discrete dimension representing B-splines.
55 using discrete_dimension_type = UniformBSplines;
56
57 /** @brief The degree of B-splines.
58 *
59 * @return The degree.
60 */
61 static constexpr std::size_t degree() noexcept
62 {
63 return D;
64 }
65
66 /** @brief Indicates if the B-splines are periodic or not.
67 *
68 * @return A boolean indicating if the B-splines are periodic or not.
69 */
70 static constexpr bool is_periodic() noexcept
71 {
72 return CDim::PERIODIC;
73 }
74
75 /** @brief Indicates if the B-splines are uniform or not (this is the case here).
76 *
77 * @return A boolean indicating if the B-splines are uniform or not.
78 */
79 static constexpr bool is_uniform() noexcept
80 {
81 return true;
82 }
83
84 /** @brief Storage class of the static attributes of the discrete dimension.
85 *
86 * @tparam DDim The name of the discrete dimension.
87 * @tparam MemorySpace The Kokkos memory space where the attributes are being stored.
88 */
89 template <class DDim, class MemorySpace>
90 class Impl
91 {
92 template <class ODDim, class OMemorySpace>
93 friend class Impl;
94
95 template <class ExecSpace, class ODDim, class Layout, class OMemorySpace>
96 friend void detail::uniform_bsplines_integrals(
97 ExecSpace const& execution_space,
98 ddc::ChunkSpan<double, ddc::DiscreteDomain<ODDim>, Layout, OMemorySpace> int_vals);
99
100 public:
101 /// @brief The type of the knots defining the B-splines.
102 using knot_discrete_dimension_type = UniformBsplinesKnots<DDim>;
103
104 /// @brief The type of the discrete dimension representing the B-splines.
105 using discrete_dimension_type = UniformBSplines;
106
107 /// @brief The type of a DiscreteDomain whose elements identify the B-splines.
108 using discrete_domain_type = DiscreteDomain<DDim>;
109
110 /// @brief The type of a DiscreteElement identifying a B-spline.
111 using discrete_element_type = DiscreteElement<DDim>;
112
113 /// @brief The type of a DiscreteVector representing an "index displacement" between two B-splines.
114 using discrete_vector_type = DiscreteVector<DDim>;
115
116 private:
117 // In the periodic case, they contain the periodic point twice!!!
118 ddc::DiscreteDomain<knot_discrete_dimension_type> m_knot_domain;
119 ddc::DiscreteDomain<knot_discrete_dimension_type> m_break_point_domain;
120
121 public:
122 Impl() = default;
123
124 /** Constructs a spline basis (B-splines) with n equidistant knots over \f$[a, b]\f$.
125 *
126 * @param rmin The real ddc::coordinate of the first knot.
127 * @param rmax The real ddc::coordinate of the last knot.
128 * @param ncells The number of cells in the range [rmin, rmax].
129 */
130 explicit Impl(ddc::Coordinate<CDim> rmin, ddc::Coordinate<CDim> rmax, std::size_t ncells)
131 {
132 assert(ncells > 0);
133 ddc::DiscreteDomain<knot_discrete_dimension_type> pre_ghost;
134 ddc::DiscreteDomain<knot_discrete_dimension_type> post_ghost;
135 std::tie(m_break_point_domain, m_knot_domain, pre_ghost, post_ghost)
136 = ddc::init_discrete_space<knot_discrete_dimension_type>(
137 knot_discrete_dimension_type::template init_ghosted<
138 knot_discrete_dimension_type>(
139 rmin,
140 rmax,
141 ddc::DiscreteVector<knot_discrete_dimension_type>(ncells + 1),
142 ddc::DiscreteVector<knot_discrete_dimension_type>(degree()),
143 ddc::DiscreteVector<knot_discrete_dimension_type>(degree())));
144 }
145
146 /** @brief Copy-constructs from another Impl with a different Kokkos memory space.
147 *
148 * @param impl A reference to the other Impl.
149 */
150 template <class OriginMemorySpace>
151 explicit Impl(Impl<DDim, OriginMemorySpace> const& impl)
152 : m_knot_domain(impl.m_knot_domain)
153 , m_break_point_domain(impl.m_break_point_domain)
154 {
155 }
156
157 /** @brief Copy-constructs.
158 *
159 * @param x A reference to another Impl.
160 */
161 Impl(Impl const& x) = default;
162
163 /** @brief Move-constructs.
164 *
165 * @param x An rvalue to another Impl.
166 */
167 Impl(Impl&& x) = default;
168
169 /// @brief Destructs.
170 ~Impl() = default;
171
172 /** @brief Copy-assigns.
173 *
174 * @param x A reference to another Impl.
175 * @return A reference to the copied Impl.
176 */
177 Impl& operator=(Impl const& x) = default;
178
179 /** @brief Move-assigns.
180 *
181 * @param x An rvalue to another Impl.
182 * @return A reference to this object.
183 */
184 Impl& operator=(Impl&& x) = default;
185
186 /** @brief Evaluates non-zero B-splines at a given coordinate.
187 *
188 * The values are computed for every B-spline with support at the given coordinate x. There are only (degree+1)
189 * B-splines which are non-zero at any given point. It is these B-splines which are evaluated.
190 * This can be useful to calculate a spline approximation of a function. A spline approximation at coordinate x
191 * is a linear combination of these B-spline evaluations weighted with the spline coefficients of the spline-transformed
192 * initial discrete function.
193 *
194 * @param[out] values The values of the B-splines evaluated at coordinate x. It has to be a 1D mdspan with (degree+1) elements.
195 * @param[in] x The coordinate where B-splines are evaluated. It has to be in the range of break points coordinates.
196 * @return The index of the first B-spline which is evaluated.
197 */
198 KOKKOS_INLINE_FUNCTION discrete_element_type
199 eval_basis(DSpan1D values, ddc::Coordinate<CDim> const& x) const
200 {
201 assert(values.size() == degree() + 1);
202 return eval_basis(values, x, degree());
203 }
204
205 /** @brief Evaluates non-zero B-spline derivatives at a given coordinate
206 *
207 * The derivatives are computed for every B-spline with support at the given coordinate x. There are only (degree+1)
208 * B-splines which are non-zero at any given point. It is these B-splines which are derivated.
209 * A spline approximation of a derivative at coordinate x is a linear
210 * combination of those B-spline derivatives weighted with the spline coefficients of the spline-transformed
211 * initial discrete function.
212 *
213 * @param[out] derivs The derivatives of the B-splines evaluated at coordinate x. It has to be a 1D mdspan with (degree+1) elements.
214 * @param[in] x The coordinate where B-spline derivatives are evaluated. It has to be in the range of break points coordinates.
215 * @return The index of the first B-spline which is evaluated.
216 */
217 KOKKOS_INLINE_FUNCTION discrete_element_type
218 eval_deriv(DSpan1D derivs, ddc::Coordinate<CDim> const& x) const;
219
220 /** @brief Evaluates non-zero B-spline values and \f$n\f$ derivatives at a given coordinate
221 *
222 * The values and derivatives are computed for every B-spline with support at the given coordinate x. There are only (degree+1)
223 * B-splines which are non-zero at any given point. It is these B-splines which are evaluated and derivated.
224 * A spline approximation of a derivative at coordinate x is a linear
225 * combination of those B-spline derivatives weighted with spline coefficients of the spline-transformed
226 * initial discrete function.
227 *
228 * @param[out] derivs The values and \f$n\f$ derivatives of the B-splines evaluated at coordinate x. It has to be a 2D mdspan of sizes (degree+1, n+1).
229 * @param[in] x The coordinate where B-spline derivatives are evaluated. It has to be in the range of break points coordinates.
230 * @param[in] n The number of derivatives to evaluate (in addition to the B-spline values themselves).
231 * @return The index of the first B-spline which is evaluated.
232 */
234 ddc::DSpan2D derivs,
235 ddc::Coordinate<CDim> const& x,
236 std::size_t n) const;
237
238 /** @brief Compute the integrals of the B-splines.
239 *
240 * The integral of each of the B-splines over their support within the domain on which this basis was defined.
241 *
242 * @deprecated Use @ref integrals instead.
243 *
244 * @param[out] int_vals The values of the integrals. It has to be a 1D Chunkspan of size (nbasis).
245 * @return The values of the integrals.
246 */
247 template <class Layout, class MemorySpace2>
248 [[deprecated("Use `integrals` instead")]] KOKKOS_INLINE_FUNCTION ddc::
249 ChunkSpan<double, ddc::DiscreteDomain<DDim>, Layout, MemorySpace2>
250 integrals(ddc::ChunkSpan<double, discrete_domain_type, Layout, MemorySpace2>
251 int_vals) const;
252
253 /** @brief Returns the coordinate of the first support knot associated to a DiscreteElement identifying a B-spline.
254 *
255 * Each B-spline has a support defined over (degree+2) knots. For a B-spline identified by the
256 * provided DiscreteElement, this function returns the first knot in the support of the B-spline.
257 * In other words it returns the lower bound of the support.
258 *
259 * @param[in] ix DiscreteElement identifying the B-spline.
260 * @return DiscreteElement of the lower bound of the support of the B-spline.
261 */
262 KOKKOS_INLINE_FUNCTION ddc::DiscreteElement<knot_discrete_dimension_type>
263 get_first_support_knot(discrete_element_type const& ix) const
264 {
265 return ddc::DiscreteElement<knot_discrete_dimension_type>(
266 (ix - discrete_element_type(0)).value());
267 }
268
269 /** @brief Returns the coordinate of the last support knot associated to a DiscreteElement identifying a B-spline.
270 *
271 * Each B-spline has a support defined over (degree+2) knots. For a B-spline identified by the
272 * provided DiscreteElement, this function returns the last knot in the support of the B-spline.
273 * In other words it returns the upper bound of the support.
274 *
275 * @param[in] ix DiscreteElement identifying the B-spline.
276 * @return DiscreteElement of the upper bound of the support of the B-spline.
277 */
278 KOKKOS_INLINE_FUNCTION ddc::DiscreteElement<knot_discrete_dimension_type>
279 get_last_support_knot(discrete_element_type const& ix) const
280 {
282 + ddc::DiscreteVector<knot_discrete_dimension_type>(degree() + 1);
283 }
284
285 /** @brief Returns the coordinate of the lower bound of the domain on which the B-splines are defined.
286 *
287 * @return Coordinate of the lower bound of the domain.
288 */
289 KOKKOS_INLINE_FUNCTION ddc::Coordinate<CDim> rmin() const noexcept
290 {
291 return ddc::coordinate(m_break_point_domain.front());
292 }
293
294 /** @brief Returns the coordinate of the upper bound of the domain on which the B-splines are defined.
295 *
296 * @return Coordinate of the upper bound of the domain.
297 */
298 KOKKOS_INLINE_FUNCTION ddc::Coordinate<CDim> rmax() const noexcept
299 {
300 return ddc::coordinate(m_break_point_domain.back());
301 }
302
303 /** @brief Returns the length of the domain.
304 *
305 * @return The length of the domain.
306 */
307 KOKKOS_INLINE_FUNCTION double length() const noexcept
308 {
309 return rmax() - rmin();
310 }
311
312 /** @brief Returns the number of elements necessary to construct a spline representation of a function.
313 *
314 * For a non-periodic domain the number of elements necessary to construct a spline representation of a function
315 * is equal to the number of basis functions. However in the periodic case it additionally includes degree additional elements
316 * which allow the first B-splines to be evaluated close to rmax (where they also appear due to the periodicity).
317 *
318 * @return The number of elements necessary to construct a spline representation of a function.
319 */
320 KOKKOS_INLINE_FUNCTION std::size_t size() const noexcept
321 {
322 return degree() + ncells();
323 }
324
325 /** @brief Returns the discrete domain including eventual additional B-splines in the periodic case. See size().
326 *
327 * @return The discrete domain including eventual additional B-splines.
328 */
329 KOKKOS_INLINE_FUNCTION discrete_domain_type full_domain() const
330 {
331 return discrete_domain_type(discrete_element_type(0), discrete_vector_type(size()));
332 }
333
334 /** @brief Returns the discrete domain which describes the break points.
335 *
336 * @return The discrete domain describing the break points.
337 */
338 KOKKOS_INLINE_FUNCTION ddc::DiscreteDomain<knot_discrete_dimension_type>
339 break_point_domain() const
340 {
341 return m_break_point_domain;
342 }
343
344 /** @brief Returns the number of basis functions.
345 *
346 * The number of functions in the spline basis.
347 *
348 * @return The number of basis functions.
349 */
350 KOKKOS_INLINE_FUNCTION std::size_t nbasis() const noexcept
351 {
352 return ncells() + !is_periodic() * degree();
353 }
354
355 /** @brief Returns the number of cells over which the B-splines are defined.
356 *
357 * The number of cells over which the B-splines and any spline representation are defined.
358 * In other words the number of polynomials that comprise a spline representation on the domain where the basis is defined.
359 *
360 * @return The number of cells over which the B-splines are defined.
361 */
362 KOKKOS_INLINE_FUNCTION std::size_t ncells() const noexcept
363 {
364 return m_break_point_domain.size() - 1;
365 }
366
367 private:
368 KOKKOS_INLINE_FUNCTION double inv_step() const noexcept
369 {
370 return 1.0 / ddc::step<knot_discrete_dimension_type>();
371 }
372
373 KOKKOS_INLINE_FUNCTION discrete_element_type
374 eval_basis(DSpan1D values, ddc::Coordinate<CDim> const& x, std::size_t degree) const;
375
376 KOKKOS_INLINE_FUNCTION void get_icell_and_offset(
377 int& icell,
378 double& offset,
379 ddc::Coordinate<CDim> const& x) const;
380 };
381};
382
383template <class DDim>
384struct is_uniform_bsplines : public std::is_base_of<detail::UniformBSplinesBase, DDim>
385{
386};
387
388/**
389 * @brief Indicates if a tag corresponds to uniform B-splines or not.
390 *
391 * @tparam The presumed uniform B-splines.
392 */
393template <class DDim>
395
396template <class CDim, std::size_t D>
397template <class DDim, class MemorySpace>
398KOKKOS_INLINE_FUNCTION ddc::DiscreteElement<DDim> UniformBSplines<CDim, D>::
399 Impl<DDim, MemorySpace>::eval_basis(
400 DSpan1D values,
401 ddc::Coordinate<CDim> const& x,
402 [[maybe_unused]] std::size_t const deg) const
403{
404 assert(values.size() == deg + 1);
405
406 double offset;
407 int jmin;
408 // 1. Compute cell index 'icell' and x_offset
409 // 2. Compute index range of B-splines with support over cell 'icell'
410 get_icell_and_offset(jmin, offset, x);
411
412 // 3. Compute values of aforementioned B-splines
413 double xx;
414 double temp;
415 double saved;
416 DDC_MDSPAN_ACCESS_OP(values, 0) = 1.0;
417 for (std::size_t j = 1; j < values.size(); ++j) {
418 xx = -offset;
419 saved = 0.0;
420 for (std::size_t r = 0; r < j; ++r) {
421 xx += 1;
422 temp = DDC_MDSPAN_ACCESS_OP(values, r) / j;
423 DDC_MDSPAN_ACCESS_OP(values, r) = saved + xx * temp;
424 saved = (j - xx) * temp;
425 }
426 DDC_MDSPAN_ACCESS_OP(values, j) = saved;
427 }
428
429 return discrete_element_type(jmin);
430}
431
432template <class CDim, std::size_t D>
433template <class DDim, class MemorySpace>
434KOKKOS_INLINE_FUNCTION ddc::DiscreteElement<DDim> UniformBSplines<CDim, D>::
435 Impl<DDim, MemorySpace>::eval_deriv(DSpan1D derivs, ddc::Coordinate<CDim> const& x) const
436{
437 assert(derivs.size() == degree() + 1);
438
439 double offset;
440 int jmin;
441 // 1. Compute cell index 'icell' and x_offset
442 // 2. Compute index range of B-splines with support over cell 'icell'
443 get_icell_and_offset(jmin, offset, x);
444
445 // 3. Compute derivatives of aforementioned B-splines
446 // Derivatives are normalized, hence they should be divided by dx
447 double xx;
448 double temp;
449 double saved;
450 DDC_MDSPAN_ACCESS_OP(derivs, 0) = 1.0 / ddc::step<knot_discrete_dimension_type>();
451 for (std::size_t j = 1; j < degree(); ++j) {
452 xx = -offset;
453 saved = 0.0;
454 for (std::size_t r = 0; r < j; ++r) {
455 xx += 1.0;
456 temp = DDC_MDSPAN_ACCESS_OP(derivs, r) / j;
457 DDC_MDSPAN_ACCESS_OP(derivs, r) = saved + xx * temp;
458 saved = (j - xx) * temp;
459 }
460 DDC_MDSPAN_ACCESS_OP(derivs, j) = saved;
461 }
462
463 // Compute derivatives
464 double bjm1 = derivs[0];
465 double bj = bjm1;
466 DDC_MDSPAN_ACCESS_OP(derivs, 0) = -bjm1;
467 for (std::size_t j = 1; j < degree(); ++j) {
468 bj = DDC_MDSPAN_ACCESS_OP(derivs, j);
469 DDC_MDSPAN_ACCESS_OP(derivs, j) = bjm1 - bj;
470 bjm1 = bj;
471 }
472 DDC_MDSPAN_ACCESS_OP(derivs, degree()) = bj;
473
474 return discrete_element_type(jmin);
475}
476
477template <class CDim, std::size_t D>
478template <class DDim, class MemorySpace>
479KOKKOS_INLINE_FUNCTION ddc::DiscreteElement<DDim> UniformBSplines<CDim, D>::
480 Impl<DDim, MemorySpace>::eval_basis_and_n_derivs(
481 ddc::DSpan2D const derivs,
482 ddc::Coordinate<CDim> const& x,
483 std::size_t const n) const
484{
485 std::array<double, (degree() + 1) * (degree() + 1)> ndu_ptr;
486 Kokkos::mdspan<double, Kokkos::extents<std::size_t, degree() + 1, degree() + 1>> const ndu(
487 ndu_ptr.data());
488 std::array<double, 2 * (degree() + 1)> a_ptr;
489 Kokkos::mdspan<double, Kokkos::extents<std::size_t, degree() + 1, 2>> const a(a_ptr.data());
490 double offset;
491 int jmin;
492
493 assert(x - rmin() >= -length() * 1e-14);
494 assert(rmax() - x >= -length() * 1e-14);
495 // assert(n >= 0); as long as n is unsigned
496 assert(n <= degree());
497 assert(derivs.extent(0) == 1 + degree());
498 assert(derivs.extent(1) == 1 + n);
499
500 // 1. Compute cell index 'icell' and x_offset
501 // 2. Compute index range of B-splines with support over cell 'icell'
502 get_icell_and_offset(jmin, offset, x);
503
504 // 3. Recursively evaluate B-splines (eval_basis)
505 // up to self%degree, and store them all in the upper-right triangle of
506 // ndu
507 double xx;
508 double temp;
509 double saved;
510 DDC_MDSPAN_ACCESS_OP(ndu, 0, 0) = 1.0;
511 for (std::size_t j = 1; j < degree() + 1; ++j) {
512 xx = -offset;
513 saved = 0.0;
514 for (std::size_t r = 0; r < j; ++r) {
515 xx += 1.0;
516 temp = DDC_MDSPAN_ACCESS_OP(ndu, j - 1, r) / j;
517 DDC_MDSPAN_ACCESS_OP(ndu, j, r) = saved + xx * temp;
518 saved = (j - xx) * temp;
519 }
520 DDC_MDSPAN_ACCESS_OP(ndu, j, j) = saved;
521 }
522 for (std::size_t i = 0; i < ndu.extent(1); ++i) {
523 DDC_MDSPAN_ACCESS_OP(derivs, i, 0) = DDC_MDSPAN_ACCESS_OP(ndu, degree(), i);
524 }
525
526 for (int r = 0; r < int(degree() + 1); ++r) {
527 int s1 = 0;
528 int s2 = 1;
529 DDC_MDSPAN_ACCESS_OP(a, 0, 0) = 1.0;
530 for (int k = 1; k < int(n + 1); ++k) {
531 double d = 0.0;
532 int const rk = r - k;
533 int const pk = degree() - k;
534 if (r >= k) {
535 DDC_MDSPAN_ACCESS_OP(a, 0, s2) = DDC_MDSPAN_ACCESS_OP(a, 0, s1) / (pk + 1);
536 d = DDC_MDSPAN_ACCESS_OP(a, 0, s2) * DDC_MDSPAN_ACCESS_OP(ndu, pk, rk);
537 }
538 int const j1 = rk > -1 ? 1 : (-rk);
539 int const j2 = (r - 1) <= pk ? k : (degree() - r + 1);
540 for (int j = j1; j < j2; ++j) {
541 DDC_MDSPAN_ACCESS_OP(a, j, s2)
542 = (DDC_MDSPAN_ACCESS_OP(a, j, s1) - DDC_MDSPAN_ACCESS_OP(a, j - 1, s1))
543 / (pk + 1);
544 d += DDC_MDSPAN_ACCESS_OP(a, j, s2) * DDC_MDSPAN_ACCESS_OP(ndu, pk, rk + j);
545 }
546 if (r <= pk) {
547 DDC_MDSPAN_ACCESS_OP(a, k, s2) = -DDC_MDSPAN_ACCESS_OP(a, k - 1, s1) / (pk + 1);
548 d += DDC_MDSPAN_ACCESS_OP(a, k, s2) * DDC_MDSPAN_ACCESS_OP(ndu, pk, r);
549 }
550 DDC_MDSPAN_ACCESS_OP(derivs, r, k) = d;
551 Kokkos::kokkos_swap(s1, s2);
552 }
553 }
554
555 // Multiply result by correct factors:
556 // degree!/(degree-n)! = degree*(degree-1)*...*(degree-n+1)
557 // k-th derivatives are normalized, hence they should be divided by dx^k
558 double const inv_dx = inv_step();
559 double d = degree() * inv_dx;
560 for (int k = 1; k < int(n + 1); ++k) {
561 for (std::size_t i = 0; i < derivs.extent(0); ++i) {
562 DDC_MDSPAN_ACCESS_OP(derivs, i, k) *= d;
563 }
564 d *= (degree() - k) * inv_dx;
565 }
566
567 return discrete_element_type(jmin);
568}
569
570template <class CDim, std::size_t D>
571template <class DDim, class MemorySpace>
572KOKKOS_INLINE_FUNCTION void UniformBSplines<CDim, D>::Impl<DDim, MemorySpace>::get_icell_and_offset(
573 int& icell,
574 double& offset,
575 ddc::Coordinate<CDim> const& x) const
576{
577 assert(x - rmin() >= -length() * 1e-14);
578 assert(rmax() - x >= -length() * 1e-14);
579
580 double const inv_dx = inv_step();
581 if (x <= rmin()) {
582 icell = 0;
583 offset = 0.0;
584 } else if (x >= rmax()) {
585 icell = ncells() - 1;
586 offset = 1.0;
587 } else {
588 offset = (x - rmin()) * inv_dx;
589 icell = static_cast<int>(offset);
590 offset = offset - icell;
591
592 // When x is very close to xmax, round-off may cause the wrong answer
593 // icell=ncells and x_offset=0, which we convert to the case x=xmax:
594 if (icell == int(ncells()) && offset == 0.0) {
595 icell = ncells() - 1;
596 offset = 1.0;
597 }
598 }
599}
600
601template <class CDim, std::size_t D>
602template <class DDim, class MemorySpace>
603template <class Layout, class MemorySpace2>
604KOKKOS_INLINE_FUNCTION ddc::ChunkSpan<double, ddc::DiscreteDomain<DDim>, Layout, MemorySpace2>
605UniformBSplines<CDim, D>::Impl<DDim, MemorySpace>::integrals(
606 ddc::ChunkSpan<double, discrete_domain_type, Layout, MemorySpace2> int_vals) const
607{
608 assert([&]() -> bool {
609 if constexpr (is_periodic()) {
610 return int_vals.size() == nbasis() || int_vals.size() == size();
611 } else {
612 return int_vals.size() == nbasis();
613 }
614 }());
615
616 discrete_domain_type const full_dom_splines(full_domain());
617
618 if constexpr (is_periodic()) {
619 discrete_domain_type const dom_bsplines(
620 full_dom_splines.take_first(discrete_vector_type {nbasis()}));
621 for (auto ix : dom_bsplines) {
622 int_vals(ix) = ddc::step<knot_discrete_dimension_type>();
623 }
624 if (int_vals.size() == size()) {
625 discrete_domain_type const dom_bsplines_repeated(
626 full_dom_splines.take_last(discrete_vector_type {degree()}));
627 for (auto ix : dom_bsplines_repeated) {
628 int_vals(ix) = 0;
629 }
630 }
631 } else {
632 discrete_domain_type const dom_bspline_entirely_in_domain
633 = full_dom_splines
634 .remove(discrete_vector_type(degree()), discrete_vector_type(degree()));
635 for (auto ix : dom_bspline_entirely_in_domain) {
636 int_vals(ix) = ddc::step<knot_discrete_dimension_type>();
637 }
638
639 std::array<double, degree() + 2> edge_vals_ptr;
640 Kokkos::mdspan<double, Kokkos::extents<std::size_t, degree() + 2>> const edge_vals(
641 edge_vals_ptr.data());
642
643 eval_basis(edge_vals, rmin(), degree() + 1);
644
645 double const d_eval = ddc::detail::sum(edge_vals);
646
647 for (std::size_t i = 0; i < degree(); ++i) {
648 double const c_eval = ddc::detail::sum(edge_vals, 0, degree() - i);
649
650 double const edge_value = ddc::step<knot_discrete_dimension_type>() * (d_eval - c_eval);
651
652 int_vals(discrete_element_type(i)) = edge_value;
653 int_vals(discrete_element_type(nbasis() - 1 - i)) = edge_value;
654 }
655 }
656 return int_vals;
657}
658
659} // namespace ddc
friend class DiscreteDomain
KOKKOS_FUNCTION constexpr bool operator!=(DiscreteVector< OTags... > const &rhs) const noexcept
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.
KOKKOS_INLINE_FUNCTION ddc::ChunkSpan< double, ddc::DiscreteDomain< DDim >, Layout, MemorySpace2 > integrals(ddc::ChunkSpan< double, discrete_domain_type, Layout, MemorySpace2 > int_vals) const
Compute the integrals of the B-splines.
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.