14#include "math_tools.hpp"
21struct UniformBSplinesBase
25template <
class ExecSpace,
class ODDim,
class Layout,
class OMemorySpace>
26void uniform_bsplines_integrals(
27 ExecSpace
const& execution_space,
38
39
40
41
42
43
44
45
46template <
class CDim, std::size_t D>
49 static_assert(D > 0,
"Parameter `D` must be positive");
53 using continuous_dimension_type = CDim;
59
60
61
62 static constexpr std::size_t
degree()
noexcept
68
69
70
73 return CDim::PERIODIC;
77
78
79
86
87
88
89
90 template <
class DDim,
class MemorySpace>
93 template <
class ODDim,
class OMemorySpace>
96 template <
class ExecSpace,
class ODDim,
class Layout,
class OMemorySpace>
97 friend void detail::uniform_bsplines_integrals(
98 ExecSpace
const& execution_space,
112 using discrete_element_type = DiscreteElement<DDim>;
122 ddc::DiscreteElement<DDim> m_reference;
128
129
130
131
132
133 explicit Impl(
ddc::Coordinate<CDim> rmin,
ddc::Coordinate<CDim> rmax, std::size_t ncells)
134 : m_reference(
ddc::create_reference_discrete_element<DDim>())
137 std::tie(m_break_point_domain, m_knot_domain, std::ignore, std::ignore)
138 =
ddc::init_discrete_space<knot_discrete_dimension_type>(
139 knot_discrete_dimension_type::
template init_ghosted<
140 knot_discrete_dimension_type>(
149
150
151
152 template <
class OriginMemorySpace>
153 explicit Impl(
Impl<DDim, OriginMemorySpace>
const& impl)
154 : m_knot_domain(impl.m_knot_domain)
155 , m_break_point_domain(impl.m_break_point_domain)
156 , m_reference(impl.m_reference)
161
162
163
167
168
169
176
177
178
179
183
184
185
186
190
191
192
193
194
195
196
197
198
199
200
202 eval_basis(DSpan1D values,
ddc::Coordinate<CDim>
const& x)
const
204 assert(values.size() == degree() + 1);
205 return eval_basis(values, x,
degree());
209
210
211
212
213
214
215
216
217
218
219
221 eval_deriv(DSpan1D derivs,
ddc::Coordinate<CDim>
const& x)
const;
224
225
226
227
228
229
230
231
232
233
234
235
238 ddc::Coordinate<CDim>
const& x,
239 std::size_t n)
const;
242
243
244
245
246
247
248
249
253 return m_knot_domain.front() + (ix - m_reference).value();
257
258
259
260
261
262
263
264
273
274
275
278 return ddc::coordinate(m_break_point_domain.front());
282
283
284
287 return ddc::coordinate(m_break_point_domain.back());
291
292
293
300
301
302
303
304
305
306
313
314
315
318 return discrete_domain_type(m_reference, discrete_vector_type(
size()));
322
323
324
328 return m_break_point_domain;
332
333
334
335
336
343
344
345
346
347
348
351 return m_break_point_domain.size() - 1;
357 return 1.0 /
ddc::step<knot_discrete_dimension_type>();
361 eval_basis(DSpan1D values,
ddc::Coordinate<CDim>
const& x, std::size_t degree)
const;
366 ddc::Coordinate<CDim>
const& x)
const;
371struct is_uniform_bsplines :
public std::is_base_of<detail::UniformBSplinesBase, DDim>::type
376
377
378
379
383template <
class CDim, std::size_t D>
384template <
class DDim,
class MemorySpace>
386 Impl<DDim, MemorySpace>::eval_basis(
388 ddc::Coordinate<CDim>
const& x,
389 [[maybe_unused]] std::size_t
const degree)
const
391 assert(values.size() == degree + 1);
397 get_icell_and_offset(jmin, offset, x);
403 DDC_MDSPAN_ACCESS_OP(values, 0) = 1.0;
404 for (std::size_t j = 1; j < values.size(); ++j) {
407 for (std::size_t r = 0; r < j; ++r) {
409 temp = DDC_MDSPAN_ACCESS_OP(values, r) / j;
410 DDC_MDSPAN_ACCESS_OP(values, r) = saved + xx * temp;
411 saved = (j - xx) * temp;
413 DDC_MDSPAN_ACCESS_OP(values, j) = saved;
416 return m_reference + jmin;
419template <
class CDim, std::size_t D>
420template <
class DDim,
class MemorySpace>
422 Impl<DDim, MemorySpace>::
eval_deriv(DSpan1D derivs,
ddc::Coordinate<CDim>
const& x)
const
424 assert(derivs.size() == degree() + 1);
430 get_icell_and_offset(jmin, offset, x);
437 DDC_MDSPAN_ACCESS_OP(derivs, 0) = 1.0 /
ddc::step<knot_discrete_dimension_type>();
438 for (std::size_t j = 1; j <
degree(); ++j) {
441 for (std::size_t r = 0; r < j; ++r) {
443 temp = DDC_MDSPAN_ACCESS_OP(derivs, r) / j;
444 DDC_MDSPAN_ACCESS_OP(derivs, r) = saved + xx * temp;
445 saved = (j - xx) * temp;
447 DDC_MDSPAN_ACCESS_OP(derivs, j) = saved;
451 double bjm1 = derivs[0];
453 DDC_MDSPAN_ACCESS_OP(derivs, 0) = -bjm1;
454 for (std::size_t j = 1; j <
degree(); ++j) {
455 bj = DDC_MDSPAN_ACCESS_OP(derivs, j);
456 DDC_MDSPAN_ACCESS_OP(derivs, j) = bjm1 - bj;
459 DDC_MDSPAN_ACCESS_OP(derivs, degree()) = bj;
461 return m_reference + jmin;
464template <
class CDim, std::size_t D>
465template <
class DDim,
class MemorySpace>
467 Impl<DDim, MemorySpace>::eval_basis_and_n_derivs(
468 ddc::DSpan2D
const derivs,
469 ddc::Coordinate<CDim>
const& x,
470 std::size_t
const n)
const
473 Kokkos::mdspan<
double, Kokkos::extents<std::size_t,
degree() + 1,
degree() + 1>>
const ndu(
475 std::array<
double, 2 * (
degree() + 1)> a_ptr;
476 Kokkos::mdspan<
double, Kokkos::extents<std::size_t,
degree() + 1, 2>>
const a(a_ptr.data());
480 assert(x - rmin() >= -length() * 1e-14);
481 assert(rmax() - x >= -length() * 1e-14);
483 assert(n <= degree());
484 assert(derivs.extent(0) == 1 + degree());
485 assert(derivs.extent(1) == 1 + n);
489 get_icell_and_offset(jmin, offset, x);
497 DDC_MDSPAN_ACCESS_OP(ndu, 0, 0) = 1.0;
498 for (std::size_t j = 1; j <
degree() + 1; ++j) {
501 for (std::size_t r = 0; r < j; ++r) {
503 temp = DDC_MDSPAN_ACCESS_OP(ndu, j - 1, r) / j;
504 DDC_MDSPAN_ACCESS_OP(ndu, j, r) = saved + xx * temp;
505 saved = (j - xx) * temp;
507 DDC_MDSPAN_ACCESS_OP(ndu, j, j) = saved;
509 for (std::size_t i = 0; i < ndu.extent(1); ++i) {
510 DDC_MDSPAN_ACCESS_OP(derivs, i, 0) = DDC_MDSPAN_ACCESS_OP(ndu, degree(), i);
513 for (
int r = 0; r <
int(
degree() + 1); ++r) {
516 DDC_MDSPAN_ACCESS_OP(a, 0, 0) = 1.0;
517 for (
int k = 1; k <
int(n + 1); ++k) {
519 int const rk = r - k;
522 DDC_MDSPAN_ACCESS_OP(a, 0, s2) = DDC_MDSPAN_ACCESS_OP(a, 0, s1) / (pk + 1);
523 d = DDC_MDSPAN_ACCESS_OP(a, 0, s2) * DDC_MDSPAN_ACCESS_OP(ndu, pk, rk);
525 int const j1 = rk > -1 ? 1 : (-rk);
526 int const j2 = (r - 1) <= pk ? k : (
degree() - r + 1);
527 for (
int j = j1; j < j2; ++j) {
528 DDC_MDSPAN_ACCESS_OP(a, j, s2)
529 = (DDC_MDSPAN_ACCESS_OP(a, j, s1) - DDC_MDSPAN_ACCESS_OP(a, j - 1, s1))
531 d += DDC_MDSPAN_ACCESS_OP(a, j, s2) * DDC_MDSPAN_ACCESS_OP(ndu, pk, rk + j);
534 DDC_MDSPAN_ACCESS_OP(a, k, s2) = -DDC_MDSPAN_ACCESS_OP(a, k - 1, s1) / (pk + 1);
535 d += DDC_MDSPAN_ACCESS_OP(a, k, s2) * DDC_MDSPAN_ACCESS_OP(ndu, pk, r);
537 DDC_MDSPAN_ACCESS_OP(derivs, r, k) = d;
538 Kokkos::kokkos_swap(s1, s2);
545 double const inv_dx = inv_step();
547 for (
int k = 1; k <
int(n + 1); ++k) {
548 for (std::size_t i = 0; i < derivs.extent(0); ++i) {
549 DDC_MDSPAN_ACCESS_OP(derivs, i, k) *= d;
554 return m_reference + jmin;
557template <
class CDim, std::size_t D>
558template <
class DDim,
class MemorySpace>
559KOKKOS_INLINE_FUNCTION
void UniformBSplines<CDim, D>::
Impl<DDim, MemorySpace>::get_icell_and_offset(
562 ddc::Coordinate<CDim>
const& x)
const
564 assert(x - rmin() >= -length() * 1e-14);
565 assert(rmax() - x >= -length() * 1e-14);
567 double const inv_dx = inv_step();
575 offset = (x -
rmin()) * inv_dx;
576 icell =
static_cast<
int>(offset);
577 offset = offset - icell;
581 if (icell ==
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.