15#include <Kokkos_Core.hpp>
23struct UniformBSplinesBase
27template <
class ExecSpace,
class ODDim,
class Layout,
class OMemorySpace>
28void uniform_bsplines_integrals(
29 ExecSpace
const& execution_space,
40
41
42
43
44
45
46
47
48template <
class CDim, std::size_t D>
51 static_assert(D > 0,
"Parameter `D` must be positive");
55 using continuous_dimension_type = CDim;
61
62
63
64 static constexpr std::size_t
degree()
noexcept
70
71
72
75 return CDim::PERIODIC;
79
80
81
88
89
90
91
92 template <
class DDim,
class MemorySpace>
95 template <
class ODDim,
class OMemorySpace>
98 template <
class ExecSpace,
class ODDim,
class Layout,
class OMemorySpace>
99 friend void detail::uniform_bsplines_integrals(
100 ExecSpace
const& execution_space,
114 using discrete_element_type = DiscreteElement<DDim>;
124 ddc::DiscreteElement<DDim> m_reference;
130
131
132
133
134
135 explicit Impl(
ddc::Coordinate<CDim> rmin,
ddc::Coordinate<CDim> rmax, std::size_t ncells)
136 : m_reference(
ddc::create_reference_discrete_element<DDim>())
139 std::tie(m_break_point_domain, m_knot_domain, std::ignore, std::ignore)
140 =
ddc::init_discrete_space<knot_discrete_dimension_type>(
141 knot_discrete_dimension_type::
template init_ghosted<
142 knot_discrete_dimension_type>(
151
152
153
154 template <
class OriginMemorySpace>
155 explicit Impl(
Impl<DDim, OriginMemorySpace>
const& impl)
156 : m_knot_domain(impl.m_knot_domain)
157 , m_break_point_domain(impl.m_break_point_domain)
158 , m_reference(impl.m_reference)
163
164
165
169
170
171
178
179
180
181
185
186
187
188
192
193
194
195
196
197
198
199
200
201
202
204 eval_basis(DSpan1D values,
ddc::Coordinate<CDim>
const& x)
const
206 KOKKOS_ASSERT(values.size() == degree() + 1)
207 return eval_basis(values, x,
degree());
211
212
213
214
215
216
217
218
219
220
221
223 eval_deriv(DSpan1D derivs,
ddc::Coordinate<CDim>
const& x)
const;
226
227
228
229
230
231
232
233
234
235
236
237
240 ddc::Coordinate<CDim>
const& x,
241 std::size_t n)
const;
244
245
246
247
248
249
250
251
255 return m_knot_domain.front() + (ix - m_reference).value();
259
260
261
262
263
264
265
266
275
276
277
280 return ddc::coordinate(m_break_point_domain.front());
284
285
286
289 return ddc::coordinate(m_break_point_domain.back());
293
294
295
302
303
304
305
306
307
308
315
316
317
320 return discrete_domain_type(m_reference, discrete_vector_type(
size()));
324
325
326
330 return m_break_point_domain;
334
335
336
337
338
345
346
347
348
349
350
353 return m_break_point_domain.size() - 1;
359 return 1.0 /
ddc::step<knot_discrete_dimension_type>();
363 eval_basis(DSpan1D values,
ddc::Coordinate<CDim>
const& x, std::size_t degree)
const;
368 ddc::Coordinate<CDim>
const& x)
const;
373struct is_uniform_bsplines :
public std::is_base_of<detail::UniformBSplinesBase, DDim>::type
378
379
380
381
385template <
class CDim, std::size_t D>
386template <
class DDim,
class MemorySpace>
388 Impl<DDim, MemorySpace>::eval_basis(
390 ddc::Coordinate<CDim>
const& x,
391 [[maybe_unused]] std::size_t
const degree)
const
393 KOKKOS_ASSERT(values.size() == degree + 1)
399 get_icell_and_offset(jmin, offset, x);
405 DDC_MDSPAN_ACCESS_OP(values, 0) = 1.0;
406 for (std::size_t j = 1; j < values.size(); ++j) {
409 for (std::size_t r = 0; r < j; ++r) {
411 temp = DDC_MDSPAN_ACCESS_OP(values, r) / j;
412 DDC_MDSPAN_ACCESS_OP(values, r) = saved + xx * temp;
413 saved = (j - xx) * temp;
415 DDC_MDSPAN_ACCESS_OP(values, j) = saved;
418 return m_reference + jmin;
421template <
class CDim, std::size_t D>
422template <
class DDim,
class MemorySpace>
424 Impl<DDim, MemorySpace>::
eval_deriv(DSpan1D derivs,
ddc::Coordinate<CDim>
const& x)
const
426 KOKKOS_ASSERT(derivs.size() == degree() + 1)
432 get_icell_and_offset(jmin, offset, x);
439 DDC_MDSPAN_ACCESS_OP(derivs, 0) = 1.0 /
ddc::step<knot_discrete_dimension_type>();
440 for (std::size_t j = 1; j <
degree(); ++j) {
443 for (std::size_t r = 0; r < j; ++r) {
445 temp = DDC_MDSPAN_ACCESS_OP(derivs, r) / j;
446 DDC_MDSPAN_ACCESS_OP(derivs, r) = saved + xx * temp;
447 saved = (j - xx) * temp;
449 DDC_MDSPAN_ACCESS_OP(derivs, j) = saved;
453 double bjm1 = derivs[0];
455 DDC_MDSPAN_ACCESS_OP(derivs, 0) = -bjm1;
456 for (std::size_t j = 1; j <
degree(); ++j) {
457 bj = DDC_MDSPAN_ACCESS_OP(derivs, j);
458 DDC_MDSPAN_ACCESS_OP(derivs, j) = bjm1 - bj;
461 DDC_MDSPAN_ACCESS_OP(derivs, degree()) = bj;
463 return m_reference + jmin;
466template <
class CDim, std::size_t D>
467template <
class DDim,
class MemorySpace>
469 Impl<DDim, MemorySpace>::eval_basis_and_n_derivs(
470 ddc::DSpan2D
const derivs,
471 ddc::Coordinate<CDim>
const& x,
472 std::size_t
const n)
const
475 Kokkos::mdspan<
double, Kokkos::extents<std::size_t,
degree() + 1,
degree() + 1>>
const ndu(
477 std::array<
double, 2 * (
degree() + 1)> a_ptr;
478 Kokkos::mdspan<
double, Kokkos::extents<std::size_t,
degree() + 1, 2>>
const a(a_ptr.data());
482 KOKKOS_ASSERT(x - rmin() >= -length() * 1e-14)
483 KOKKOS_ASSERT(rmax() - x >= -length() * 1e-14)
485 KOKKOS_ASSERT(n <= degree())
486 KOKKOS_ASSERT(derivs.extent(0) == 1 + degree())
487 KOKKOS_ASSERT(derivs.extent(1) == 1 + n)
491 get_icell_and_offset(jmin, offset, x);
499 DDC_MDSPAN_ACCESS_OP(ndu, 0, 0) = 1.0;
500 for (std::size_t j = 1; j <
degree() + 1; ++j) {
503 for (std::size_t r = 0; r < j; ++r) {
505 temp = DDC_MDSPAN_ACCESS_OP(ndu, j - 1, r) / j;
506 DDC_MDSPAN_ACCESS_OP(ndu, j, r) = saved + xx * temp;
507 saved = (j - xx) * temp;
509 DDC_MDSPAN_ACCESS_OP(ndu, j, j) = saved;
511 for (std::size_t i = 0; i < ndu.extent(1); ++i) {
512 DDC_MDSPAN_ACCESS_OP(derivs, i, 0) = DDC_MDSPAN_ACCESS_OP(ndu, degree(), i);
515 for (
int r = 0; r <
static_cast<
int>(
degree() + 1); ++r) {
518 DDC_MDSPAN_ACCESS_OP(a, 0, 0) = 1.0;
519 for (
int k = 1; k <
static_cast<
int>(n + 1); ++k) {
521 int const rk = r - k;
524 DDC_MDSPAN_ACCESS_OP(a, 0, s2) = DDC_MDSPAN_ACCESS_OP(a, 0, s1) / (pk + 1);
525 d = DDC_MDSPAN_ACCESS_OP(a, 0, s2) * DDC_MDSPAN_ACCESS_OP(ndu, pk, rk);
527 int const j1 = rk > -1 ? 1 : (-rk);
528 int const j2 = (r - 1) <= pk ? k : (
degree() - r + 1);
529 for (
int j = j1; j < j2; ++j) {
530 DDC_MDSPAN_ACCESS_OP(a, j, s2)
531 = (DDC_MDSPAN_ACCESS_OP(a, j, s1) - DDC_MDSPAN_ACCESS_OP(a, j - 1, s1))
533 d += DDC_MDSPAN_ACCESS_OP(a, j, s2) * DDC_MDSPAN_ACCESS_OP(ndu, pk, rk + j);
536 DDC_MDSPAN_ACCESS_OP(a, k, s2) = -DDC_MDSPAN_ACCESS_OP(a, k - 1, s1) / (pk + 1);
537 d += DDC_MDSPAN_ACCESS_OP(a, k, s2) * DDC_MDSPAN_ACCESS_OP(ndu, pk, r);
539 DDC_MDSPAN_ACCESS_OP(derivs, r, k) = d;
540 Kokkos::kokkos_swap(s1, s2);
547 double const inv_dx = inv_step();
549 for (
int k = 1; k <
static_cast<
int>(n + 1); ++k) {
550 for (std::size_t i = 0; i < derivs.extent(0); ++i) {
551 DDC_MDSPAN_ACCESS_OP(derivs, i, k) *= d;
556 return m_reference + jmin;
559template <
class CDim, std::size_t D>
560template <
class DDim,
class MemorySpace>
561KOKKOS_INLINE_FUNCTION
void UniformBSplines<CDim, D>::
Impl<DDim, MemorySpace>::get_icell_and_offset(
564 ddc::Coordinate<CDim>
const& x)
const
566 KOKKOS_ASSERT(x - rmin() >= -length() * 1e-14)
567 KOKKOS_ASSERT(rmax() - x >= -length() * 1e-14)
569 double const inv_dx = inv_step();
577 offset = (x -
rmin()) * inv_dx;
578 icell =
static_cast<
int>(offset);
579 offset = offset - icell;
583 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.