DDC 0.15.1
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 <cstddef>
10#include <tuple>
11#include <type_traits>
12
13#include <ddc/ddc.hpp>
14
15#include <Kokkos_Core.hpp>
16
17namespace ddc {
18
19namespace detail {
20
21struct UniformBSplinesBase
22{
23};
24
25template <class ExecSpace, class ODDim, class Layout, class OMemorySpace>
26void uniform_bsplines_integrals(
27 ExecSpace const& execution_space,
28 ddc::ChunkSpan<double, ddc::DiscreteDomain<ODDim>, Layout, OMemorySpace> int_vals);
29
30} // namespace detail
31
32template <class T>
34{
35};
36
37/**
38 * The type of a uniform 1D spline basis (B-spline).
39 *
40 * Knots for uniform B-splines are uniformly distributed (the associated discrete dimension
41 * is a UniformPointSampling).
42 *
43 * @tparam CDim The tag identifying the continuous dimension on which the support of the B-spline functions are defined.
44 * @tparam D The degree of the B-splines.
45 */
46template <class CDim, std::size_t D, bool Periodic = CDim::PERIODIC>
47class UniformBSplines : detail::UniformBSplinesBase
48{
49 static_assert(D > 0, "Parameter `D` must be positive");
50
51public:
52 /// @brief The tag identifying the continuous dimension on which the support of the B-splines are defined.
53 using continuous_dimension_type = CDim;
54
55 /// @brief The discrete dimension representing B-splines.
56 using discrete_dimension_type = UniformBSplines;
57
58 /** @brief The degree of B-splines.
59 *
60 * @return The degree.
61 */
62 static constexpr std::size_t degree() noexcept
63 {
64 return D;
65 }
66
67 /** @brief Indicates if the B-splines are periodic or not.
68 *
69 * @return A boolean indicating if the B-splines are periodic or not.
70 */
71 static constexpr bool is_periodic() noexcept
72 {
73 return Periodic;
74 }
75
76 /** @brief Indicates if the B-splines are uniform or not (this is the case here).
77 *
78 * @return A boolean indicating if the B-splines are uniform or not.
79 */
80 static constexpr bool is_uniform() noexcept
81 {
82 return true;
83 }
84
85 /** @brief Storage class of the static attributes of the discrete dimension.
86 *
87 * @tparam DDim The name of the discrete dimension.
88 * @tparam MemorySpace The Kokkos memory space where the attributes are being stored.
89 */
90 template <class DDim, class MemorySpace>
91 class Impl
92 {
93 template <class ODDim, class OMemorySpace>
94 friend class Impl;
95
96 template <class ExecSpace, class ODDim, class Layout, class OMemorySpace>
97 friend void detail::uniform_bsplines_integrals(
98 ExecSpace const& execution_space,
99 ddc::ChunkSpan<double, ddc::DiscreteDomain<ODDim>, Layout, OMemorySpace> int_vals);
100
101 public:
102 /// @brief The type of the knots defining the B-splines.
103 using knot_discrete_dimension_type = UniformBsplinesKnots<DDim>;
104
105 /// @brief The type of the discrete dimension representing the B-splines.
106 using discrete_dimension_type = UniformBSplines;
107
108 /// @brief The type of a DiscreteDomain whose elements identify the B-splines.
109 using discrete_domain_type = DiscreteDomain<DDim>;
110
111 /// @brief The type of a DiscreteElement identifying a B-spline.
112 using discrete_element_type = DiscreteElement<DDim>;
113
114 /// @brief The type of a DiscreteVector representing an "index displacement" between two B-splines.
115 using discrete_vector_type = DiscreteVector<DDim>;
116
117 private:
118 // In the periodic case, they contain the periodic point twice!!!
119 ddc::DiscreteDomain<knot_discrete_dimension_type> m_knot_domain;
120 ddc::DiscreteDomain<knot_discrete_dimension_type> m_break_point_domain;
121
122 ddc::DiscreteElement<DDim> m_reference;
123
124 public:
125 Impl() = default;
126
127 /** Constructs a spline basis (B-splines) with n equidistant knots over \f$[a, b]\f$.
128 *
129 * @param rmin The real ddc::coordinate of the first knot.
130 * @param rmax The real ddc::coordinate of the last knot.
131 * @param ncells The number of cells in the range [rmin, rmax].
132 */
133 explicit Impl(ddc::Coordinate<CDim> rmin, ddc::Coordinate<CDim> rmax, std::size_t ncells)
134 : m_reference(ddc::create_reference_discrete_element<DDim>())
135 {
136 assert(ncells > 0);
137 std::tie(m_break_point_domain, m_knot_domain, std::ignore, std::ignore)
138 = ddc::init_discrete_space<knot_discrete_dimension_type>(
139 knot_discrete_dimension_type::template init_ghosted<
140 knot_discrete_dimension_type>(
141 rmin,
142 rmax,
143 ddc::DiscreteVector<knot_discrete_dimension_type>(ncells + 1),
144 ddc::DiscreteVector<knot_discrete_dimension_type>(degree()),
145 ddc::DiscreteVector<knot_discrete_dimension_type>(degree())));
146 }
147
148 /** @brief Copy-constructs from another Impl with a different Kokkos memory space.
149 *
150 * @param impl A reference to the other Impl.
151 */
152 template <class OriginMemorySpace>
153 explicit Impl(Impl<DDim, OriginMemorySpace> const& impl)
154 : m_knot_domain(impl.m_knot_domain)
155 , m_break_point_domain(impl.m_break_point_domain)
156 , m_reference(impl.m_reference)
157 {
158 }
159
160 /** @brief Copy-constructs.
161 *
162 * @param x A reference to another Impl.
163 */
164 Impl(Impl const& x) = default;
165
166 /** @brief Move-constructs.
167 *
168 * @param x An rvalue to another Impl.
169 */
170 Impl(Impl&& x) = default;
171
172 /// @brief Destructs.
173 ~Impl() = default;
174
175 /** @brief Copy-assigns.
176 *
177 * @param x A reference to another Impl.
178 * @return A reference to the copied Impl.
179 */
180 Impl& operator=(Impl const& x) = default;
181
182 /** @brief Move-assigns.
183 *
184 * @param x An rvalue to another Impl.
185 * @return A reference to this object.
186 */
187 Impl& operator=(Impl&& x) = default;
188
189 /** @brief Evaluates non-zero B-splines at a given coordinate.
190 *
191 * The values are computed for every B-spline with support at the given coordinate x. There are only (degree+1)
192 * B-splines which are non-zero at any given point. It is these B-splines which are evaluated.
193 * This can be useful to calculate a spline approximation of a function. A spline approximation at coordinate x
194 * is a linear combination of these B-spline evaluations weighted with the spline coefficients of the spline-transformed
195 * initial discrete function.
196 *
197 * @param[out] values The values of the B-splines evaluated at coordinate x. It has to be a 1D mdspan with (degree+1) elements.
198 * @param[in] x The coordinate where B-splines are evaluated. It has to be in the range of break points coordinates.
199 * @return The index of the first B-spline which is evaluated.
200 */
201 KOKKOS_INLINE_FUNCTION discrete_element_type eval_basis(
202 Kokkos::mdspan<double, Kokkos::dextents<std::size_t, 1>> values,
203 ddc::Coordinate<CDim> const& x) const
204 {
205 KOKKOS_ASSERT(values.size() == degree() + 1)
206 return eval_basis(values, x, degree());
207 }
208
209 /** @brief Evaluates non-zero B-spline derivatives at a given coordinate
210 *
211 * The derivatives are computed for every B-spline with support at the given coordinate x. There are only (degree+1)
212 * B-splines which are non-zero at any given point. It is these B-splines which are differentiated.
213 * A spline approximation of a derivative at coordinate x is a linear
214 * combination of those B-spline derivatives weighted with the spline coefficients of the spline-transformed
215 * initial discrete function.
216 *
217 * @param[out] derivs The derivatives of the B-splines evaluated at coordinate x. It has to be a 1D mdspan with (degree+1) elements.
218 * @param[in] x The coordinate where B-spline derivatives are evaluated. It has to be in the range of break points coordinates.
219 * @return The index of the first B-spline which is evaluated.
220 */
221 KOKKOS_INLINE_FUNCTION discrete_element_type eval_deriv(
222 Kokkos::mdspan<double, Kokkos::dextents<std::size_t, 1>> derivs,
223 ddc::Coordinate<CDim> const& x) const;
224
225 /** @brief Evaluates non-zero B-spline values and \f$n\f$ derivatives at a given coordinate
226 *
227 * The values and derivatives are computed for every B-spline with support at the given coordinate x. There are only (degree+1)
228 * B-splines which are non-zero at any given point. It is these B-splines which are evaluated and differentiated.
229 * A spline approximation of a derivative at coordinate x is a linear
230 * combination of those B-spline derivatives weighted with spline coefficients of the spline-transformed
231 * initial discrete function.
232 *
233 * @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).
234 * @param[in] x The coordinate where B-spline derivatives are evaluated. It has to be in the range of break points coordinates.
235 * @param[in] n The number of derivatives to evaluate (in addition to the B-spline values themselves).
236 * @return The index of the first B-spline which is evaluated.
237 */
238 KOKKOS_INLINE_FUNCTION discrete_element_type eval_basis_and_n_derivs(
239 Kokkos::mdspan<double, Kokkos::dextents<std::size_t, 2>> derivs,
240 ddc::Coordinate<CDim> const& x,
241 std::size_t n) const;
242
243 /** @brief Returns the coordinate of the first support knot associated to a DiscreteElement identifying a B-spline.
244 *
245 * Each B-spline has a support defined over (degree+2) knots. For a B-spline identified by the
246 * provided DiscreteElement, this function returns the first knot in the support of the B-spline.
247 * In other words it returns the lower bound of the support.
248 *
249 * @param[in] ix DiscreteElement identifying the B-spline.
250 * @return DiscreteElement of the lower bound of the support of the B-spline.
251 */
252 KOKKOS_INLINE_FUNCTION ddc::DiscreteElement<knot_discrete_dimension_type>
253 get_first_support_knot(discrete_element_type const& ix) const
254 {
255 return m_knot_domain.front() + (ix - m_reference).value();
256 }
257
258 /** @brief Returns the coordinate of the last support knot associated to a DiscreteElement identifying a B-spline.
259 *
260 * Each B-spline has a support defined over (degree+2) knots. For a B-spline identified by the
261 * provided DiscreteElement, this function returns the last knot in the support of the B-spline.
262 * In other words it returns the upper bound of the support.
263 *
264 * @param[in] ix DiscreteElement identifying the B-spline.
265 * @return DiscreteElement of the upper bound of the support of the B-spline.
266 */
267 KOKKOS_INLINE_FUNCTION ddc::DiscreteElement<knot_discrete_dimension_type>
268 get_last_support_knot(discrete_element_type const& ix) const
269 {
271 + ddc::DiscreteVector<knot_discrete_dimension_type>(degree() + 1);
272 }
273
274 /** @brief Returns the coordinate of the lower bound of the domain on which the B-splines are defined.
275 *
276 * @return Coordinate of the lower bound of the domain.
277 */
278 KOKKOS_INLINE_FUNCTION ddc::Coordinate<CDim> rmin() const noexcept
279 {
280 return ddc::coordinate(m_break_point_domain.front());
281 }
282
283 /** @brief Returns the coordinate of the upper bound of the domain on which the B-splines are defined.
284 *
285 * @return Coordinate of the upper bound of the domain.
286 */
287 KOKKOS_INLINE_FUNCTION ddc::Coordinate<CDim> rmax() const noexcept
288 {
289 return ddc::coordinate(m_break_point_domain.back());
290 }
291
292 /** @brief Returns the length of the domain.
293 *
294 * @return The length of the domain.
295 */
296 KOKKOS_INLINE_FUNCTION double length() const noexcept
297 {
298 return rmax() - rmin();
299 }
300
301 /** @brief Returns the number of elements necessary to construct a spline representation of a function.
302 *
303 * For a non-periodic domain the number of elements necessary to construct a spline representation of a function
304 * is equal to the number of basis functions. However in the periodic case it additionally includes degree additional elements
305 * which allow the first B-splines to be evaluated close to rmax (where they also appear due to the periodicity).
306 *
307 * @return The number of elements necessary to construct a spline representation of a function.
308 */
309 KOKKOS_INLINE_FUNCTION std::size_t size() const noexcept
310 {
311 return degree() + ncells();
312 }
313
314 /** @brief Returns the discrete domain including eventual additional B-splines in the periodic case. See size().
315 *
316 * @return The discrete domain including eventual additional B-splines.
317 */
318 KOKKOS_INLINE_FUNCTION discrete_domain_type full_domain() const
319 {
320 return discrete_domain_type(m_reference, discrete_vector_type(size()));
321 }
322
323 /** @brief Returns the discrete domain which describes the break points.
324 *
325 * @return The discrete domain describing the break points.
326 */
327 KOKKOS_INLINE_FUNCTION ddc::DiscreteDomain<knot_discrete_dimension_type>
328 break_point_domain() const
329 {
330 return m_break_point_domain;
331 }
332
333 /** @brief Returns the number of basis functions.
334 *
335 * The number of functions in the spline basis.
336 *
337 * @return The number of basis functions.
338 */
339 KOKKOS_INLINE_FUNCTION std::size_t nbasis() const noexcept
340 {
341 return ncells() + !is_periodic() * degree();
342 }
343
344 /** @brief Returns the number of cells over which the B-splines are defined.
345 *
346 * The number of cells over which the B-splines and any spline representation are defined.
347 * In other words the number of polynomials that comprise a spline representation on the domain where the basis is defined.
348 *
349 * @return The number of cells over which the B-splines are defined.
350 */
351 KOKKOS_INLINE_FUNCTION std::size_t ncells() const noexcept
352 {
353 return m_break_point_domain.size() - 1;
354 }
355
356 private:
357 KOKKOS_INLINE_FUNCTION double inv_step() const noexcept
358 {
359 return 1.0 / ddc::step<knot_discrete_dimension_type>();
360 }
361
362 KOKKOS_INLINE_FUNCTION discrete_element_type eval_basis(
363 Kokkos::mdspan<double, Kokkos::dextents<std::size_t, 1>> values,
364 ddc::Coordinate<CDim> const& x,
365 std::size_t degree) const;
366
367 KOKKOS_INLINE_FUNCTION void get_icell_and_offset(
368 int& icell,
369 double& offset,
370 ddc::Coordinate<CDim> const& x) const;
371 };
372};
373
374template <class DDim>
375struct is_uniform_bsplines : public std::is_base_of<detail::UniformBSplinesBase, DDim>::type
376{
377};
378
379/**
380 * @brief Indicates if a tag corresponds to uniform B-splines or not.
381 *
382 * @tparam The presumed uniform B-splines.
383 */
384template <class DDim>
386
387namespace concepts {
388
389template <class DDim>
390concept uniform_bsplines = is_uniform_bsplines_v<DDim>;
391
392}
393
394template <class CDim, std::size_t D, bool Periodic>
395template <class DDim, class MemorySpace>
396KOKKOS_INLINE_FUNCTION ddc::DiscreteElement<DDim> UniformBSplines<CDim, D, Periodic>::
397 Impl<DDim, MemorySpace>::eval_basis(
398 Kokkos::mdspan<double, Kokkos::dextents<std::size_t, 1>> values,
399 ddc::Coordinate<CDim> const& x,
400 [[maybe_unused]] std::size_t const degree) const
401{
402 KOKKOS_ASSERT(values.size() == degree + 1)
403
404 double offset;
405 int jmin;
406 // 1. Compute cell index 'icell' and x_offset
407 // 2. Compute index range of B-splines with support over cell 'icell'
408 get_icell_and_offset(jmin, offset, x);
409
410 // 3. Compute values of aforementioned B-splines
411 double xx;
412 double temp;
413 double saved;
414 DDC_MDSPAN_ACCESS_OP(values, 0) = 1.0;
415 for (std::size_t j = 1; j < values.size(); ++j) {
416 xx = -offset;
417 saved = 0.0;
418 for (std::size_t r = 0; r < j; ++r) {
419 xx += 1;
420 temp = DDC_MDSPAN_ACCESS_OP(values, r) / j;
421 DDC_MDSPAN_ACCESS_OP(values, r) = saved + xx * temp;
422 saved = (j - xx) * temp;
423 }
424 DDC_MDSPAN_ACCESS_OP(values, j) = saved;
425 }
426
427 return m_reference + jmin;
428}
429
430template <class CDim, std::size_t D, bool Periodic>
431template <class DDim, class MemorySpace>
432KOKKOS_INLINE_FUNCTION ddc::DiscreteElement<DDim> UniformBSplines<CDim, D, Periodic>::
433 Impl<DDim, MemorySpace>::eval_deriv(
434 Kokkos::mdspan<double, Kokkos::dextents<std::size_t, 1>> derivs,
435 ddc::Coordinate<CDim> const& x) const
436{
437 KOKKOS_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 m_reference + jmin;
475}
476
477template <class CDim, std::size_t D, bool Periodic>
478template <class DDim, class MemorySpace>
479KOKKOS_INLINE_FUNCTION ddc::DiscreteElement<DDim> UniformBSplines<CDim, D, Periodic>::
480 Impl<DDim, MemorySpace>::eval_basis_and_n_derivs(
481 Kokkos::mdspan<double, Kokkos::dextents<std::size_t, 2>> 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 KOKKOS_ASSERT(x - rmin() >= -length() * 1e-14)
494 KOKKOS_ASSERT(rmax() - x >= -length() * 1e-14)
495 // KOKKOS_ASSERT(n >= 0) as long as n is unsigned
496 KOKKOS_ASSERT(n <= degree())
497 KOKKOS_ASSERT(derivs.extent(0) == 1 + degree())
498 KOKKOS_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 < static_cast<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 < static_cast<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 < static_cast<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 m_reference + jmin;
568}
569
570template <class CDim, std::size_t D, bool Periodic>
571template <class DDim, class MemorySpace>
572KOKKOS_INLINE_FUNCTION void UniformBSplines<CDim, D, Periodic>::Impl<DDim, MemorySpace>::
573 get_icell_and_offset(int& icell, double& offset, ddc::Coordinate<CDim> const& x) const
574{
575 KOKKOS_ASSERT(x - rmin() >= -length() * 1e-14)
576 KOKKOS_ASSERT(rmax() - x >= -length() * 1e-14)
577
578 double const inv_dx = inv_step();
579 if (x <= rmin()) {
580 icell = 0;
581 offset = 0.0;
582 } else if (x >= rmax()) {
583 icell = ncells() - 1;
584 offset = 1.0;
585 } else {
586 offset = (x - rmin()) * inv_dx;
587 icell = static_cast<int>(offset);
588 offset = offset - icell;
589
590 // When x is very close to xmax, round-off may cause the wrong answer
591 // icell=ncells and x_offset=0, which we convert to the case x=xmax:
592 if (icell == static_cast<int>(ncells()) && offset == 0.0) {
593 icell = ncells() - 1;
594 offset = 1.0;
595 }
596 }
597}
598
599} // namespace ddc
friend class ChunkSpan
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 std::size_t ncells() const noexcept
Returns the number of cells over which the B-splines are defined.
Impl(Impl &&x)=default
Move-constructs.
KOKKOS_INLINE_FUNCTION std::size_t nbasis() const noexcept
Returns the number of basis functions.
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...
KOKKOS_INLINE_FUNCTION discrete_element_type eval_basis_and_n_derivs(Kokkos::mdspan< double, Kokkos::dextents< std::size_t, 2 > > derivs, ddc::Coordinate< CDim > const &x, std::size_t n) const
Evaluates non-zero B-spline values and derivatives at a given coordinate.
Impl(Impl< DDim, OriginMemorySpace > const &impl)
Copy-constructs from another Impl with a different Kokkos memory space.
Impl(Impl const &x)=default
Copy-constructs.
KOKKOS_INLINE_FUNCTION discrete_element_type eval_deriv(Kokkos::mdspan< double, Kokkos::dextents< std::size_t, 1 > > derivs, ddc::Coordinate< CDim > const &x) const
Evaluates non-zero B-spline derivatives 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.
Impl & operator=(Impl const &x)=default
Copy-assigns.
KOKKOS_INLINE_FUNCTION std::size_t npoints() const noexcept
The number of break points.
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(RandomIt breaks_begin, RandomIt breaks_end)
Constructs an Impl by iterating over a range of break points from begin to end.
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 std::size_t size() const noexcept
Returns the number of elements necessary to construct a spline representation of a function.
Impl(std::initializer_list< ddc::Coordinate< CDim > > breaks)
Constructs an Impl using a brace-list, i.e.
Impl & operator=(Impl &&x)=default
Move-assigns.
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.
KOKKOS_INLINE_FUNCTION discrete_element_type eval_basis(Kokkos::mdspan< double, Kokkos::dextents< std::size_t, 1 > > values, ddc::Coordinate< CDim > const &x) const
Evaluates non-zero B-splines at a given coordinate.
~Impl()=default
Destructs.
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.
Impl(std::vector< ddc::Coordinate< CDim > > const &breaks)
Constructs an Impl using a std::vector.
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 std::size_t ncells() const noexcept
Returns the number of cells over which the B-splines are defined.
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(Impl const &x)=default
Copy-constructs.
KOKKOS_INLINE_FUNCTION double length() const noexcept
Returns the length of the domain.
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 discrete_element_type eval_deriv(Kokkos::mdspan< double, Kokkos::dextents< std::size_t, 1 > > derivs, ddc::Coordinate< CDim > const &x) const
Evaluates non-zero B-spline derivatives at a given coordinate.
~Impl()=default
Destructs.
Impl(Impl< DDim, OriginMemorySpace > const &impl)
Copy-constructs from another Impl with a different Kokkos memory space.
KOKKOS_INLINE_FUNCTION discrete_element_type eval_basis_and_n_derivs(Kokkos::mdspan< double, Kokkos::dextents< std::size_t, 2 > > derivs, ddc::Coordinate< CDim > const &x, std::size_t n) const
Evaluates non-zero B-spline values and derivatives at a given coordinate.
Impl & operator=(Impl &&x)=default
Move-assigns.
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 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...
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 discrete_element_type eval_basis(Kokkos::mdspan< double, Kokkos::dextents< std::size_t, 1 > > values, ddc::Coordinate< CDim > const &x) const
Evaluates non-zero B-splines 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 std::size_t nbasis() const noexcept
Returns the number of basis functions.
Impl & operator=(Impl const &x)=default
Copy-assigns.
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.
Impl(ddc::Coordinate< CDim > rmin, ddc::Coordinate< CDim > rmax, std::size_t ncells)
Constructs a spline basis (B-splines) with n equidistant knots over .
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 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.
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.
constexpr bool is_non_uniform_bsplines_v
Indicates if a tag corresponds to non-uniform B-splines or not.