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>;
110 ddc::DiscreteElement<DDim> m_reference;
116
117
118
119
120
121
122 Impl(std::initializer_list<
ddc::Coordinate<CDim>> breaks)
123 :
Impl(breaks.begin(), breaks.end())
128
129
130
131
132
133
134 explicit Impl(std::vector<
ddc::Coordinate<CDim>>
const& breaks)
135 :
Impl(breaks.begin(), breaks.end())
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157 template <
class RandomIt>
158 Impl(RandomIt breaks_begin, RandomIt breaks_end);
161
162
163
164 template <
class OriginMemorySpace>
165 explicit Impl(
Impl<DDim, OriginMemorySpace>
const& impl)
166 : m_knot_domain(impl.m_knot_domain)
167 , m_break_point_domain(impl.m_break_point_domain)
168 , m_reference(impl.m_reference)
173
174
175
179
180
181
188
189
190
191
195
196
197
198
202
203
204
205
206
207
208
209
210
211
212
214 eval_basis(DSpan1D values,
ddc::Coordinate<CDim>
const& x)
const;
217
218
219
220
221
222
223
224
225
226
227
229 eval_deriv(DSpan1D derivs,
ddc::Coordinate<CDim>
const& x)
const;
232
233
234
235
236
237
238
239
240
241
242
243
246 ddc::Coordinate<CDim>
const& x,
247 std::size_t n)
const;
250
251
252
253
254
255
256
257
261 return m_knot_domain.front() + (ix - m_reference).value();
265
266
267
268
269
270
271
272
281
282
283
286 return ddc::coordinate(m_break_point_domain.front());
290
291
292
295 return ddc::coordinate(m_break_point_domain.back());
299
300
301
308
309
310
311
312
313
314
321
322
323
326 return discrete_domain_type(m_reference, discrete_vector_type(
size()));
330
331
332
336 return m_break_point_domain;
340
341
342
343
344
347 return m_knot_domain.size() - 2 *
degree();
351
352
353
354
355
362
363
364
365
366
367
375 ddc::DiscreteElement<knot_discrete_dimension_type>
const& ic)
const
377 return m_reference + (ic - m_break_point_domain.front()).value();
381
382
383
384
386 ddc::Coordinate<CDim>
const& x)
const;
396
397
398
399
405template <
class RandomIt>
407 RandomIt
const breaks_begin,
408 RandomIt
const breaks_end)
410 ddc::DiscreteElement<knot_discrete_dimension_type>(0),
412 (breaks_end - breaks_begin)
414 , m_break_point_domain(
415 ddc::DiscreteElement<knot_discrete_dimension_type>(
degree()),
417 (breaks_end - breaks_begin)))
418 , m_reference(
ddc::create_reference_discrete_element<DDim>())
420 std::vector<
ddc::Coordinate<CDim>> knots((breaks_end - breaks_begin) + 2 *
degree());
423 for (RandomIt it = breaks_begin; it < breaks_end; ++it) {
427 ddc::Coordinate<CDim>
const rmin = knots[
degree()];
428 ddc::Coordinate<CDim>
const rmax = knots[(breaks_end - breaks_begin) +
degree() - 1];
433 double const period = rmax - rmin;
434 for (std::size_t i = 1; i <
degree() + 1; ++i) {
440 for (std::size_t i = 1; i <
degree() + 1; ++i) {
445 ddc::init_discrete_space<knot_discrete_dimension_type>(knots);
448template <
class CDim, std::size_t D>
449template <
class DDim,
class MemorySpace>
451 Impl<DDim, MemorySpace>::
eval_basis(DSpan1D values,
ddc::Coordinate<CDim>
const& x)
const
453 assert(values.size() == D + 1);
458 assert(x - rmin() >= -length() * 1e-14);
459 assert(rmax() - x >= -length() * 1e-14);
460 assert(values.size() == degree() + 1);
463 ddc::DiscreteElement<knot_discrete_dimension_type>
const icell = find_cell_start(x);
465 assert(icell >= m_break_point_domain.front());
466 assert(icell <= m_break_point_domain.back());
467 assert(ddc::coordinate(icell) - x <= length() * 1e-14);
468 assert(x - ddc::coordinate(icell + 1) <= length() * 1e-14);
473 for (std::size_t j = 0; j <
degree(); ++j) {
474 left[j] = x -
ddc::coordinate(icell - j);
475 right[j] =
ddc::coordinate(icell + j + 1) - x;
477 for (std::size_t r = 0; r < j + 1; ++r) {
478 temp = values[r] / (right[r] + left[j - r]);
479 values[r] = saved + right[r] * temp;
480 saved = left[j - r] * temp;
482 values[j + 1] = saved;
485 return get_first_bspline_in_cell(icell);
488template <
class CDim, std::size_t D>
489template <
class DDim,
class MemorySpace>
491 Impl<DDim, MemorySpace>::
eval_deriv(DSpan1D derivs,
ddc::Coordinate<CDim>
const& x)
const
496 assert(x - rmin() >= -length() * 1e-14);
497 assert(rmax() - x >= -length() * 1e-14);
498 assert(derivs.size() == degree() + 1);
501 ddc::DiscreteElement<knot_discrete_dimension_type>
const icell = find_cell_start(x);
503 assert(icell >= m_break_point_domain.front());
504 assert(icell <= m_break_point_domain.back());
505 assert(ddc::coordinate(icell) <= x);
506 assert(ddc::coordinate(icell + 1) >= x);
511
512
513
514
518 for (std::size_t j = 0; j <
degree() - 1; ++j) {
519 left[j] = x -
ddc::coordinate(icell - j);
520 right[j] =
ddc::coordinate(icell + j + 1) - x;
522 for (std::size_t r = 0; r < j + 1; ++r) {
523 temp = derivs[r] / (right[r] + left[j - r]);
524 derivs[r] = saved + right[r] * temp;
525 saved = left[j - r] * temp;
527 derivs[j + 1] = saved;
531
532
533
535 / (
ddc::coordinate(icell + 1) -
ddc::coordinate(icell + 1 -
degree()));
537 for (std::size_t j = 1; j <
degree(); ++j) {
540 / (
ddc::coordinate(icell + j + 1) -
ddc::coordinate(icell + j + 1 -
degree()));
541 derivs[j] = temp - saved;
545 return get_first_bspline_in_cell(icell);
548template <
class CDim, std::size_t D>
549template <
class DDim,
class MemorySpace>
551 Impl<DDim, MemorySpace>::eval_basis_and_n_derivs(
552 ddc::DSpan2D
const derivs,
553 ddc::Coordinate<CDim>
const& x,
554 std::size_t
const n)
const
559 std::array<
double, 2 * (
degree() + 1)> a_ptr;
560 Kokkos::mdspan<
double, Kokkos::extents<std::size_t,
degree() + 1, 2>>
const a(a_ptr.data());
563 Kokkos::mdspan<
double, Kokkos::extents<std::size_t,
degree() + 1,
degree() + 1>>
const ndu(
566 assert(x - rmin() >= -length() * 1e-14);
567 assert(rmax() - x >= -length() * 1e-14);
569 assert(n <= degree());
570 assert(derivs.extent(0) == 1 + degree());
571 assert(derivs.extent(1) == 1 + n);
574 ddc::DiscreteElement<knot_discrete_dimension_type>
const icell = find_cell_start(x);
576 assert(icell >= m_break_point_domain.front());
577 assert(icell <= m_break_point_domain.back());
578 assert(ddc::coordinate(icell) <= x);
579 assert(ddc::coordinate(icell + 1) >= x);
591 DDC_MDSPAN_ACCESS_OP(ndu, 0, 0) = 1.0;
592 for (std::size_t j = 0; j <
degree(); ++j) {
593 left[j] = x -
ddc::coordinate(icell - j);
594 right[j] =
ddc::coordinate(icell + j + 1) - x;
596 for (std::size_t r = 0; r < j + 1; ++r) {
599 DDC_MDSPAN_ACCESS_OP(ndu, r, j + 1) = 1.0 / (right[r] + left[j - r]);
602 temp = DDC_MDSPAN_ACCESS_OP(ndu, j, r) * DDC_MDSPAN_ACCESS_OP(ndu, r, j + 1);
603 DDC_MDSPAN_ACCESS_OP(ndu, j + 1, r) = saved + right[r] * temp;
604 saved = left[j - r] * temp;
606 DDC_MDSPAN_ACCESS_OP(ndu, j + 1, j + 1) = saved;
609 for (std::size_t j = 0; j <
degree() + 1; ++j) {
610 DDC_MDSPAN_ACCESS_OP(derivs, j, 0) = DDC_MDSPAN_ACCESS_OP(ndu, degree(), j);
613 for (
int r = 0; r <
int(
degree() + 1); ++r) {
616 DDC_MDSPAN_ACCESS_OP(a, 0, 0) = 1.0;
617 for (
int k = 1; k <
int(n + 1); ++k) {
619 int const rk = r - k;
622 DDC_MDSPAN_ACCESS_OP(a, 0, s2)
623 = DDC_MDSPAN_ACCESS_OP(a, 0, s1) * DDC_MDSPAN_ACCESS_OP(ndu, rk, pk + 1);
624 d = DDC_MDSPAN_ACCESS_OP(a, 0, s2) * DDC_MDSPAN_ACCESS_OP(ndu, pk, rk);
626 int const j1 = rk > -1 ? 1 : (-rk);
627 int const j2 = (r - 1) <= pk ? k : (
degree() - r + 1);
628 for (
int j = j1; j < j2; ++j) {
629 DDC_MDSPAN_ACCESS_OP(a, j, s2)
630 = (DDC_MDSPAN_ACCESS_OP(a, j, s1) - DDC_MDSPAN_ACCESS_OP(a, j - 1, s1))
631 * DDC_MDSPAN_ACCESS_OP(ndu, rk + j, pk + 1);
632 d += DDC_MDSPAN_ACCESS_OP(a, j, s2) * DDC_MDSPAN_ACCESS_OP(ndu, pk, rk + j);
635 DDC_MDSPAN_ACCESS_OP(a, k, s2) = -DDC_MDSPAN_ACCESS_OP(a, k - 1, s1)
636 * DDC_MDSPAN_ACCESS_OP(ndu, r, pk + 1);
637 d += DDC_MDSPAN_ACCESS_OP(a, k, s2) * DDC_MDSPAN_ACCESS_OP(ndu, pk, r);
639 DDC_MDSPAN_ACCESS_OP(derivs, r, k) = d;
640 Kokkos::kokkos_swap(s1, s2);
645 for (
int k = 1; k <
int(n + 1); ++k) {
646 for (std::size_t i = 0; i < derivs.extent(0); ++i) {
647 DDC_MDSPAN_ACCESS_OP(derivs, i, k) *= r;
652 return get_first_bspline_in_cell(icell);
655template <
class CDim, std::size_t D>
656template <
class DDim,
class MemorySpace>
659 D>::
Impl<DDim, MemorySpace>::find_cell_start(
ddc::Coordinate<CDim>
const& x)
const
661 assert(x - rmin() >= -length() * 1e-14);
662 assert(rmax() - x >= -length() * 1e-14);
665 return m_break_point_domain.front();
668 return m_break_point_domain.back() - 1;
672 ddc::DiscreteElement<knot_discrete_dimension_type> low = m_break_point_domain.front();
673 ddc::DiscreteElement<knot_discrete_dimension_type> high = m_break_point_domain.back();
674 ddc::DiscreteElement<knot_discrete_dimension_type> icell = low + (high - low) / 2;
675 while (x <
ddc::coordinate(icell) || x >=
ddc::coordinate(icell + 1)) {
676 if (x <
ddc::coordinate(icell)) {
681 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.