10#include <initializer_list>
19#include <Kokkos_Core.hpp>
25struct NonUniformBSplinesBase
37
38
39
40
41
42
43
44
45template <
class CDim, std::size_t D,
bool Periodic>
47 : detail::NonUniformBSplinesBase
50 static_assert(D > 0,
"Parameter `D` must be positive");
54 using continuous_dimension_type = CDim;
60
61
62
63 static constexpr std::size_t
degree()
noexcept
69
70
71
78
79
80
87
88
89
90
91 template <
class DDim,
class MemorySpace>
94 template <
class ODDim,
class OMemorySpace>
108 using discrete_element_type = DiscreteElement<DDim>;
117 ddc::DiscreteElement<DDim> m_reference;
123
124
125
126
127
128
129 Impl(std::initializer_list<
ddc::Coordinate<CDim>> breaks)
130 :
Impl(breaks.begin(), breaks.end())
135
136
137
138
139
140
141 explicit Impl(std::vector<
ddc::Coordinate<CDim>>
const& breaks)
142 :
Impl(breaks.begin(), breaks.end())
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164 template <
class RandomIt>
165 Impl(RandomIt breaks_begin, RandomIt breaks_end);
168
169
170
171 template <
class OriginMemorySpace>
172 explicit Impl(
Impl<DDim, OriginMemorySpace>
const& impl)
173 : m_knot_domain(impl.m_knot_domain)
174 , m_break_point_domain(impl.m_break_point_domain)
175 , m_reference(impl.m_reference)
180
181
182
186
187
188
195
196
197
198
202
203
204
205
209
210
211
212
213
214
215
216
217
218
219
220 KOKKOS_INLINE_FUNCTION discrete_element_type
eval_basis(
221 Kokkos::mdspan<
double, Kokkos::dextents<std::size_t, 1>> values,
222 ddc::Coordinate<CDim>
const& x)
const;
225
226
227
228
229
230
231
232
233
234
235
236 KOKKOS_INLINE_FUNCTION discrete_element_type
eval_deriv(
237 Kokkos::mdspan<
double, Kokkos::dextents<std::size_t, 1>> derivs,
238 ddc::Coordinate<CDim>
const& x)
const;
241
242
243
244
245
246
247
248
249
250
251
252
254 Kokkos::mdspan<
double, Kokkos::dextents<std::size_t, 2>> derivs,
255 ddc::Coordinate<CDim>
const& x,
256 std::size_t n)
const;
259
260
261
262
263
264
265
266
267 KOKKOS_INLINE_FUNCTION
ddc::DiscreteElement<knot_discrete_dimension_type>
270 return m_knot_domain.front() + (ix - m_reference).value();
274
275
276
277
278
279
280
281
282 KOKKOS_INLINE_FUNCTION
ddc::DiscreteElement<knot_discrete_dimension_type>
290
291
292
293 KOKKOS_INLINE_FUNCTION
ddc::Coordinate<CDim>
rmin()
const noexcept
295 return ddc::coordinate(m_break_point_domain.front());
299
300
301
302 KOKKOS_INLINE_FUNCTION
ddc::Coordinate<CDim>
rmax()
const noexcept
304 return ddc::coordinate(m_break_point_domain.back());
308
309
310
311 KOKKOS_INLINE_FUNCTION Real
length()
const noexcept
317
318
319
320
321
322
323
324 KOKKOS_INLINE_FUNCTION std::size_t
size()
const noexcept
330
331
332
333 KOKKOS_INLINE_FUNCTION discrete_domain_type
full_domain()
const
335 return discrete_domain_type(m_reference, discrete_vector_type(
size()));
339
340
341
345 return m_break_point_domain;
349
350
351
352
353
354 KOKKOS_INLINE_FUNCTION std::size_t
npoints()
const noexcept
356 return m_knot_domain.size() - 2 *
degree();
360
361
362
363
364
365 KOKKOS_INLINE_FUNCTION std::size_t
nbasis()
const noexcept
371
372
373
374
375
376
377 KOKKOS_INLINE_FUNCTION std::size_t
ncells()
const noexcept
383 KOKKOS_INLINE_FUNCTION discrete_element_type get_first_bspline_in_cell(
384 ddc::DiscreteElement<knot_discrete_dimension_type>
const& ic)
const
386 return m_reference + (ic - m_break_point_domain.front()).value();
390
391
392
393
394 KOKKOS_INLINE_FUNCTION
ddc::DiscreteElement<knot_discrete_dimension_type> find_cell_start(
395 ddc::Coordinate<CDim>
const& x)
const;
405
406
407
408
415concept non_uniform_bsplines = discrete_dimension<T> && is_non_uniform_bsplines_v<T>;
421template <
class RandomIt>
423 RandomIt
const breaks_begin,
424 RandomIt
const breaks_end)
426 ddc::DiscreteElement<knot_discrete_dimension_type>(0),
428 (breaks_end - breaks_begin)
430 , m_break_point_domain(
431 ddc::DiscreteElement<knot_discrete_dimension_type>(
degree()),
433 (breaks_end - breaks_begin)))
434 , m_reference(
ddc::create_reference_discrete_element<DDim>())
436 std::vector<
ddc::Coordinate<CDim>> knots((breaks_end - breaks_begin) + 2 *
degree());
439 for (RandomIt it = breaks_begin; it < breaks_end; ++it) {
443 ddc::Coordinate<CDim>
const rmin = knots[
degree()];
444 ddc::Coordinate<CDim>
const rmax = knots[(breaks_end - breaks_begin) +
degree() - 1];
449 Real
const period = rmax - rmin;
450 for (std::size_t i = 1; i <
degree() + 1; ++i) {
456 for (std::size_t i = 1; i <
degree() + 1; ++i) {
461 ddc::init_discrete_space<knot_discrete_dimension_type>(knots);
464template <
class CDim, std::size_t D,
bool Periodic>
465template <
class DDim,
class MemorySpace>
468 Kokkos::mdspan<
double, Kokkos::dextents<std::size_t, 1>> values,
469 ddc::Coordinate<CDim>
const& x)
const
471 KOKKOS_ASSERT(values.size() == D + 1)
476 KOKKOS_ASSERT(x -
rmin() >= -
length() * 100 * std::numeric_limits<Real>::epsilon())
477 KOKKOS_ASSERT(
rmax() - x >= -
length() * 100 * std::numeric_limits<Real>::epsilon())
478 KOKKOS_ASSERT(values.size() ==
degree() + 1)
481 ddc::DiscreteElement<knot_discrete_dimension_type>
const icell = find_cell_start(x);
483 KOKKOS_ASSERT(icell >= m_break_point_domain.front())
484 KOKKOS_ASSERT(icell <= m_break_point_domain.back())
486 ddc::coordinate(icell) - x <=
length() * 100 * std::numeric_limits<Real>::epsilon())
488 x -
ddc::coordinate(icell + 1) <=
length() * 100 * std::numeric_limits<Real>::epsilon())
493 for (std::size_t j = 0; j <
degree(); ++j) {
494 left[j] = x -
ddc::coordinate(icell - j);
495 right[j] =
ddc::coordinate(icell + j + 1) - x;
497 for (std::size_t r = 0; r < j + 1; ++r) {
498 temp = values[r] / (right[r] + left[j - r]);
499 values[r] = saved + right[r] * temp;
500 saved = left[j - r] * temp;
502 values[j + 1] = saved;
505 return get_first_bspline_in_cell(icell);
508template <
class CDim, std::size_t D,
bool Periodic>
509template <
class DDim,
class MemorySpace>
512 Kokkos::mdspan<
double, Kokkos::dextents<std::size_t, 1>> derivs,
513 ddc::Coordinate<CDim>
const& x)
const
518 KOKKOS_ASSERT(x -
rmin() >= -
length() * 100 * std::numeric_limits<Real>::epsilon())
519 KOKKOS_ASSERT(
rmax() - x >= -
length() * 100 * std::numeric_limits<Real>::epsilon())
520 KOKKOS_ASSERT(derivs.size() ==
degree() + 1)
523 ddc::DiscreteElement<knot_discrete_dimension_type>
const icell = find_cell_start(x);
525 KOKKOS_ASSERT(icell >= m_break_point_domain.front())
526 KOKKOS_ASSERT(icell <= m_break_point_domain.back())
528 ddc::coordinate(icell) - x <=
length() * 100 * std::numeric_limits<Real>::epsilon())
530 x -
ddc::coordinate(icell + 1) <=
length() * 100 * std::numeric_limits<Real>::epsilon())
535
536
537
538
542 for (std::size_t j = 0; j <
degree() - 1; ++j) {
543 left[j] = x -
ddc::coordinate(icell - j);
544 right[j] =
ddc::coordinate(icell + j + 1) - x;
546 for (std::size_t r = 0; r < j + 1; ++r) {
547 temp = derivs[r] / (right[r] + left[j - r]);
548 derivs[r] = saved + right[r] * temp;
549 saved = left[j - r] * temp;
551 derivs[j + 1] = saved;
555
556
557
559 / (
ddc::coordinate(icell + 1) -
ddc::coordinate(icell + 1 -
degree()));
561 for (std::size_t j = 1; j <
degree(); ++j) {
564 / (
ddc::coordinate(icell + j + 1) -
ddc::coordinate(icell + j + 1 -
degree()));
565 derivs[j] = temp - saved;
569 return get_first_bspline_in_cell(icell);
572template <
class CDim, std::size_t D,
bool Periodic>
573template <
class DDim,
class MemorySpace>
575 Impl<DDim, MemorySpace>::eval_basis_and_n_derivs(
576 Kokkos::mdspan<
double, Kokkos::dextents<std::size_t, 2>>
const derivs,
577 ddc::Coordinate<CDim>
const& x,
578 std::size_t
const n)
const
583 std::array<Real, 2 * (
degree() + 1)> a_ptr;
584 Kokkos::mdspan<Real, Kokkos::extents<std::size_t,
degree() + 1, 2>>
const a(a_ptr.data());
587 Kokkos::mdspan<Real, Kokkos::extents<std::size_t,
degree() + 1,
degree() + 1>>
const ndu(
590 KOKKOS_ASSERT(x -
rmin() >= -
length() * 100 * std::numeric_limits<Real>::epsilon())
591 KOKKOS_ASSERT(
rmax() - x >= -
length() * 100 * std::numeric_limits<Real>::epsilon())
594 KOKKOS_ASSERT(derivs.extent(0) == 1 +
degree())
595 KOKKOS_ASSERT(derivs.extent(1) == 1 + n)
598 ddc::DiscreteElement<knot_discrete_dimension_type>
const icell = find_cell_start(x);
600 KOKKOS_ASSERT(icell >= m_break_point_domain.front())
601 KOKKOS_ASSERT(icell <= m_break_point_domain.back())
603 ddc::coordinate(icell) - x <=
length() * 100 * std::numeric_limits<Real>::epsilon())
605 x -
ddc::coordinate(icell + 1) <=
length() * 100 * std::numeric_limits<Real>::epsilon())
617 DDC_MDSPAN_ACCESS_OP(ndu, 0, 0) = 1.0;
618 for (std::size_t j = 0; j <
degree(); ++j) {
619 left[j] = x -
ddc::coordinate(icell - j);
620 right[j] =
ddc::coordinate(icell + j + 1) - x;
622 for (std::size_t r = 0; r < j + 1; ++r) {
625 DDC_MDSPAN_ACCESS_OP(ndu, r, j + 1) = 1.0 / (right[r] + left[j - r]);
628 temp = DDC_MDSPAN_ACCESS_OP(ndu, j, r) * DDC_MDSPAN_ACCESS_OP(ndu, r, j + 1);
629 DDC_MDSPAN_ACCESS_OP(ndu, j + 1, r) = saved + right[r] * temp;
630 saved = left[j - r] * temp;
632 DDC_MDSPAN_ACCESS_OP(ndu, j + 1, j + 1) = saved;
635 for (std::size_t j = 0; j <
degree() + 1; ++j) {
636 DDC_MDSPAN_ACCESS_OP(derivs, j, 0) = DDC_MDSPAN_ACCESS_OP(ndu,
degree(), j);
639 for (
int r = 0; r <
static_cast<
int>(
degree() + 1); ++r) {
642 DDC_MDSPAN_ACCESS_OP(a, 0, 0) = 1.0;
643 for (
int k = 1; k <
static_cast<
int>(n + 1); ++k) {
645 int const rk = r - k;
648 DDC_MDSPAN_ACCESS_OP(a, 0, s2)
649 = DDC_MDSPAN_ACCESS_OP(a, 0, s1) * DDC_MDSPAN_ACCESS_OP(ndu, rk, pk + 1);
650 d = DDC_MDSPAN_ACCESS_OP(a, 0, s2) * DDC_MDSPAN_ACCESS_OP(ndu, pk, rk);
652 int const j1 = rk > -1 ? 1 : (-rk);
653 int const j2 = (r - 1) <= pk ? k : (
degree() - r + 1);
654 for (
int j = j1; j < j2; ++j) {
655 DDC_MDSPAN_ACCESS_OP(a, j, s2)
656 = (DDC_MDSPAN_ACCESS_OP(a, j, s1) - DDC_MDSPAN_ACCESS_OP(a, j - 1, s1))
657 * DDC_MDSPAN_ACCESS_OP(ndu, rk + j, pk + 1);
658 d += DDC_MDSPAN_ACCESS_OP(a, j, s2) * DDC_MDSPAN_ACCESS_OP(ndu, pk, rk + j);
661 DDC_MDSPAN_ACCESS_OP(a, k, s2) = -DDC_MDSPAN_ACCESS_OP(a, k - 1, s1)
662 * DDC_MDSPAN_ACCESS_OP(ndu, r, pk + 1);
663 d += DDC_MDSPAN_ACCESS_OP(a, k, s2) * DDC_MDSPAN_ACCESS_OP(ndu, pk, r);
665 DDC_MDSPAN_ACCESS_OP(derivs, r, k) = d;
666 Kokkos::kokkos_swap(s1, s2);
671 for (
int k = 1; k <
static_cast<
int>(n + 1); ++k) {
672 for (std::size_t i = 0; i < derivs.extent(0); ++i) {
673 DDC_MDSPAN_ACCESS_OP(derivs, i, k) *= r;
678 return get_first_bspline_in_cell(icell);
681template <
class CDim, std::size_t D,
bool Periodic>
682template <
class DDim,
class MemorySpace>
686 Periodic>::
Impl<DDim, MemorySpace>::find_cell_start(
ddc::Coordinate<CDim>
const& x)
const
688 KOKKOS_ASSERT(x -
rmin() >= -
length() * 100 * std::numeric_limits<Real>::epsilon())
689 KOKKOS_ASSERT(
rmax() - x >= -
length() * 100 * std::numeric_limits<Real>::epsilon())
692 return m_break_point_domain.front();
695 return m_break_point_domain.back() - 1;
699 ddc::DiscreteElement<knot_discrete_dimension_type> low = m_break_point_domain.front();
700 ddc::DiscreteElement<knot_discrete_dimension_type> high = m_break_point_domain.back();
701 ddc::DiscreteElement<knot_discrete_dimension_type> icell = low + (high - low) / 2;
702 while (x <
ddc::coordinate(icell) || x >=
ddc::coordinate(icell + 1)) {
703 if (x <
ddc::coordinate(icell)) {
708 icell = low + (high - low) / 2;
friend class DiscreteDomain
KOKKOS_FUNCTION constexpr bool operator!=(DiscreteVector< OTags... > const &rhs) const noexcept
The top-level namespace of DDC.
constexpr bool is_non_uniform_bsplines_v
Indicates if a tag corresponds to non-uniform B-splines or not.