18#include <Kokkos_Core.hpp>
24struct UniformBSplinesBase
28template <
class ExecSpace,
class ODDim,
class Layout,
class OMemorySpace>
29void uniform_bsplines_integrals(
30 ExecSpace
const& execution_space,
41
42
43
44
45
46
47
48
49template <
class CDim, std::size_t D,
bool Periodic>
51 : detail::UniformBSplinesBase
54 static_assert(D > 0,
"Parameter `D` must be positive");
58 using continuous_dimension_type = CDim;
64
65
66
67 static constexpr std::size_t
degree()
noexcept
73
74
75
82
83
84
91
92
93
94
95 template <
class DDim,
class MemorySpace>
98 template <
class ODDim,
class OMemorySpace>
101 template <
class ExecSpace,
class ODDim,
class Layout,
class OMemorySpace>
102 friend void detail::uniform_bsplines_integrals(
103 ExecSpace
const& execution_space,
117 using discrete_element_type = DiscreteElement<DDim>;
127 ddc::DiscreteElement<DDim> m_reference;
133
134
135
136
137
138 explicit Impl(
ddc::Coordinate<CDim> rmin,
ddc::Coordinate<CDim> rmax, std::size_t ncells)
139 : m_reference(
ddc::create_reference_discrete_element<DDim>())
142 std::tie(m_break_point_domain, m_knot_domain, std::ignore, std::ignore)
143 =
ddc::init_discrete_space<knot_discrete_dimension_type>(
144 knot_discrete_dimension_type::
template init_ghosted<
145 knot_discrete_dimension_type>(
154
155
156
157 template <
class OriginMemorySpace>
158 explicit Impl(
Impl<DDim, OriginMemorySpace>
const& impl)
159 : m_knot_domain(impl.m_knot_domain)
160 , m_break_point_domain(impl.m_break_point_domain)
161 , m_reference(impl.m_reference)
166
167
168
172
173
174
181
182
183
184
188
189
190
191
195
196
197
198
199
200
201
202
203
204
205
206 KOKKOS_INLINE_FUNCTION discrete_element_type
eval_basis(
207 Kokkos::mdspan<
double, Kokkos::dextents<std::size_t, 1>> values,
208 ddc::Coordinate<CDim>
const& x)
const
210 KOKKOS_ASSERT(values.size() ==
degree() + 1)
211 return eval_basis(values, x,
degree());
215
216
217
218
219
220
221
222
223
224
225
226 KOKKOS_INLINE_FUNCTION discrete_element_type
eval_deriv(
227 Kokkos::mdspan<
double, Kokkos::dextents<std::size_t, 1>> derivs,
228 ddc::Coordinate<CDim>
const& x)
const;
231
232
233
234
235
236
237
238
239
240
241
242
244 Kokkos::mdspan<
double, Kokkos::dextents<std::size_t, 2>> derivs,
245 ddc::Coordinate<CDim>
const& x,
246 std::size_t n)
const;
249
250
251
252
253
254
255
256
257 KOKKOS_INLINE_FUNCTION
ddc::DiscreteElement<knot_discrete_dimension_type>
260 return m_knot_domain.front() + (ix - m_reference).value();
264
265
266
267
268
269
270
271
272 KOKKOS_INLINE_FUNCTION
ddc::DiscreteElement<knot_discrete_dimension_type>
280
281
282
283 KOKKOS_INLINE_FUNCTION
ddc::Coordinate<CDim>
rmin()
const noexcept
285 return ddc::coordinate(m_break_point_domain.front());
289
290
291
292 KOKKOS_INLINE_FUNCTION
ddc::Coordinate<CDim>
rmax()
const noexcept
294 return ddc::coordinate(m_break_point_domain.back());
298
299
300
301 KOKKOS_INLINE_FUNCTION Real
length()
const noexcept
307
308
309
310
311
312
313
314 KOKKOS_INLINE_FUNCTION std::size_t
size()
const noexcept
320
321
322
323 KOKKOS_INLINE_FUNCTION discrete_domain_type
full_domain()
const
325 return discrete_domain_type(m_reference, discrete_vector_type(
size()));
329
330
331
335 return m_break_point_domain;
339
340
341
342
343
344 KOKKOS_INLINE_FUNCTION std::size_t
nbasis()
const noexcept
350
351
352
353
354
355
356 KOKKOS_INLINE_FUNCTION std::size_t
ncells()
const noexcept
358 return m_break_point_domain.size() - 1;
362 KOKKOS_INLINE_FUNCTION Real inv_step()
const noexcept
364 return 1.0 /
ddc::step<knot_discrete_dimension_type>();
367 KOKKOS_INLINE_FUNCTION discrete_element_type eval_basis(
368 Kokkos::mdspan<
double, Kokkos::dextents<std::size_t, 1>> values,
369 ddc::Coordinate<CDim>
const& x,
370 std::size_t degree)
const;
372 KOKKOS_INLINE_FUNCTION
void get_icell_and_offset(
375 ddc::Coordinate<CDim>
const& x)
const;
385
386
387
388
395concept uniform_bsplines = discrete_dimension<T> && is_uniform_bsplines_v<T>;
399template <
class CDim, std::size_t D,
bool Periodic>
400template <
class DDim,
class MemorySpace>
402 Impl<DDim, MemorySpace>::eval_basis(
403 Kokkos::mdspan<
double, Kokkos::dextents<std::size_t, 1>> values,
404 ddc::Coordinate<CDim>
const& x,
405 [[maybe_unused]] std::size_t
const degree)
const
407 KOKKOS_ASSERT(values.size() == degree + 1)
413 get_icell_and_offset(jmin, offset, x);
419 DDC_MDSPAN_ACCESS_OP(values, 0) = 1.0;
420 for (std::size_t j = 1; j < values.size(); ++j) {
423 for (std::size_t r = 0; r < j; ++r) {
425 temp = DDC_MDSPAN_ACCESS_OP(values, r) / j;
426 DDC_MDSPAN_ACCESS_OP(values, r) = saved + xx * temp;
427 saved = (j - xx) * temp;
429 DDC_MDSPAN_ACCESS_OP(values, j) = saved;
432 return m_reference + jmin;
435template <
class CDim, std::size_t D,
bool Periodic>
436template <
class DDim,
class MemorySpace>
439 Kokkos::mdspan<
double, Kokkos::dextents<std::size_t, 1>> derivs,
440 ddc::Coordinate<CDim>
const& x)
const
442 KOKKOS_ASSERT(derivs.size() ==
degree() + 1)
448 get_icell_and_offset(jmin, offset, x);
455 DDC_MDSPAN_ACCESS_OP(derivs, 0) = 1.0 /
ddc::step<knot_discrete_dimension_type>();
456 for (std::size_t j = 1; j <
degree(); ++j) {
459 for (std::size_t r = 0; r < j; ++r) {
461 temp = DDC_MDSPAN_ACCESS_OP(derivs, r) / j;
462 DDC_MDSPAN_ACCESS_OP(derivs, r) = saved + xx * temp;
463 saved = (j - xx) * temp;
465 DDC_MDSPAN_ACCESS_OP(derivs, j) = saved;
469 Real bjm1 = derivs[0];
471 DDC_MDSPAN_ACCESS_OP(derivs, 0) = -bjm1;
472 for (std::size_t j = 1; j <
degree(); ++j) {
473 bj = DDC_MDSPAN_ACCESS_OP(derivs, j);
474 DDC_MDSPAN_ACCESS_OP(derivs, j) = bjm1 - bj;
477 DDC_MDSPAN_ACCESS_OP(derivs, degree()) = bj;
479 return m_reference + jmin;
482template <
class CDim, std::size_t D,
bool Periodic>
483template <
class DDim,
class MemorySpace>
485 Impl<DDim, MemorySpace>::eval_basis_and_n_derivs(
486 Kokkos::mdspan<
double, Kokkos::dextents<std::size_t, 2>>
const derivs,
487 ddc::Coordinate<CDim>
const& x,
488 std::size_t
const n)
const
491 Kokkos::mdspan<Real, Kokkos::extents<std::size_t,
degree() + 1,
degree() + 1>>
const ndu(
493 std::array<Real, 2 * (
degree() + 1)> a_ptr;
494 Kokkos::mdspan<Real, Kokkos::extents<std::size_t,
degree() + 1, 2>>
const a(a_ptr.data());
498 KOKKOS_ASSERT(x -
rmin() >= -
length() * 100 * std::numeric_limits<Real>::epsilon())
499 KOKKOS_ASSERT(
rmax() - x >= -
length() * 100 * std::numeric_limits<Real>::epsilon())
502 KOKKOS_ASSERT(derivs.extent(0) == 1 +
degree())
503 KOKKOS_ASSERT(derivs.extent(1) == 1 + n)
507 get_icell_and_offset(jmin, offset, x);
515 DDC_MDSPAN_ACCESS_OP(ndu, 0, 0) = 1.0;
516 for (std::size_t j = 1; j <
degree() + 1; ++j) {
519 for (std::size_t r = 0; r < j; ++r) {
521 temp = DDC_MDSPAN_ACCESS_OP(ndu, j - 1, r) / j;
522 DDC_MDSPAN_ACCESS_OP(ndu, j, r) = saved + xx * temp;
523 saved = (j - xx) * temp;
525 DDC_MDSPAN_ACCESS_OP(ndu, j, j) = saved;
527 for (std::size_t i = 0; i < ndu.extent(1); ++i) {
528 DDC_MDSPAN_ACCESS_OP(derivs, i, 0) = DDC_MDSPAN_ACCESS_OP(ndu,
degree(), i);
531 for (
int r = 0; r <
static_cast<
int>(
degree() + 1); ++r) {
534 DDC_MDSPAN_ACCESS_OP(a, 0, 0) = 1.0;
535 for (
int k = 1; k <
static_cast<
int>(n + 1); ++k) {
537 int const rk = r - k;
540 DDC_MDSPAN_ACCESS_OP(a, 0, s2) = DDC_MDSPAN_ACCESS_OP(a, 0, s1) / (pk + 1);
541 d = DDC_MDSPAN_ACCESS_OP(a, 0, s2) * DDC_MDSPAN_ACCESS_OP(ndu, pk, rk);
543 int const j1 = rk > -1 ? 1 : (-rk);
544 int const j2 = (r - 1) <= pk ? k : (
degree() - r + 1);
545 for (
int j = j1; j < j2; ++j) {
546 DDC_MDSPAN_ACCESS_OP(a, j, s2)
547 = (DDC_MDSPAN_ACCESS_OP(a, j, s1) - DDC_MDSPAN_ACCESS_OP(a, j - 1, s1))
549 d += DDC_MDSPAN_ACCESS_OP(a, j, s2) * DDC_MDSPAN_ACCESS_OP(ndu, pk, rk + j);
552 DDC_MDSPAN_ACCESS_OP(a, k, s2) = -DDC_MDSPAN_ACCESS_OP(a, k - 1, s1) / (pk + 1);
553 d += DDC_MDSPAN_ACCESS_OP(a, k, s2) * DDC_MDSPAN_ACCESS_OP(ndu, pk, r);
555 DDC_MDSPAN_ACCESS_OP(derivs, r, k) = d;
556 Kokkos::kokkos_swap(s1, s2);
563 Real
const inv_dx = inv_step();
565 for (
int k = 1; k <
static_cast<
int>(n + 1); ++k) {
566 for (std::size_t i = 0; i < derivs.extent(0); ++i) {
567 DDC_MDSPAN_ACCESS_OP(derivs, i, k) *= d;
572 return m_reference + jmin;
575template <
class CDim, std::size_t D,
bool Periodic>
576template <
class DDim,
class MemorySpace>
578 get_icell_and_offset(
int& icell, Real& offset,
ddc::Coordinate<CDim>
const& x)
const
580 KOKKOS_ASSERT(x -
rmin() >= -
length() * 100 * std::numeric_limits<Real>::epsilon())
581 KOKKOS_ASSERT(
rmax() - x >= -
length() * 100 * std::numeric_limits<Real>::epsilon())
583 Real
const inv_dx = inv_step();
591 offset = (x -
rmin()) * inv_dx;
592 icell =
static_cast<
int>(offset);
593 offset = offset - icell;
597 if (icell ==
static_cast<
int>(
ncells()) && offset == 0.0) {
friend class DiscreteDomain
KOKKOS_FUNCTION constexpr bool operator!=(DiscreteVector< OTags... > const &rhs) const noexcept
The top-level namespace of DDC.
constexpr bool is_uniform_bsplines_v
Indicates if a tag corresponds to uniform B-splines or not.
constexpr bool is_non_uniform_bsplines_v
Indicates if a tag corresponds to non-uniform B-splines or not.