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>;
126
127
128
129
130
131 explicit Impl(
ddc::Coordinate<CDim> rmin,
ddc::Coordinate<CDim> rmax, std::size_t ncells)
134 std::tie(m_break_point_domain, m_knot_domain, std::ignore, std::ignore)
135 =
ddc::init_discrete_space<knot_discrete_dimension_type>(
136 knot_discrete_dimension_type::
template init_ghosted<
137 knot_discrete_dimension_type>(
146
147
148
149 template <
class OriginMemorySpace>
150 explicit Impl(
Impl<DDim, OriginMemorySpace>
const& impl)
151 : m_knot_domain(impl.m_knot_domain)
152 , m_break_point_domain(impl.m_break_point_domain)
157
158
159
163
164
165
172
173
174
175
179
180
181
182
186
187
188
189
190
191
192
193
194
195
196
198 eval_basis(DSpan1D values,
ddc::Coordinate<CDim>
const& x)
const
200 assert(values.size() == degree() + 1);
201 return eval_basis(values, x,
degree());
205
206
207
208
209
210
211
212
213
214
215
217 eval_deriv(DSpan1D derivs,
ddc::Coordinate<CDim>
const& x)
const;
220
221
222
223
224
225
226
227
228
229
230
231
234 ddc::Coordinate<CDim>
const& x,
235 std::size_t n)
const;
238
239
240
241
242
243
244
245
249 return ddc::DiscreteElement<knot_discrete_dimension_type>(
250 (ix - discrete_element_type(0)).value());
254
255
256
257
258
259
260
261
270
271
272
275 return ddc::coordinate(m_break_point_domain.front());
279
280
281
284 return ddc::coordinate(m_break_point_domain.back());
288
289
290
297
298
299
300
301
302
303
310
311
312
315 return discrete_domain_type(discrete_element_type(0), discrete_vector_type(
size()));
319
320
321
325 return m_break_point_domain;
329
330
331
332
333
340
341
342
343
344
345
348 return m_break_point_domain.size() - 1;
354 return 1.0 /
ddc::step<knot_discrete_dimension_type>();
358 eval_basis(DSpan1D values,
ddc::Coordinate<CDim>
const& x, std::size_t degree)
const;
363 ddc::Coordinate<CDim>
const& x)
const;
368struct is_uniform_bsplines :
public std::is_base_of<detail::UniformBSplinesBase, DDim>::type
373
374
375
376
380template <
class CDim, std::size_t D>
381template <
class DDim,
class MemorySpace>
383 Impl<DDim, MemorySpace>::eval_basis(
385 ddc::Coordinate<CDim>
const& x,
386 [[maybe_unused]] std::size_t
const degree)
const
388 assert(values.size() == degree + 1);
394 get_icell_and_offset(jmin, offset, x);
400 DDC_MDSPAN_ACCESS_OP(values, 0) = 1.0;
401 for (std::size_t j = 1; j < values.size(); ++j) {
404 for (std::size_t r = 0; r < j; ++r) {
406 temp = DDC_MDSPAN_ACCESS_OP(values, r) / j;
407 DDC_MDSPAN_ACCESS_OP(values, r) = saved + xx * temp;
408 saved = (j - xx) * temp;
410 DDC_MDSPAN_ACCESS_OP(values, j) = saved;
413 return discrete_element_type(jmin);
416template <
class CDim, std::size_t D>
417template <
class DDim,
class MemorySpace>
419 Impl<DDim, MemorySpace>::
eval_deriv(DSpan1D derivs,
ddc::Coordinate<CDim>
const& x)
const
421 assert(derivs.size() == degree() + 1);
427 get_icell_and_offset(jmin, offset, x);
434 DDC_MDSPAN_ACCESS_OP(derivs, 0) = 1.0 /
ddc::step<knot_discrete_dimension_type>();
435 for (std::size_t j = 1; j <
degree(); ++j) {
438 for (std::size_t r = 0; r < j; ++r) {
440 temp = DDC_MDSPAN_ACCESS_OP(derivs, r) / j;
441 DDC_MDSPAN_ACCESS_OP(derivs, r) = saved + xx * temp;
442 saved = (j - xx) * temp;
444 DDC_MDSPAN_ACCESS_OP(derivs, j) = saved;
448 double bjm1 = derivs[0];
450 DDC_MDSPAN_ACCESS_OP(derivs, 0) = -bjm1;
451 for (std::size_t j = 1; j <
degree(); ++j) {
452 bj = DDC_MDSPAN_ACCESS_OP(derivs, j);
453 DDC_MDSPAN_ACCESS_OP(derivs, j) = bjm1 - bj;
456 DDC_MDSPAN_ACCESS_OP(derivs, degree()) = bj;
458 return discrete_element_type(jmin);
461template <
class CDim, std::size_t D>
462template <
class DDim,
class MemorySpace>
464 Impl<DDim, MemorySpace>::eval_basis_and_n_derivs(
465 ddc::DSpan2D
const derivs,
466 ddc::Coordinate<CDim>
const& x,
467 std::size_t
const n)
const
470 Kokkos::mdspan<
double, Kokkos::extents<std::size_t,
degree() + 1,
degree() + 1>>
const ndu(
472 std::array<
double, 2 * (
degree() + 1)> a_ptr;
473 Kokkos::mdspan<
double, Kokkos::extents<std::size_t,
degree() + 1, 2>>
const a(a_ptr.data());
477 assert(x - rmin() >= -length() * 1e-14);
478 assert(rmax() - x >= -length() * 1e-14);
480 assert(n <= degree());
481 assert(derivs.extent(0) == 1 + degree());
482 assert(derivs.extent(1) == 1 + n);
486 get_icell_and_offset(jmin, offset, x);
494 DDC_MDSPAN_ACCESS_OP(ndu, 0, 0) = 1.0;
495 for (std::size_t j = 1; j <
degree() + 1; ++j) {
498 for (std::size_t r = 0; r < j; ++r) {
500 temp = DDC_MDSPAN_ACCESS_OP(ndu, j - 1, r) / j;
501 DDC_MDSPAN_ACCESS_OP(ndu, j, r) = saved + xx * temp;
502 saved = (j - xx) * temp;
504 DDC_MDSPAN_ACCESS_OP(ndu, j, j) = saved;
506 for (std::size_t i = 0; i < ndu.extent(1); ++i) {
507 DDC_MDSPAN_ACCESS_OP(derivs, i, 0) = DDC_MDSPAN_ACCESS_OP(ndu, degree(), i);
510 for (
int r = 0; r <
int(
degree() + 1); ++r) {
513 DDC_MDSPAN_ACCESS_OP(a, 0, 0) = 1.0;
514 for (
int k = 1; k <
int(n + 1); ++k) {
516 int const rk = r - k;
519 DDC_MDSPAN_ACCESS_OP(a, 0, s2) = DDC_MDSPAN_ACCESS_OP(a, 0, s1) / (pk + 1);
520 d = DDC_MDSPAN_ACCESS_OP(a, 0, s2) * DDC_MDSPAN_ACCESS_OP(ndu, pk, rk);
522 int const j1 = rk > -1 ? 1 : (-rk);
523 int const j2 = (r - 1) <= pk ? k : (
degree() - r + 1);
524 for (
int j = j1; j < j2; ++j) {
525 DDC_MDSPAN_ACCESS_OP(a, j, s2)
526 = (DDC_MDSPAN_ACCESS_OP(a, j, s1) - DDC_MDSPAN_ACCESS_OP(a, j - 1, s1))
528 d += DDC_MDSPAN_ACCESS_OP(a, j, s2) * DDC_MDSPAN_ACCESS_OP(ndu, pk, rk + j);
531 DDC_MDSPAN_ACCESS_OP(a, k, s2) = -DDC_MDSPAN_ACCESS_OP(a, k - 1, s1) / (pk + 1);
532 d += DDC_MDSPAN_ACCESS_OP(a, k, s2) * DDC_MDSPAN_ACCESS_OP(ndu, pk, r);
534 DDC_MDSPAN_ACCESS_OP(derivs, r, k) = d;
535 Kokkos::kokkos_swap(s1, s2);
542 double const inv_dx = inv_step();
544 for (
int k = 1; k <
int(n + 1); ++k) {
545 for (std::size_t i = 0; i < derivs.extent(0); ++i) {
546 DDC_MDSPAN_ACCESS_OP(derivs, i, k) *= d;
551 return discrete_element_type(jmin);
554template <
class CDim, std::size_t D>
555template <
class DDim,
class MemorySpace>
556KOKKOS_INLINE_FUNCTION
void UniformBSplines<CDim, D>::
Impl<DDim, MemorySpace>::get_icell_and_offset(
559 ddc::Coordinate<CDim>
const& x)
const
561 assert(x - rmin() >= -length() * 1e-14);
562 assert(rmax() - x >= -length() * 1e-14);
564 double const inv_dx = inv_step();
572 offset = (x -
rmin()) * inv_dx;
573 icell =
static_cast<
int>(offset);
574 offset = offset - icell;
578 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.