10#include <initializer_list>
16#include <Kokkos_Core.hpp>
24struct NonUniformBSplinesBase
36
37
38
39
40
41
42
43
44template <
class CDim, std::size_t D>
47 static_assert(D > 0,
"Parameter `D` must be positive");
51 using continuous_dimension_type = CDim;
57
58
59
60 static constexpr std::size_t
degree()
noexcept
66
67
68
71 return CDim::PERIODIC;
75
76
77
84
85
86
87
88 template <
class DDim,
class MemorySpace>
91 template <
class ODDim,
class OMemorySpace>
105 using discrete_element_type = DiscreteElement<DDim>;
114 ddc::DiscreteElement<DDim> m_reference;
120
121
122
123
124
125
126 Impl(std::initializer_list<
ddc::Coordinate<CDim>> breaks)
127 :
Impl(breaks.begin(), breaks.end())
132
133
134
135
136
137
138 explicit Impl(std::vector<
ddc::Coordinate<CDim>>
const& breaks)
139 :
Impl(breaks.begin(), breaks.end())
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161 template <
class RandomIt>
162 Impl(RandomIt breaks_begin, RandomIt breaks_end);
165
166
167
168 template <
class OriginMemorySpace>
169 explicit Impl(
Impl<DDim, OriginMemorySpace>
const& impl)
170 : m_knot_domain(impl.m_knot_domain)
171 , m_break_point_domain(impl.m_break_point_domain)
172 , m_reference(impl.m_reference)
177
178
179
183
184
185
192
193
194
195
199
200
201
202
206
207
208
209
210
211
212
213
214
215
216
218 eval_basis(DSpan1D values,
ddc::Coordinate<CDim>
const& x)
const;
221
222
223
224
225
226
227
228
229
230
231
233 eval_deriv(DSpan1D derivs,
ddc::Coordinate<CDim>
const& x)
const;
236
237
238
239
240
241
242
243
244
245
246
247
250 ddc::Coordinate<CDim>
const& x,
251 std::size_t n)
const;
254
255
256
257
258
259
260
261
265 return m_knot_domain.front() + (ix - m_reference).value();
269
270
271
272
273
274
275
276
285
286
287
290 return ddc::coordinate(m_break_point_domain.front());
294
295
296
299 return ddc::coordinate(m_break_point_domain.back());
303
304
305
312
313
314
315
316
317
318
325
326
327
330 return discrete_domain_type(m_reference, discrete_vector_type(
size()));
334
335
336
340 return m_break_point_domain;
344
345
346
347
348
351 return m_knot_domain.size() - 2 *
degree();
355
356
357
358
359
366
367
368
369
370
371
379 ddc::DiscreteElement<knot_discrete_dimension_type>
const& ic)
const
381 return m_reference + (ic - m_break_point_domain.front()).value();
385
386
387
388
390 ddc::Coordinate<CDim>
const& x)
const;
400
401
402
403
409template <
class RandomIt>
411 RandomIt
const breaks_begin,
412 RandomIt
const breaks_end)
414 ddc::DiscreteElement<knot_discrete_dimension_type>(0),
416 (breaks_end - breaks_begin)
418 , m_break_point_domain(
419 ddc::DiscreteElement<knot_discrete_dimension_type>(
degree()),
421 (breaks_end - breaks_begin)))
422 , m_reference(
ddc::create_reference_discrete_element<DDim>())
424 std::vector<
ddc::Coordinate<CDim>> knots((breaks_end - breaks_begin) + 2 *
degree());
427 for (RandomIt it = breaks_begin; it < breaks_end; ++it) {
431 ddc::Coordinate<CDim>
const rmin = knots[
degree()];
432 ddc::Coordinate<CDim>
const rmax = knots[(breaks_end - breaks_begin) +
degree() - 1];
437 double const period = rmax - rmin;
438 for (std::size_t i = 1; i <
degree() + 1; ++i) {
444 for (std::size_t i = 1; i <
degree() + 1; ++i) {
449 ddc::init_discrete_space<knot_discrete_dimension_type>(knots);
452template <
class CDim, std::size_t D>
453template <
class DDim,
class MemorySpace>
455 Impl<DDim, MemorySpace>::
eval_basis(DSpan1D values,
ddc::Coordinate<CDim>
const& x)
const
457 KOKKOS_ASSERT(values.size() == D + 1)
462 KOKKOS_ASSERT(x - rmin() >= -length() * 1e-14)
463 KOKKOS_ASSERT(rmax() - x >= -length() * 1e-14)
464 KOKKOS_ASSERT(values.size() == degree() + 1)
467 ddc::DiscreteElement<knot_discrete_dimension_type>
const icell = find_cell_start(x);
469 KOKKOS_ASSERT(icell >= m_break_point_domain.front())
470 KOKKOS_ASSERT(icell <= m_break_point_domain.back())
471 KOKKOS_ASSERT(ddc::coordinate(icell) - x <= length() * 1e-14)
472 KOKKOS_ASSERT(x - ddc::coordinate(icell + 1) <= length() * 1e-14)
477 for (std::size_t j = 0; j <
degree(); ++j) {
478 left[j] = x -
ddc::coordinate(icell - j);
479 right[j] =
ddc::coordinate(icell + j + 1) - x;
481 for (std::size_t r = 0; r < j + 1; ++r) {
482 temp = values[r] / (right[r] + left[j - r]);
483 values[r] = saved + right[r] * temp;
484 saved = left[j - r] * temp;
486 values[j + 1] = saved;
489 return get_first_bspline_in_cell(icell);
492template <
class CDim, std::size_t D>
493template <
class DDim,
class MemorySpace>
495 Impl<DDim, MemorySpace>::
eval_deriv(DSpan1D derivs,
ddc::Coordinate<CDim>
const& x)
const
500 KOKKOS_ASSERT(x - rmin() >= -length() * 1e-14)
501 KOKKOS_ASSERT(rmax() - x >= -length() * 1e-14)
502 KOKKOS_ASSERT(derivs.size() == degree() + 1)
505 ddc::DiscreteElement<knot_discrete_dimension_type>
const icell = find_cell_start(x);
507 KOKKOS_ASSERT(icell >= m_break_point_domain.front())
508 KOKKOS_ASSERT(icell <= m_break_point_domain.back())
509 KOKKOS_ASSERT(ddc::coordinate(icell) <= x)
510 KOKKOS_ASSERT(ddc::coordinate(icell + 1) >= x)
515
516
517
518
522 for (std::size_t j = 0; j <
degree() - 1; ++j) {
523 left[j] = x -
ddc::coordinate(icell - j);
524 right[j] =
ddc::coordinate(icell + j + 1) - x;
526 for (std::size_t r = 0; r < j + 1; ++r) {
527 temp = derivs[r] / (right[r] + left[j - r]);
528 derivs[r] = saved + right[r] * temp;
529 saved = left[j - r] * temp;
531 derivs[j + 1] = saved;
535
536
537
539 / (
ddc::coordinate(icell + 1) -
ddc::coordinate(icell + 1 -
degree()));
541 for (std::size_t j = 1; j <
degree(); ++j) {
544 / (
ddc::coordinate(icell + j + 1) -
ddc::coordinate(icell + j + 1 -
degree()));
545 derivs[j] = temp - saved;
549 return get_first_bspline_in_cell(icell);
552template <
class CDim, std::size_t D>
553template <
class DDim,
class MemorySpace>
555 Impl<DDim, MemorySpace>::eval_basis_and_n_derivs(
556 ddc::DSpan2D
const derivs,
557 ddc::Coordinate<CDim>
const& x,
558 std::size_t
const n)
const
563 std::array<
double, 2 * (
degree() + 1)> a_ptr;
564 Kokkos::mdspan<
double, Kokkos::extents<std::size_t,
degree() + 1, 2>>
const a(a_ptr.data());
567 Kokkos::mdspan<
double, Kokkos::extents<std::size_t,
degree() + 1,
degree() + 1>>
const ndu(
570 KOKKOS_ASSERT(x - rmin() >= -length() * 1e-14)
571 KOKKOS_ASSERT(rmax() - x >= -length() * 1e-14)
573 KOKKOS_ASSERT(n <= degree())
574 KOKKOS_ASSERT(derivs.extent(0) == 1 + degree())
575 KOKKOS_ASSERT(derivs.extent(1) == 1 + n)
578 ddc::DiscreteElement<knot_discrete_dimension_type>
const icell = find_cell_start(x);
580 KOKKOS_ASSERT(icell >= m_break_point_domain.front())
581 KOKKOS_ASSERT(icell <= m_break_point_domain.back())
582 KOKKOS_ASSERT(ddc::coordinate(icell) <= x)
583 KOKKOS_ASSERT(ddc::coordinate(icell + 1) >= x)
595 DDC_MDSPAN_ACCESS_OP(ndu, 0, 0) = 1.0;
596 for (std::size_t j = 0; j <
degree(); ++j) {
597 left[j] = x -
ddc::coordinate(icell - j);
598 right[j] =
ddc::coordinate(icell + j + 1) - x;
600 for (std::size_t r = 0; r < j + 1; ++r) {
603 DDC_MDSPAN_ACCESS_OP(ndu, r, j + 1) = 1.0 / (right[r] + left[j - r]);
606 temp = DDC_MDSPAN_ACCESS_OP(ndu, j, r) * DDC_MDSPAN_ACCESS_OP(ndu, r, j + 1);
607 DDC_MDSPAN_ACCESS_OP(ndu, j + 1, r) = saved + right[r] * temp;
608 saved = left[j - r] * temp;
610 DDC_MDSPAN_ACCESS_OP(ndu, j + 1, j + 1) = saved;
613 for (std::size_t j = 0; j <
degree() + 1; ++j) {
614 DDC_MDSPAN_ACCESS_OP(derivs, j, 0) = DDC_MDSPAN_ACCESS_OP(ndu, degree(), j);
617 for (
int r = 0; r <
static_cast<
int>(
degree() + 1); ++r) {
620 DDC_MDSPAN_ACCESS_OP(a, 0, 0) = 1.0;
621 for (
int k = 1; k <
static_cast<
int>(n + 1); ++k) {
623 int const rk = r - k;
626 DDC_MDSPAN_ACCESS_OP(a, 0, s2)
627 = DDC_MDSPAN_ACCESS_OP(a, 0, s1) * DDC_MDSPAN_ACCESS_OP(ndu, rk, pk + 1);
628 d = DDC_MDSPAN_ACCESS_OP(a, 0, s2) * DDC_MDSPAN_ACCESS_OP(ndu, pk, rk);
630 int const j1 = rk > -1 ? 1 : (-rk);
631 int const j2 = (r - 1) <= pk ? k : (
degree() - r + 1);
632 for (
int j = j1; j < j2; ++j) {
633 DDC_MDSPAN_ACCESS_OP(a, j, s2)
634 = (DDC_MDSPAN_ACCESS_OP(a, j, s1) - DDC_MDSPAN_ACCESS_OP(a, j - 1, s1))
635 * DDC_MDSPAN_ACCESS_OP(ndu, rk + j, pk + 1);
636 d += DDC_MDSPAN_ACCESS_OP(a, j, s2) * DDC_MDSPAN_ACCESS_OP(ndu, pk, rk + j);
639 DDC_MDSPAN_ACCESS_OP(a, k, s2) = -DDC_MDSPAN_ACCESS_OP(a, k - 1, s1)
640 * DDC_MDSPAN_ACCESS_OP(ndu, r, pk + 1);
641 d += DDC_MDSPAN_ACCESS_OP(a, k, s2) * DDC_MDSPAN_ACCESS_OP(ndu, pk, r);
643 DDC_MDSPAN_ACCESS_OP(derivs, r, k) = d;
644 Kokkos::kokkos_swap(s1, s2);
649 for (
int k = 1; k <
static_cast<
int>(n + 1); ++k) {
650 for (std::size_t i = 0; i < derivs.extent(0); ++i) {
651 DDC_MDSPAN_ACCESS_OP(derivs, i, k) *= r;
656 return get_first_bspline_in_cell(icell);
659template <
class CDim, std::size_t D>
660template <
class DDim,
class MemorySpace>
663 D>::
Impl<DDim, MemorySpace>::find_cell_start(
ddc::Coordinate<CDim>
const& x)
const
665 KOKKOS_ASSERT(x - rmin() >= -length() * 1e-14)
666 KOKKOS_ASSERT(rmax() - x >= -length() * 1e-14)
669 return m_break_point_domain.front();
672 return m_break_point_domain.back() - 1;
676 ddc::DiscreteElement<knot_discrete_dimension_type> low = m_break_point_domain.front();
677 ddc::DiscreteElement<knot_discrete_dimension_type> high = m_break_point_domain.back();
678 ddc::DiscreteElement<knot_discrete_dimension_type> icell = low + (high - low) / 2;
679 while (x <
ddc::coordinate(icell) || x >=
ddc::coordinate(icell + 1)) {
680 if (x <
ddc::coordinate(icell)) {
685 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.