10#include <initializer_list>
17#include <Kokkos_Core.hpp>
23struct NonUniformBSplinesBase
35
36
37
38
39
40
41
42
43template <
class CDim, std::size_t D,
bool Periodic = CDim::PERIODIC>
46 static_assert(D > 0,
"Parameter `D` must be positive");
50 using continuous_dimension_type = CDim;
56
57
58
59 static constexpr std::size_t
degree()
noexcept
65
66
67
74
75
76
83
84
85
86
87 template <
class DDim,
class MemorySpace>
90 template <
class ODDim,
class OMemorySpace>
104 using discrete_element_type = DiscreteElement<DDim>;
113 ddc::DiscreteElement<DDim> m_reference;
119
120
121
122
123
124
125 Impl(std::initializer_list<
ddc::Coordinate<CDim>> breaks)
126 :
Impl(breaks.begin(), breaks.end())
131
132
133
134
135
136
137 explicit Impl(std::vector<
ddc::Coordinate<CDim>>
const& breaks)
138 :
Impl(breaks.begin(), breaks.end())
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160 template <
class RandomIt>
161 Impl(RandomIt breaks_begin, RandomIt breaks_end);
164
165
166
167 template <
class OriginMemorySpace>
168 explicit Impl(
Impl<DDim, OriginMemorySpace>
const& impl)
169 : m_knot_domain(impl.m_knot_domain)
170 , m_break_point_domain(impl.m_break_point_domain)
171 , m_reference(impl.m_reference)
176
177
178
182
183
184
191
192
193
194
198
199
200
201
205
206
207
208
209
210
211
212
213
214
215
216 KOKKOS_INLINE_FUNCTION discrete_element_type
eval_basis(
217 Kokkos::mdspan<
double, Kokkos::dextents<std::size_t, 1>> values,
218 ddc::Coordinate<CDim>
const& x)
const;
221
222
223
224
225
226
227
228
229
230
231
232 KOKKOS_INLINE_FUNCTION discrete_element_type
eval_deriv(
233 Kokkos::mdspan<
double, Kokkos::dextents<std::size_t, 1>> derivs,
234 ddc::Coordinate<CDim>
const& x)
const;
237
238
239
240
241
242
243
244
245
246
247
248
250 Kokkos::mdspan<
double, Kokkos::dextents<std::size_t, 2>> derivs,
251 ddc::Coordinate<CDim>
const& x,
252 std::size_t n)
const;
255
256
257
258
259
260
261
262
263 KOKKOS_INLINE_FUNCTION
ddc::DiscreteElement<knot_discrete_dimension_type>
266 return m_knot_domain.front() + (ix - m_reference).value();
270
271
272
273
274
275
276
277
278 KOKKOS_INLINE_FUNCTION
ddc::DiscreteElement<knot_discrete_dimension_type>
286
287
288
289 KOKKOS_INLINE_FUNCTION
ddc::Coordinate<CDim>
rmin()
const noexcept
291 return ddc::coordinate(m_break_point_domain.front());
295
296
297
298 KOKKOS_INLINE_FUNCTION
ddc::Coordinate<CDim>
rmax()
const noexcept
300 return ddc::coordinate(m_break_point_domain.back());
304
305
306
307 KOKKOS_INLINE_FUNCTION Real
length()
const noexcept
313
314
315
316
317
318
319
320 KOKKOS_INLINE_FUNCTION std::size_t
size()
const noexcept
326
327
328
329 KOKKOS_INLINE_FUNCTION discrete_domain_type
full_domain()
const
331 return discrete_domain_type(m_reference, discrete_vector_type(
size()));
335
336
337
341 return m_break_point_domain;
345
346
347
348
349
350 KOKKOS_INLINE_FUNCTION std::size_t
npoints()
const noexcept
352 return m_knot_domain.size() - 2 *
degree();
356
357
358
359
360
361 KOKKOS_INLINE_FUNCTION std::size_t
nbasis()
const noexcept
367
368
369
370
371
372
373 KOKKOS_INLINE_FUNCTION std::size_t
ncells()
const noexcept
379 KOKKOS_INLINE_FUNCTION discrete_element_type get_first_bspline_in_cell(
380 ddc::DiscreteElement<knot_discrete_dimension_type>
const& ic)
const
382 return m_reference + (ic - m_break_point_domain.front()).value();
386
387
388
389
390 KOKKOS_INLINE_FUNCTION
ddc::DiscreteElement<knot_discrete_dimension_type> find_cell_start(
391 ddc::Coordinate<CDim>
const& x)
const;
401
402
403
404
411concept non_uniform_bsplines = is_non_uniform_bsplines_v<DDim>;
417template <
class RandomIt>
419 RandomIt
const breaks_begin,
420 RandomIt
const breaks_end)
422 ddc::DiscreteElement<knot_discrete_dimension_type>(0),
424 (breaks_end - breaks_begin)
426 , m_break_point_domain(
427 ddc::DiscreteElement<knot_discrete_dimension_type>(
degree()),
429 (breaks_end - breaks_begin)))
430 , m_reference(
ddc::create_reference_discrete_element<DDim>())
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 Real
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,
bool Periodic>
461template <
class DDim,
class MemorySpace>
464 Kokkos::mdspan<
double, Kokkos::dextents<std::size_t, 1>> values,
465 ddc::Coordinate<CDim>
const& x)
const
467 KOKKOS_ASSERT(values.size() == D + 1)
472 KOKKOS_ASSERT(x -
rmin() >= -
length() * 100 * std::numeric_limits<Real>::epsilon())
473 KOKKOS_ASSERT(
rmax() - x >= -
length() * 100 * std::numeric_limits<Real>::epsilon())
474 KOKKOS_ASSERT(values.size() ==
degree() + 1)
477 ddc::DiscreteElement<knot_discrete_dimension_type>
const icell = find_cell_start(x);
479 KOKKOS_ASSERT(icell >= m_break_point_domain.front())
480 KOKKOS_ASSERT(icell <= m_break_point_domain.back())
482 ddc::coordinate(icell) - x <=
length() * 100 * std::numeric_limits<Real>::epsilon())
484 x -
ddc::coordinate(icell + 1) <=
length() * 100 * std::numeric_limits<Real>::epsilon())
489 for (std::size_t j = 0; j <
degree(); ++j) {
490 left[j] = x -
ddc::coordinate(icell - j);
491 right[j] =
ddc::coordinate(icell + j + 1) - x;
493 for (std::size_t r = 0; r < j + 1; ++r) {
494 temp = values[r] / (right[r] + left[j - r]);
495 values[r] = saved + right[r] * temp;
496 saved = left[j - r] * temp;
498 values[j + 1] = saved;
501 return get_first_bspline_in_cell(icell);
504template <
class CDim, std::size_t D,
bool Periodic>
505template <
class DDim,
class MemorySpace>
508 Kokkos::mdspan<
double, Kokkos::dextents<std::size_t, 1>> derivs,
509 ddc::Coordinate<CDim>
const& x)
const
514 KOKKOS_ASSERT(x -
rmin() >= -
length() * 100 * std::numeric_limits<Real>::epsilon())
515 KOKKOS_ASSERT(
rmax() - x >= -
length() * 100 * std::numeric_limits<Real>::epsilon())
516 KOKKOS_ASSERT(derivs.size() ==
degree() + 1)
519 ddc::DiscreteElement<knot_discrete_dimension_type>
const icell = find_cell_start(x);
521 KOKKOS_ASSERT(icell >= m_break_point_domain.front())
522 KOKKOS_ASSERT(icell <= m_break_point_domain.back())
524 ddc::coordinate(icell) - x <=
length() * 100 * std::numeric_limits<Real>::epsilon())
526 x -
ddc::coordinate(icell + 1) <=
length() * 100 * std::numeric_limits<Real>::epsilon())
531
532
533
534
538 for (std::size_t j = 0; j <
degree() - 1; ++j) {
539 left[j] = x -
ddc::coordinate(icell - j);
540 right[j] =
ddc::coordinate(icell + j + 1) - x;
542 for (std::size_t r = 0; r < j + 1; ++r) {
543 temp = derivs[r] / (right[r] + left[j - r]);
544 derivs[r] = saved + right[r] * temp;
545 saved = left[j - r] * temp;
547 derivs[j + 1] = saved;
551
552
553
555 / (
ddc::coordinate(icell + 1) -
ddc::coordinate(icell + 1 -
degree()));
557 for (std::size_t j = 1; j <
degree(); ++j) {
560 / (
ddc::coordinate(icell + j + 1) -
ddc::coordinate(icell + j + 1 -
degree()));
561 derivs[j] = temp - saved;
565 return get_first_bspline_in_cell(icell);
568template <
class CDim, std::size_t D,
bool Periodic>
569template <
class DDim,
class MemorySpace>
571 Impl<DDim, MemorySpace>::eval_basis_and_n_derivs(
572 Kokkos::mdspan<
double, Kokkos::dextents<std::size_t, 2>>
const derivs,
573 ddc::Coordinate<CDim>
const& x,
574 std::size_t
const n)
const
579 std::array<Real, 2 * (
degree() + 1)> a_ptr;
580 Kokkos::mdspan<Real, Kokkos::extents<std::size_t,
degree() + 1, 2>>
const a(a_ptr.data());
583 Kokkos::mdspan<Real, Kokkos::extents<std::size_t,
degree() + 1,
degree() + 1>>
const ndu(
586 KOKKOS_ASSERT(x -
rmin() >= -
length() * 100 * std::numeric_limits<Real>::epsilon())
587 KOKKOS_ASSERT(
rmax() - x >= -
length() * 100 * std::numeric_limits<Real>::epsilon())
590 KOKKOS_ASSERT(derivs.extent(0) == 1 +
degree())
591 KOKKOS_ASSERT(derivs.extent(1) == 1 + n)
594 ddc::DiscreteElement<knot_discrete_dimension_type>
const icell = find_cell_start(x);
596 KOKKOS_ASSERT(icell >= m_break_point_domain.front())
597 KOKKOS_ASSERT(icell <= m_break_point_domain.back())
599 ddc::coordinate(icell) - x <=
length() * 100 * std::numeric_limits<Real>::epsilon())
601 x -
ddc::coordinate(icell + 1) <=
length() * 100 * std::numeric_limits<Real>::epsilon())
613 DDC_MDSPAN_ACCESS_OP(ndu, 0, 0) = 1.0;
614 for (std::size_t j = 0; j <
degree(); ++j) {
615 left[j] = x -
ddc::coordinate(icell - j);
616 right[j] =
ddc::coordinate(icell + j + 1) - x;
618 for (std::size_t r = 0; r < j + 1; ++r) {
621 DDC_MDSPAN_ACCESS_OP(ndu, r, j + 1) = 1.0 / (right[r] + left[j - r]);
624 temp = DDC_MDSPAN_ACCESS_OP(ndu, j, r) * DDC_MDSPAN_ACCESS_OP(ndu, r, j + 1);
625 DDC_MDSPAN_ACCESS_OP(ndu, j + 1, r) = saved + right[r] * temp;
626 saved = left[j - r] * temp;
628 DDC_MDSPAN_ACCESS_OP(ndu, j + 1, j + 1) = saved;
631 for (std::size_t j = 0; j <
degree() + 1; ++j) {
632 DDC_MDSPAN_ACCESS_OP(derivs, j, 0) = DDC_MDSPAN_ACCESS_OP(ndu,
degree(), j);
635 for (
int r = 0; r <
static_cast<
int>(
degree() + 1); ++r) {
638 DDC_MDSPAN_ACCESS_OP(a, 0, 0) = 1.0;
639 for (
int k = 1; k <
static_cast<
int>(n + 1); ++k) {
641 int const rk = r - k;
644 DDC_MDSPAN_ACCESS_OP(a, 0, s2)
645 = DDC_MDSPAN_ACCESS_OP(a, 0, s1) * DDC_MDSPAN_ACCESS_OP(ndu, rk, pk + 1);
646 d = DDC_MDSPAN_ACCESS_OP(a, 0, s2) * DDC_MDSPAN_ACCESS_OP(ndu, pk, rk);
648 int const j1 = rk > -1 ? 1 : (-rk);
649 int const j2 = (r - 1) <= pk ? k : (
degree() - r + 1);
650 for (
int j = j1; j < j2; ++j) {
651 DDC_MDSPAN_ACCESS_OP(a, j, s2)
652 = (DDC_MDSPAN_ACCESS_OP(a, j, s1) - DDC_MDSPAN_ACCESS_OP(a, j - 1, s1))
653 * DDC_MDSPAN_ACCESS_OP(ndu, rk + j, pk + 1);
654 d += DDC_MDSPAN_ACCESS_OP(a, j, s2) * DDC_MDSPAN_ACCESS_OP(ndu, pk, rk + j);
657 DDC_MDSPAN_ACCESS_OP(a, k, s2) = -DDC_MDSPAN_ACCESS_OP(a, k - 1, s1)
658 * DDC_MDSPAN_ACCESS_OP(ndu, r, pk + 1);
659 d += DDC_MDSPAN_ACCESS_OP(a, k, s2) * DDC_MDSPAN_ACCESS_OP(ndu, pk, r);
661 DDC_MDSPAN_ACCESS_OP(derivs, r, k) = d;
662 Kokkos::kokkos_swap(s1, s2);
667 for (
int k = 1; k <
static_cast<
int>(n + 1); ++k) {
668 for (std::size_t i = 0; i < derivs.extent(0); ++i) {
669 DDC_MDSPAN_ACCESS_OP(derivs, i, k) *= r;
674 return get_first_bspline_in_cell(icell);
677template <
class CDim, std::size_t D,
bool Periodic>
678template <
class DDim,
class MemorySpace>
682 Periodic>::
Impl<DDim, MemorySpace>::find_cell_start(
ddc::Coordinate<CDim>
const& x)
const
684 KOKKOS_ASSERT(x -
rmin() >= -
length() * 100 * std::numeric_limits<Real>::epsilon())
685 KOKKOS_ASSERT(
rmax() - x >= -
length() * 100 * std::numeric_limits<Real>::epsilon())
688 return m_break_point_domain.front();
691 return m_break_point_domain.back() - 1;
695 ddc::DiscreteElement<knot_discrete_dimension_type> low = m_break_point_domain.front();
696 ddc::DiscreteElement<knot_discrete_dimension_type> high = m_break_point_domain.back();
697 ddc::DiscreteElement<knot_discrete_dimension_type> icell = low + (high - low) / 2;
698 while (x <
ddc::coordinate(icell) || x >=
ddc::coordinate(icell + 1)) {
699 if (x <
ddc::coordinate(icell)) {
704 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.