20struct NonUniformBSplinesBase
32
33
34
35
36
37
38
39
40template <
class CDim, std::size_t D>
43 static_assert(D > 0,
"Parameter `D` must be positive");
47 using continuous_dimension_type = CDim;
53
54
55
56 static constexpr std::size_t
degree()
noexcept
62
63
64
67 return CDim::PERIODIC;
71
72
73
80
81
82
83
84 template <
class DDim,
class MemorySpace>
87 template <
class ODDim,
class OMemorySpace>
101 using discrete_element_type = DiscreteElement<DDim>;
114
115
116
117
118
119
120 Impl(std::initializer_list<
ddc::Coordinate<CDim>> breaks)
121 :
Impl(breaks.begin(), breaks.end())
126
127
128
129
130
131
132 explicit Impl(std::vector<
ddc::Coordinate<CDim>>
const& breaks)
133 :
Impl(breaks.begin(), breaks.end())
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155 template <
class RandomIt>
156 Impl(RandomIt breaks_begin, RandomIt breaks_end);
159
160
161
162 template <
class OriginMemorySpace>
163 explicit Impl(
Impl<DDim, OriginMemorySpace>
const& impl)
164 : m_knot_domain(impl.m_knot_domain)
165 , m_break_point_domain(impl.m_break_point_domain)
170
171
172
176
177
178
185
186
187
188
192
193
194
195
199
200
201
202
203
204
205
206
207
208
209
211 eval_basis(DSpan1D values,
ddc::Coordinate<CDim>
const& x)
const;
214
215
216
217
218
219
220
221
222
223
224
226 eval_deriv(DSpan1D derivs,
ddc::Coordinate<CDim>
const& x)
const;
229
230
231
232
233
234
235
236
237
238
239
240
243 ddc::Coordinate<CDim>
const& x,
244 std::size_t n)
const;
247
248
249
250
251
252
253
254
255 template <
class Layout,
class MemorySpace2>
262
263
264
265
266
267
268
269
273 return ddc::DiscreteElement<knot_discrete_dimension_type>(
274 (ix - discrete_element_type(0)).value());
278
279
280
281
282
283
284
285
294
295
296
299 return ddc::coordinate(m_break_point_domain.front());
303
304
305
308 return ddc::coordinate(m_break_point_domain.back());
312
313
314
321
322
323
324
325
326
327
334
335
336
339 return discrete_domain_type(discrete_element_type(0), discrete_vector_type(
size()));
343
344
345
349 return m_break_point_domain;
353
354
355
356
357
360 return m_knot_domain.size() - 2 *
degree();
364
365
366
367
368
375
376
377
378
379
380
388 ddc::DiscreteElement<knot_discrete_dimension_type>
const& ic)
const
390 return discrete_element_type((ic - m_break_point_domain.front()).value());
394
395
396
397
399 ddc::Coordinate<CDim>
const& x)
const;
409
410
411
412
418template <
class RandomIt>
420 RandomIt
const breaks_begin,
421 RandomIt
const breaks_end)
423 ddc::DiscreteElement<knot_discrete_dimension_type>(0),
425 (breaks_end - breaks_begin)
427 , m_break_point_domain(
428 ddc::DiscreteElement<knot_discrete_dimension_type>(
degree()),
430 (breaks_end - breaks_begin)))
432 std::vector<
ddc::Coordinate<CDim>> knots((breaks_end - breaks_begin) + 2 *
degree());
435 for (RandomIt it = breaks_begin; it < breaks_end; ++it) {
439 ddc::Coordinate<CDim>
const rmin = knots[
degree()];
440 ddc::Coordinate<CDim>
const rmax = knots[(breaks_end - breaks_begin) +
degree() - 1];
445 double const period = rmax - rmin;
446 for (std::size_t i = 1; i <
degree() + 1; ++i) {
452 for (std::size_t i = 1; i <
degree() + 1; ++i) {
457 ddc::init_discrete_space<knot_discrete_dimension_type>(knots);
460template <
class CDim, std::size_t D>
461template <
class DDim,
class MemorySpace>
463 Impl<DDim, MemorySpace>::
eval_basis(DSpan1D values,
ddc::Coordinate<CDim>
const& x)
const
465 assert(values.size() == D + 1);
470 assert(x - rmin() >= -length() * 1e-14);
471 assert(rmax() - x >= -length() * 1e-14);
472 assert(values.size() == degree() + 1);
475 ddc::DiscreteElement<knot_discrete_dimension_type>
const icell = find_cell_start(x);
477 assert(icell >= m_break_point_domain.front());
478 assert(icell <= m_break_point_domain.back());
479 assert(ddc::coordinate(icell) - x <= length() * 1e-14);
480 assert(x - ddc::coordinate(icell + 1) <= length() * 1e-14);
485 for (std::size_t j = 0; j <
degree(); ++j) {
486 left[j] = x -
ddc::coordinate(icell - j);
487 right[j] =
ddc::coordinate(icell + j + 1) - x;
489 for (std::size_t r = 0; r < j + 1; ++r) {
490 temp = values[r] / (right[r] + left[j - r]);
491 values[r] = saved + right[r] * temp;
492 saved = left[j - r] * temp;
494 values[j + 1] = saved;
497 return get_first_bspline_in_cell(icell);
500template <
class CDim, std::size_t D>
501template <
class DDim,
class MemorySpace>
503 Impl<DDim, MemorySpace>::
eval_deriv(DSpan1D derivs,
ddc::Coordinate<CDim>
const& x)
const
508 assert(x - rmin() >= -length() * 1e-14);
509 assert(rmax() - x >= -length() * 1e-14);
510 assert(derivs.size() == degree() + 1);
513 ddc::DiscreteElement<knot_discrete_dimension_type>
const icell = find_cell_start(x);
515 assert(icell >= m_break_point_domain.front());
516 assert(icell <= m_break_point_domain.back());
517 assert(ddc::coordinate(icell) <= x);
518 assert(ddc::coordinate(icell + 1) >= x);
523
524
525
526
530 for (std::size_t j = 0; j <
degree() - 1; ++j) {
531 left[j] = x -
ddc::coordinate(icell - j);
532 right[j] =
ddc::coordinate(icell + j + 1) - x;
534 for (std::size_t r = 0; r < j + 1; ++r) {
535 temp = derivs[r] / (right[r] + left[j - r]);
536 derivs[r] = saved + right[r] * temp;
537 saved = left[j - r] * temp;
539 derivs[j + 1] = saved;
543
544
545
547 / (
ddc::coordinate(icell + 1) -
ddc::coordinate(icell + 1 -
degree()));
549 for (std::size_t j = 1; j <
degree(); ++j) {
552 / (
ddc::coordinate(icell + j + 1) -
ddc::coordinate(icell + j + 1 -
degree()));
553 derivs[j] = temp - saved;
557 return get_first_bspline_in_cell(icell);
560template <
class CDim, std::size_t D>
561template <
class DDim,
class MemorySpace>
563 Impl<DDim, MemorySpace>::eval_basis_and_n_derivs(
564 ddc::DSpan2D
const derivs,
565 ddc::Coordinate<CDim>
const& x,
566 std::size_t
const n)
const
571 std::array<
double, 2 * (
degree() + 1)> a_ptr;
572 Kokkos::mdspan<
double, Kokkos::extents<std::size_t,
degree() + 1, 2>>
const a(a_ptr.data());
575 Kokkos::mdspan<
double, Kokkos::extents<std::size_t,
degree() + 1,
degree() + 1>>
const ndu(
578 assert(x - rmin() >= -length() * 1e-14);
579 assert(rmax() - x >= -length() * 1e-14);
581 assert(n <= degree());
582 assert(derivs.extent(0) == 1 + degree());
583 assert(derivs.extent(1) == 1 + n);
586 ddc::DiscreteElement<knot_discrete_dimension_type>
const icell = find_cell_start(x);
588 assert(icell >= m_break_point_domain.front());
589 assert(icell <= m_break_point_domain.back());
590 assert(ddc::coordinate(icell) <= x);
591 assert(ddc::coordinate(icell + 1) >= x);
603 DDC_MDSPAN_ACCESS_OP(ndu, 0, 0) = 1.0;
604 for (std::size_t j = 0; j <
degree(); ++j) {
605 left[j] = x -
ddc::coordinate(icell - j);
606 right[j] =
ddc::coordinate(icell + j + 1) - x;
608 for (std::size_t r = 0; r < j + 1; ++r) {
611 DDC_MDSPAN_ACCESS_OP(ndu, r, j + 1) = 1.0 / (right[r] + left[j - r]);
614 temp = DDC_MDSPAN_ACCESS_OP(ndu, j, r) * DDC_MDSPAN_ACCESS_OP(ndu, r, j + 1);
615 DDC_MDSPAN_ACCESS_OP(ndu, j + 1, r) = saved + right[r] * temp;
616 saved = left[j - r] * temp;
618 DDC_MDSPAN_ACCESS_OP(ndu, j + 1, j + 1) = saved;
621 for (std::size_t j = 0; j <
degree() + 1; ++j) {
622 DDC_MDSPAN_ACCESS_OP(derivs, j, 0) = DDC_MDSPAN_ACCESS_OP(ndu, degree(), j);
625 for (
int r = 0; r <
int(
degree() + 1); ++r) {
628 DDC_MDSPAN_ACCESS_OP(a, 0, 0) = 1.0;
629 for (
int k = 1; k <
int(n + 1); ++k) {
631 int const rk = r - k;
634 DDC_MDSPAN_ACCESS_OP(a, 0, s2)
635 = DDC_MDSPAN_ACCESS_OP(a, 0, s1) * DDC_MDSPAN_ACCESS_OP(ndu, rk, pk + 1);
636 d = DDC_MDSPAN_ACCESS_OP(a, 0, s2) * DDC_MDSPAN_ACCESS_OP(ndu, pk, rk);
638 int const j1 = rk > -1 ? 1 : (-rk);
639 int const j2 = (r - 1) <= pk ? k : (
degree() - r + 1);
640 for (
int j = j1; j < j2; ++j) {
641 DDC_MDSPAN_ACCESS_OP(a, j, s2)
642 = (DDC_MDSPAN_ACCESS_OP(a, j, s1) - DDC_MDSPAN_ACCESS_OP(a, j - 1, s1))
643 * DDC_MDSPAN_ACCESS_OP(ndu, rk + j, pk + 1);
644 d += DDC_MDSPAN_ACCESS_OP(a, j, s2) * DDC_MDSPAN_ACCESS_OP(ndu, pk, rk + j);
647 DDC_MDSPAN_ACCESS_OP(a, k, s2) = -DDC_MDSPAN_ACCESS_OP(a, k - 1, s1)
648 * DDC_MDSPAN_ACCESS_OP(ndu, r, pk + 1);
649 d += DDC_MDSPAN_ACCESS_OP(a, k, s2) * DDC_MDSPAN_ACCESS_OP(ndu, pk, r);
651 DDC_MDSPAN_ACCESS_OP(derivs, r, k) = d;
652 Kokkos::kokkos_swap(s1, s2);
657 for (
int k = 1; k <
int(n + 1); ++k) {
658 for (std::size_t i = 0; i < derivs.extent(0); ++i) {
659 DDC_MDSPAN_ACCESS_OP(derivs, i, k) *= r;
664 return get_first_bspline_in_cell(icell);
667template <
class CDim, std::size_t D>
668template <
class DDim,
class MemorySpace>
671 D>::
Impl<DDim, MemorySpace>::find_cell_start(
ddc::Coordinate<CDim>
const& x)
const
673 assert(x - rmin() >= -length() * 1e-14);
674 assert(rmax() - x >= -length() * 1e-14);
677 return m_break_point_domain.front();
680 return m_break_point_domain.back() - 1;
684 ddc::DiscreteElement<knot_discrete_dimension_type> low = m_break_point_domain.front();
685 ddc::DiscreteElement<knot_discrete_dimension_type> high = m_break_point_domain.back();
686 ddc::DiscreteElement<knot_discrete_dimension_type> icell = low + (high - low) / 2;
687 while (x <
ddc::coordinate(icell) || x >=
ddc::coordinate(icell + 1)) {
688 if (x <
ddc::coordinate(icell)) {
693 icell = low + (high - low) / 2;
700template <
class Layout,
class MemorySpace2>
703 ddc::
ChunkSpan<
double, discrete_domain_type, Layout, MemorySpace2> int_vals)
const
705 assert([&]() ->
bool {
706 if constexpr (is_periodic()) {
707 return int_vals.size() == nbasis() || int_vals.size() == size();
709 return int_vals.size() == nbasis();
713 double const inv_deg = 1.0 / (
degree() + 1);
715 discrete_domain_type
const dom_bsplines(
717 for (
auto ix : dom_bsplines) {
724 if (int_vals.size() ==
size()) {
725 discrete_domain_type
const dom_bsplines_wrap(
727 for (
auto ix : dom_bsplines_wrap) {
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.