13#include "math_tools.hpp"
20struct UniformBSplinesBase
24template <
class ExecSpace,
class ODDim,
class Layout,
class OMemorySpace>
25void uniform_bsplines_integrals(
26 ExecSpace
const& execution_space,
37
38
39
40
41
42
43
44
45template <
class CDim, std::size_t D>
48 static_assert(D > 0,
"Parameter `D` must be positive");
52 using continuous_dimension_type = CDim;
58
59
60
61 static constexpr std::size_t
degree()
noexcept
67
68
69
72 return CDim::PERIODIC;
76
77
78
85
86
87
88
89 template <
class DDim,
class MemorySpace>
92 template <
class ODDim,
class OMemorySpace>
95 template <
class ExecSpace,
class ODDim,
class Layout,
class OMemorySpace>
96 friend void detail::uniform_bsplines_integrals(
97 ExecSpace
const& execution_space,
111 using discrete_element_type = DiscreteElement<DDim>;
125
126
127
128
129
130 explicit Impl(
ddc::Coordinate<CDim> rmin,
ddc::Coordinate<CDim> rmax, std::size_t ncells)
135 std::tie(m_break_point_domain, m_knot_domain, pre_ghost, post_ghost)
136 =
ddc::init_discrete_space<knot_discrete_dimension_type>(
137 knot_discrete_dimension_type::
template init_ghosted<
138 knot_discrete_dimension_type>(
147
148
149
150 template <
class OriginMemorySpace>
151 explicit Impl(
Impl<DDim, OriginMemorySpace>
const& impl)
152 : m_knot_domain(impl.m_knot_domain)
153 , m_break_point_domain(impl.m_break_point_domain)
158
159
160
164
165
166
173
174
175
176
180
181
182
183
187
188
189
190
191
192
193
194
195
196
197
199 eval_basis(DSpan1D values,
ddc::Coordinate<CDim>
const& x)
const
201 assert(values.size() == degree() + 1);
202 return eval_basis(values, x,
degree());
206
207
208
209
210
211
212
213
214
215
216
218 eval_deriv(DSpan1D derivs,
ddc::Coordinate<CDim>
const& x)
const;
221
222
223
224
225
226
227
228
229
230
231
232
235 ddc::Coordinate<CDim>
const& x,
236 std::size_t n)
const;
239
240
241
242
243
244
245
246
247 template <
class Layout,
class MemorySpace2>
254
255
256
257
258
259
260
261
265 return ddc::DiscreteElement<knot_discrete_dimension_type>(
266 (ix - discrete_element_type(0)).value());
270
271
272
273
274
275
276
277
286
287
288
291 return ddc::coordinate(m_break_point_domain.front());
295
296
297
300 return ddc::coordinate(m_break_point_domain.back());
304
305
306
313
314
315
316
317
318
319
326
327
328
331 return discrete_domain_type(discrete_element_type(0), discrete_vector_type(
size()));
335
336
337
341 return m_break_point_domain;
345
346
347
348
349
356
357
358
359
360
361
364 return m_break_point_domain.size() - 1;
370 return 1.0 /
ddc::step<knot_discrete_dimension_type>();
374 eval_basis(DSpan1D values,
ddc::Coordinate<CDim>
const& x, std::size_t degree)
const;
379 ddc::Coordinate<CDim>
const& x)
const;
389
390
391
392
396template <
class CDim, std::size_t D>
397template <
class DDim,
class MemorySpace>
399 Impl<DDim, MemorySpace>::eval_basis(
401 ddc::Coordinate<CDim>
const& x,
402 [[maybe_unused]] std::size_t
const deg)
const
404 assert(values.size() == deg + 1);
410 get_icell_and_offset(jmin, offset, x);
416 DDC_MDSPAN_ACCESS_OP(values, 0) = 1.0;
417 for (std::size_t j = 1; j < values.size(); ++j) {
420 for (std::size_t r = 0; r < j; ++r) {
422 temp = DDC_MDSPAN_ACCESS_OP(values, r) / j;
423 DDC_MDSPAN_ACCESS_OP(values, r) = saved + xx * temp;
424 saved = (j - xx) * temp;
426 DDC_MDSPAN_ACCESS_OP(values, j) = saved;
429 return discrete_element_type(jmin);
432template <
class CDim, std::size_t D>
433template <
class DDim,
class MemorySpace>
435 Impl<DDim, MemorySpace>::
eval_deriv(DSpan1D derivs,
ddc::Coordinate<CDim>
const& x)
const
437 assert(derivs.size() == degree() + 1);
443 get_icell_and_offset(jmin, offset, x);
450 DDC_MDSPAN_ACCESS_OP(derivs, 0) = 1.0 /
ddc::step<knot_discrete_dimension_type>();
451 for (std::size_t j = 1; j <
degree(); ++j) {
454 for (std::size_t r = 0; r < j; ++r) {
456 temp = DDC_MDSPAN_ACCESS_OP(derivs, r) / j;
457 DDC_MDSPAN_ACCESS_OP(derivs, r) = saved + xx * temp;
458 saved = (j - xx) * temp;
460 DDC_MDSPAN_ACCESS_OP(derivs, j) = saved;
464 double bjm1 = derivs[0];
466 DDC_MDSPAN_ACCESS_OP(derivs, 0) = -bjm1;
467 for (std::size_t j = 1; j <
degree(); ++j) {
468 bj = DDC_MDSPAN_ACCESS_OP(derivs, j);
469 DDC_MDSPAN_ACCESS_OP(derivs, j) = bjm1 - bj;
472 DDC_MDSPAN_ACCESS_OP(derivs, degree()) = bj;
474 return discrete_element_type(jmin);
477template <
class CDim, std::size_t D>
478template <
class DDim,
class MemorySpace>
480 Impl<DDim, MemorySpace>::eval_basis_and_n_derivs(
481 ddc::DSpan2D
const derivs,
482 ddc::Coordinate<CDim>
const& x,
483 std::size_t
const n)
const
486 Kokkos::mdspan<
double, Kokkos::extents<std::size_t,
degree() + 1,
degree() + 1>>
const ndu(
488 std::array<
double, 2 * (
degree() + 1)> a_ptr;
489 Kokkos::mdspan<
double, Kokkos::extents<std::size_t,
degree() + 1, 2>>
const a(a_ptr.data());
493 assert(x - rmin() >= -length() * 1e-14);
494 assert(rmax() - x >= -length() * 1e-14);
496 assert(n <= degree());
497 assert(derivs.extent(0) == 1 + degree());
498 assert(derivs.extent(1) == 1 + n);
502 get_icell_and_offset(jmin, offset, x);
510 DDC_MDSPAN_ACCESS_OP(ndu, 0, 0) = 1.0;
511 for (std::size_t j = 1; j <
degree() + 1; ++j) {
514 for (std::size_t r = 0; r < j; ++r) {
516 temp = DDC_MDSPAN_ACCESS_OP(ndu, j - 1, r) / j;
517 DDC_MDSPAN_ACCESS_OP(ndu, j, r) = saved + xx * temp;
518 saved = (j - xx) * temp;
520 DDC_MDSPAN_ACCESS_OP(ndu, j, j) = saved;
522 for (std::size_t i = 0; i < ndu.extent(1); ++i) {
523 DDC_MDSPAN_ACCESS_OP(derivs, i, 0) = DDC_MDSPAN_ACCESS_OP(ndu, degree(), i);
526 for (
int r = 0; r <
int(
degree() + 1); ++r) {
529 DDC_MDSPAN_ACCESS_OP(a, 0, 0) = 1.0;
530 for (
int k = 1; k <
int(n + 1); ++k) {
532 int const rk = r - k;
535 DDC_MDSPAN_ACCESS_OP(a, 0, s2) = DDC_MDSPAN_ACCESS_OP(a, 0, s1) / (pk + 1);
536 d = DDC_MDSPAN_ACCESS_OP(a, 0, s2) * DDC_MDSPAN_ACCESS_OP(ndu, pk, rk);
538 int const j1 = rk > -1 ? 1 : (-rk);
539 int const j2 = (r - 1) <= pk ? k : (
degree() - r + 1);
540 for (
int j = j1; j < j2; ++j) {
541 DDC_MDSPAN_ACCESS_OP(a, j, s2)
542 = (DDC_MDSPAN_ACCESS_OP(a, j, s1) - DDC_MDSPAN_ACCESS_OP(a, j - 1, s1))
544 d += DDC_MDSPAN_ACCESS_OP(a, j, s2) * DDC_MDSPAN_ACCESS_OP(ndu, pk, rk + j);
547 DDC_MDSPAN_ACCESS_OP(a, k, s2) = -DDC_MDSPAN_ACCESS_OP(a, k - 1, s1) / (pk + 1);
548 d += DDC_MDSPAN_ACCESS_OP(a, k, s2) * DDC_MDSPAN_ACCESS_OP(ndu, pk, r);
550 DDC_MDSPAN_ACCESS_OP(derivs, r, k) = d;
551 Kokkos::kokkos_swap(s1, s2);
558 double const inv_dx = inv_step();
560 for (
int k = 1; k <
int(n + 1); ++k) {
561 for (std::size_t i = 0; i < derivs.extent(0); ++i) {
562 DDC_MDSPAN_ACCESS_OP(derivs, i, k) *= d;
567 return discrete_element_type(jmin);
570template <
class CDim, std::size_t D>
571template <
class DDim,
class MemorySpace>
572KOKKOS_INLINE_FUNCTION
void UniformBSplines<CDim, D>::
Impl<DDim, MemorySpace>::get_icell_and_offset(
575 ddc::Coordinate<CDim>
const& x)
const
577 assert(x - rmin() >= -length() * 1e-14);
578 assert(rmax() - x >= -length() * 1e-14);
580 double const inv_dx = inv_step();
588 offset = (x -
rmin()) * inv_dx;
589 icell =
static_cast<
int>(offset);
590 offset = offset - icell;
594 if (icell ==
int(
ncells()) && offset == 0.0) {
603template <
class Layout,
class MemorySpace2>
606 ddc::
ChunkSpan<
double, discrete_domain_type, Layout, MemorySpace2> int_vals)
const
608 assert([&]() ->
bool {
609 if constexpr (is_periodic()) {
610 return int_vals.size() == nbasis() || int_vals.size() == size();
612 return int_vals.size() == nbasis();
619 discrete_domain_type
const dom_bsplines(
620 full_dom_splines.take_first(discrete_vector_type {
nbasis()}));
621 for (
auto ix : dom_bsplines) {
622 int_vals(ix) =
ddc::step<knot_discrete_dimension_type>();
624 if (int_vals.size() ==
size()) {
625 discrete_domain_type
const dom_bsplines_repeated(
626 full_dom_splines.take_last(discrete_vector_type {
degree()}));
627 for (
auto ix : dom_bsplines_repeated) {
632 discrete_domain_type
const dom_bspline_entirely_in_domain
635 for (
auto ix : dom_bspline_entirely_in_domain) {
636 int_vals(ix) =
ddc::step<knot_discrete_dimension_type>();
639 std::array<
double,
degree() + 2> edge_vals_ptr;
640 Kokkos::mdspan<
double, Kokkos::extents<std::size_t,
degree() + 2>>
const edge_vals(
641 edge_vals_ptr.data());
645 double const d_eval =
ddc::detail::sum(edge_vals);
647 for (std::size_t i = 0; i <
degree(); ++i) {
648 double const c_eval =
ddc::detail::sum(edge_vals, 0,
degree() - i);
650 double const edge_value =
ddc::step<knot_discrete_dimension_type>() * (d_eval - c_eval);
652 int_vals(discrete_element_type(i)) = edge_value;
653 int_vals(discrete_element_type(
nbasis() - 1 - i)) = edge_value;
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.