DDC 0.4.1
Loading...
Searching...
No Matches
spline_builder.hpp
1// Copyright (C) The DDC development team, see COPYRIGHT.md file
2//
3// SPDX-License-Identifier: MIT
4
5#pragma once
6
7#include <cassert>
8#include <cstddef>
9#include <memory>
10#include <optional>
11#include <stdexcept>
12#include <tuple>
13#include <utility>
14
15#include <ddc/ddc.hpp>
16
17#include <Kokkos_Core.hpp>
18
19#include "deriv.hpp"
20#include "integrals.hpp"
21#include "math_tools.hpp"
22#include "spline_boundary_conditions.hpp"
23#include "splines_linear_problem_maker.hpp"
24
25namespace ddc {
26
27/**
28 * @brief An enum determining the backend solver of a SplineBuilder or SplineBuilder2d.
29 *
30 * An enum determining the backend solver of a SplineBuilder or SplineBuilder2d.
31 */
32enum class SplineSolver {
33 GINKGO, ///< Enum member to identify the Ginkgo-based solver (iterative method)
34 LAPACK ///< Enum member to identify the LAPACK-based solver (direct method)
35};
36
37/**
38 * @brief A class for creating a spline approximation of a function.
39 *
40 * A class which contains an operator () which can be used to build a spline approximation
41 * of a function. A spline approximation is represented by coefficients stored in a Chunk
42 * of B-splines. The spline is constructed such that it respects the boundary conditions
43 * BcLower and BcUpper, and it interpolates the function at the points on the interpolation_discrete_dimension
44 * associated with interpolation_discrete_dimension_type.
45 * @tparam ExecSpace The Kokkos execution space on which the spline approximation is performed.
46 * @tparam MemorySpace The Kokkos memory space on which the data (interpolation function and splines coefficients) is stored.
47 * @tparam BSplines The discrete dimension representing the B-splines.
48 * @tparam InterpolationDDim The discrete dimension on which interpolation points are defined.
49 * @tparam BcLower The lower boundary condition.
50 * @tparam BcUpper The upper boundary condition.
51 * @tparam Solver The SplineSolver giving the backend used to perform the spline approximation.
52 * @tparam DDimX A variadic template of all the discrete dimensions forming the full space (InterpolationDDim + batched dimensions).
53 */
54template <
55 class ExecSpace,
56 class MemorySpace,
57 class BSplines,
58 class InterpolationDDim,
59 ddc::BoundCond BcLower,
60 ddc::BoundCond BcUpper,
61 SplineSolver Solver,
62 class... DDimX>
63class SplineBuilder
64{
65 static_assert(
66 (BSplines::is_periodic() && (BcLower == ddc::BoundCond::PERIODIC)
67 && (BcUpper == ddc::BoundCond::PERIODIC))
68 || (!BSplines::is_periodic() && (BcLower != ddc::BoundCond::PERIODIC)
69 && (BcUpper != ddc::BoundCond::PERIODIC)));
70
71public:
72 /// @brief The type of the Kokkos execution space used by this class.
73 using exec_space = ExecSpace;
74
75 /// @brief The type of the Kokkos memory space used by this class.
76 using memory_space = MemorySpace;
77
78 /// @brief The type of the interpolation continuous dimension (continuous dimension of interest) used by this class.
79 using continuous_dimension_type = typename InterpolationDDim::continuous_dimension_type;
80
81 /// @brief The type of the interpolation discrete dimension (discrete dimension of interest) used by this class.
82 using interpolation_discrete_dimension_type = InterpolationDDim;
83
84 /// @brief The discrete dimension representing the B-splines.
85 using bsplines_type = BSplines;
86
87 /// @brief The type of the Deriv dimension at the boundaries.
88 using deriv_type = ddc::Deriv<continuous_dimension_type>;
89
90 /// @brief The type of the domain for the 1D interpolation mesh used by this class.
91 using interpolation_domain_type = ddc::DiscreteDomain<interpolation_discrete_dimension_type>;
92
93 /// @brief The type of the whole domain representing interpolation points.
94 using batched_interpolation_domain_type = ddc::DiscreteDomain<DDimX...>;
95
96 /**
97 * @brief The type of the batch domain (obtained by removing the dimension of interest
98 * from the whole domain).
99 *
100 * Example: For batched_interpolation_domain_type = DiscreteDomain<X,Y,Z> and a dimension of interest Y,
101 * this is DiscreteDomain<X,Z>
102 */
103 using batch_domain_type = ddc::remove_dims_of_t<
104 batched_interpolation_domain_type,
105 interpolation_discrete_dimension_type>;
106
107 /**
108 * @brief The type of the whole spline domain (cartesian product of 1D spline domain
109 * and batch domain) preserving the underlying memory layout (order of dimensions).
110 *
111 * Example: For batched_interpolation_domain_type = DiscreteDomain<X,Y,Z> and a dimension of interest Y
112 * (associated to a B-splines tag BSplinesY), this is DiscreteDomain<X,BSplinesY,Z>.
113 */
114 using batched_spline_domain_type = ddc::replace_dim_of_t<
115 batched_interpolation_domain_type,
116 interpolation_discrete_dimension_type,
117 bsplines_type>;
118
119private:
120 /**
121 * @brief The type of the whole spline domain (cartesian product of the 1D spline domain
122 * and the batch domain) with 1D spline dimension being the leading dimension.
123 *
124 * Example: For batched_interpolation_domain_type = DiscreteDomain<X,Y,Z> and a dimension of interest Y
125 * (associated to a B-splines tag BSplinesY), this is DiscreteDomain<BSplinesY,X,Z>.
126 */
127 using batched_spline_tr_domain_type =
128 typename ddc::detail::convert_type_seq_to_discrete_domain_t<ddc::type_seq_merge_t<
129 ddc::detail::TypeSeq<bsplines_type>,
130 ddc::type_seq_remove_t<
131 ddc::detail::TypeSeq<DDimX...>,
132 ddc::detail::TypeSeq<interpolation_discrete_dimension_type>>>>;
133
134public:
135 /**
136 * @brief The type of the whole Deriv domain (cartesian product of 1D Deriv domain
137 * and batch domain) preserving the underlying memory layout (order of dimensions).
138 *
139 * Example: For batched_interpolation_domain_type = DiscreteDomain<X,Y,Z> and a dimension of interest Y,
140 * this is DiscreteDomain<X,Deriv<Y>,Z>
141 */
142 using batched_derivs_domain_type = ddc::replace_dim_of_t<
143 batched_interpolation_domain_type,
144 interpolation_discrete_dimension_type,
145 deriv_type>;
146
147 /// @brief Indicates if the degree of the splines is odd or even.
148 static constexpr bool s_odd = BSplines::degree() % 2;
149
150 /// @brief The number of equations defining the boundary condition at the lower bound.
151 static constexpr int s_nbc_xmin = n_boundary_equations(BcLower, BSplines::degree());
152
153 /// @brief The number of equations defining the boundary condition at the upper bound.
154 static constexpr int s_nbc_xmax = n_boundary_equations(BcUpper, BSplines::degree());
155
156 /// @brief The boundary condition implemented at the lower bound.
157 static constexpr ddc::BoundCond s_bc_xmin = BcLower;
158
159 /// @brief The boundary condition implemented at the upper bound.
160 static constexpr ddc::BoundCond s_bc_xmax = BcUpper;
161
162 /// @brief The SplineSolver giving the backend used to perform the spline approximation.
163 static constexpr SplineSolver s_spline_solver = Solver;
164
165private:
166 batched_interpolation_domain_type m_batched_interpolation_domain;
167
168 int m_offset = 0;
169
170 double m_dx; // average cell size for normalization of derivatives
171
172 // interpolator specific
173 std::unique_ptr<ddc::detail::SplinesLinearProblem<exec_space>> matrix;
174
175 /// Calculate offset so that the matrix is diagonally dominant
176 void compute_offset(interpolation_domain_type const& interpolation_domain, int& offset);
177
178public:
179 /**
180 * @brief Build a SplineBuilder acting on batched_interpolation_domain.
181 *
182 * @param batched_interpolation_domain The domain on which the interpolation points are defined.
183 *
184 * @param cols_per_chunk A parameter used by the slicer (internal to the solver) to define the size
185 * of a chunk of right-hand sides of the linear problem to be computed in parallel (chunks are treated
186 * by the linear solver one-after-the-other).
187 * This value is optional. If no value is provided then the default value is chosen by the requested solver.
188 *
189 * @param preconditioner_max_block_size A parameter used by the slicer (internal to the solver) to
190 * define the size of a block used by the Block-Jacobi preconditioner.
191 * This value is optional. If no value is provided then the default value is chosen by the requested solver.
192 *
193 * @see MatrixSparse
194 */
195 explicit SplineBuilder(
196 batched_interpolation_domain_type const& batched_interpolation_domain,
197 std::optional<std::size_t> cols_per_chunk = std::nullopt,
198 std::optional<unsigned int> preconditioner_max_block_size = std::nullopt)
199 : m_batched_interpolation_domain(batched_interpolation_domain)
200 , m_dx((ddc::discrete_space<BSplines>().rmax() - ddc::discrete_space<BSplines>().rmin())
201 / ddc::discrete_space<BSplines>().ncells())
202 {
203 static_assert(
204 ((BcLower == BoundCond::PERIODIC) == (BcUpper == BoundCond::PERIODIC)),
205 "Incompatible boundary conditions");
206 check_valid_grid();
207
208 compute_offset(interpolation_domain(), m_offset);
209
210 // Calculate block sizes
211 int lower_block_size;
212 int upper_block_size;
213 if constexpr (bsplines_type::is_uniform()) {
214 upper_block_size = compute_block_sizes_uniform(BcLower, s_nbc_xmin);
215 lower_block_size = compute_block_sizes_uniform(BcUpper, s_nbc_xmax);
216 } else {
217 upper_block_size = compute_block_sizes_non_uniform(BcLower, s_nbc_xmin);
218 lower_block_size = compute_block_sizes_non_uniform(BcUpper, s_nbc_xmax);
219 }
220 allocate_matrix(
221 lower_block_size,
222 upper_block_size,
223 cols_per_chunk,
224 preconditioner_max_block_size);
225 }
226
227 /// @brief Copy-constructor is deleted.
228 SplineBuilder(SplineBuilder const& x) = delete;
229
230 /** @brief Move-constructs.
231 *
232 * @param x An rvalue to another SplineBuilder.
233 */
234 SplineBuilder(SplineBuilder&& x) = default;
235
236 /// @brief Destructs.
237 ~SplineBuilder() = default;
238
239 /// @brief Copy-assignment is deleted.
240 SplineBuilder& operator=(SplineBuilder const& x) = delete;
241
242 /** @brief Move-assigns.
243 *
244 * @param x An rvalue to another SplineBuilder.
245 * @return A reference to this object.
246 */
247 SplineBuilder& operator=(SplineBuilder&& x) = default;
248
249 /**
250 * @brief Get the domain for the 1D interpolation mesh used by this class.
251 *
252 * This is 1D because it is defined along the dimension of interest.
253 *
254 * @return The 1D domain for the interpolation mesh.
255 */
256 interpolation_domain_type interpolation_domain() const noexcept
257 {
258 return interpolation_domain_type(m_batched_interpolation_domain);
259 }
260
261 /**
262 * @brief Get the whole domain representing interpolation points.
263 *
264 * Values of the function must be provided on this domain in order
265 * to build a spline representation of the function (cartesian product of 1D interpolation_domain and batch_domain).
266 *
267 * @return The domain for the interpolation mesh.
268 */
269 batched_interpolation_domain_type batched_interpolation_domain() const noexcept
270 {
271 return m_batched_interpolation_domain;
272 }
273
274 /**
275 * @brief Get the batch domain.
276 *
277 * Obtained by removing the dimension of interest from the whole interpolation domain.
278 *
279 * @return The batch domain.
280 */
281 batch_domain_type batch_domain() const noexcept
282 {
284 }
285
286 /**
287 * @brief Get the 1D domain on which spline coefficients are defined.
288 *
289 * The 1D spline domain corresponding to the dimension of interest.
290 *
291 * @return The 1D domain for the spline coefficients.
292 */
293 ddc::DiscreteDomain<bsplines_type> spline_domain() const noexcept
294 {
295 return ddc::discrete_space<bsplines_type>().full_domain();
296 }
297
298 /**
299 * @brief Get the whole domain on which spline coefficients are defined.
300 *
301 * Spline approximations (spline-transformed functions) are computed on this domain.
302 *
303 * @return The domain for the spline coefficients.
304 */
305 batched_spline_domain_type batched_spline_domain() const noexcept
306 {
307 return ddc::replace_dim_of<
308 interpolation_discrete_dimension_type,
310 }
311
312private:
313 /**
314 * @brief Get the whole domain on which spline coefficients are defined, with the dimension of interest being the leading dimension.
315 *
316 * This is used internally due to solver limitation and because it may be beneficial to computation performance. For LAPACK backend and non-periodic boundary condition, we are using SplinesLinearSolver3x3Blocks which requires upper_block_size additional rows for internal operations.
317 *
318 * @return The (transposed) domain for the spline coefficients.
319 */
320 batched_spline_tr_domain_type batched_spline_tr_domain() const noexcept
321 {
322 return batched_spline_tr_domain_type(ddc::replace_dim_of<bsplines_type, bsplines_type>(
324 ddc::DiscreteDomain<bsplines_type>(
325 ddc::DiscreteElement<bsplines_type>(0),
326 ddc::DiscreteVector<bsplines_type>(
327 matrix->required_number_of_rhs_rows()))));
328 }
329
330public:
331 /**
332 * @brief Get the whole domain on which derivatives on lower boundary are defined.
333 *
334 * This is only used with BoundCond::HERMITE boundary conditions.
335 *
336 * @return The domain for the Derivs values.
337 */
338 batched_derivs_domain_type batched_derivs_xmin_domain() const noexcept
339 {
340 return ddc::replace_dim_of<interpolation_discrete_dimension_type, deriv_type>(
342 ddc::DiscreteDomain<deriv_type>(
343 ddc::DiscreteElement<deriv_type>(1),
344 ddc::DiscreteVector<deriv_type>(s_nbc_xmin)));
345 }
346
347 /**
348 * @brief Get the whole domain on which derivatives on upper boundary are defined.
349 *
350 * This is only used with BoundCond::HERMITE boundary conditions.
351 *
352 * @return The domain for the Derivs values.
353 */
354 batched_derivs_domain_type batched_derivs_xmax_domain() const noexcept
355 {
356 return ddc::replace_dim_of<interpolation_discrete_dimension_type, deriv_type>(
358 ddc::DiscreteDomain<deriv_type>(
359 ddc::DiscreteElement<deriv_type>(1),
360 ddc::DiscreteVector<deriv_type>(s_nbc_xmax)));
361 }
362
363 /**
364 * @brief Compute a spline approximation of a function.
365 *
366 * Use the values of a function (defined on
367 * SplineBuilder::batched_interpolation_domain) and the derivatives of the
368 * function at the boundaries (in the case of BoundCond::HERMITE only, defined
369 * on SplineBuilder::batched_derivs_xmin_domain and SplineBuilder::batched_derivs_xmax_domain)
370 * to calculate a spline approximation of this function.
371 *
372 * The spline approximation is stored as a ChunkSpan of coefficients
373 * associated with B-splines.
374 *
375 * @param[out] spline The coefficients of the spline computed by this SplineBuilder.
376 * @param[in] vals The values of the function on the interpolation mesh.
377 * @param[in] derivs_xmin The values of the derivatives at the lower boundary
378 * (used only with BoundCond::HERMITE lower boundary condition).
379 * @param[in] derivs_xmax The values of the derivatives at the upper boundary
380 * (used only with BoundCond::HERMITE upper boundary condition).
381 */
382 template <class Layout>
383 void operator()(
384 ddc::ChunkSpan<double, batched_spline_domain_type, Layout, memory_space> spline,
385 ddc::ChunkSpan<double const, batched_interpolation_domain_type, Layout, memory_space>
386 vals,
387 std::optional<
388 ddc::ChunkSpan<double const, batched_derivs_domain_type, Layout, memory_space>>
389 derivs_xmin
390 = std::nullopt,
391 std::optional<
392 ddc::ChunkSpan<double const, batched_derivs_domain_type, Layout, memory_space>>
393 derivs_xmax
394 = std::nullopt) const;
395
396 /**
397 * @brief Compute the quadrature coefficients associated to the b-splines used by this SplineBuilder.
398 *
399 * Those coefficients can be used to perform integration way faster than SplineEvaluator::integrate().
400 *
401 * This function solves matrix equation A^t*Q=integral_bsplines. In case of HERMITE boundary conditions,
402 * integral_bsplines contains the integral coefficients at the boundaries, and Q thus has to
403 * be split in three parts (quadrature coefficients for the derivatives at lower boundary,
404 * for the values inside the domain and for the derivatives at upper boundary).
405 *
406 * A discrete function f can then be integrated using sum_j Q_j*f_j for j in interpolation_domain.
407 * If boundary condition is HERMITE, sum_j Qderiv_j*(d^j f/dx^j) for j in derivs_domain
408 * must be added at the boundary.
409 *
410 * Please refer to section 2.8.1 of Emily's Bourne phd (https://theses.fr/2022AIXM0412) for more information and to
411 * the (Non)PeriodicSplineBuilderTest for example usage to compute integrals.
412 *
413 * @tparam OutMemorySpace The Kokkos::MemorySpace on which the quadrature coefficients are be returned
414 * (but they are computed on ExecSpace then copied).
415 *
416 * @return A tuple containing the three Chunks containing the quadrature coefficients (if HERMITE
417 * is not used, first and third are empty).
418 */
419 template <class OutMemorySpace = MemorySpace>
420 std::tuple<
421 ddc::Chunk<
422 double,
424 ddc::Deriv<typename InterpolationDDim::continuous_dimension_type>>,
425 ddc::KokkosAllocator<double, OutMemorySpace>>,
426 ddc::Chunk<
427 double,
428 ddc::DiscreteDomain<InterpolationDDim>,
429 ddc::KokkosAllocator<double, OutMemorySpace>>,
430 ddc::Chunk<
431 double,
433 ddc::Deriv<typename InterpolationDDim::continuous_dimension_type>>,
434 ddc::KokkosAllocator<double, OutMemorySpace>>>
436
437private:
438 static int compute_block_sizes_uniform(ddc::BoundCond bound_cond, int nbc);
439
440 static int compute_block_sizes_non_uniform(ddc::BoundCond bound_cond, int nbc);
441
442 void allocate_matrix(
443 int lower_block_size,
444 int upper_block_size,
445 std::optional<std::size_t> cols_per_chunk = std::nullopt,
446 std::optional<unsigned int> preconditioner_max_block_size = std::nullopt);
447
448 void build_matrix_system();
449
450 void check_valid_grid();
451
452 template <class KnotElement>
453 static void check_n_points_in_cell(int n_points_in_cell, KnotElement current_cell_end_idx);
454};
455
456template <
457 class ExecSpace,
458 class MemorySpace,
459 class BSplines,
460 class InterpolationDDim,
461 ddc::BoundCond BcLower,
462 ddc::BoundCond BcUpper,
463 SplineSolver Solver,
464 class... DDimX>
465void SplineBuilder<
466 ExecSpace,
467 MemorySpace,
468 BSplines,
469 InterpolationDDim,
470 BcLower,
471 BcUpper,
472 Solver,
473 DDimX...>::
474 compute_offset(interpolation_domain_type const& interpolation_domain, int& offset)
475{
476 if constexpr (bsplines_type::is_periodic()) {
477 // Calculate offset so that the matrix is diagonally dominant
478 std::array<double, bsplines_type::degree() + 1> values_ptr;
479 Kokkos::mdspan<double, Kokkos::extents<std::size_t, bsplines_type::degree() + 1>> const
480 values(values_ptr.data());
481 ddc::DiscreteElement<interpolation_discrete_dimension_type> start(
482 interpolation_domain.front());
483 auto jmin = ddc::discrete_space<BSplines>()
484 .eval_basis(values, ddc::coordinate(start + BSplines::degree()));
485 if constexpr (bsplines_type::degree() % 2 == 0) {
486 offset = jmin.uid() - start.uid() + bsplines_type::degree() / 2 - BSplines::degree();
487 } else {
488 int const mid = bsplines_type::degree() / 2;
489 offset = jmin.uid() - start.uid()
490 + (DDC_MDSPAN_ACCESS_OP(values, mid) > DDC_MDSPAN_ACCESS_OP(values, mid + 1)
491 ? mid
492 : mid + 1)
493 - BSplines::degree();
494 }
495 } else {
496 offset = 0;
497 }
498}
499
500template <
501 class ExecSpace,
502 class MemorySpace,
503 class BSplines,
504 class InterpolationDDim,
505 ddc::BoundCond BcLower,
506 ddc::BoundCond BcUpper,
507 SplineSolver Solver,
508 class... DDimX>
509int SplineBuilder<
510 ExecSpace,
511 MemorySpace,
512 BSplines,
513 InterpolationDDim,
514 BcLower,
515 BcUpper,
516 Solver,
517 DDimX...>::compute_block_sizes_uniform(ddc::BoundCond const bound_cond, int const nbc)
518{
519 if (bound_cond == ddc::BoundCond::PERIODIC) {
520 return static_cast<int>(bsplines_type::degree()) / 2;
521 }
522
523 if (bound_cond == ddc::BoundCond::HERMITE) {
524 return nbc;
525 }
526
527 if (bound_cond == ddc::BoundCond::GREVILLE) {
528 return static_cast<int>(bsplines_type::degree()) - 1;
529 }
530
531 throw std::runtime_error("ddc::BoundCond not handled");
532}
533
534template <
535 class ExecSpace,
536 class MemorySpace,
537 class BSplines,
538 class InterpolationDDim,
539 ddc::BoundCond BcLower,
540 ddc::BoundCond BcUpper,
541 SplineSolver Solver,
542 class... DDimX>
543int SplineBuilder<
544 ExecSpace,
545 MemorySpace,
546 BSplines,
547 InterpolationDDim,
548 BcLower,
549 BcUpper,
550 Solver,
551 DDimX...>::compute_block_sizes_non_uniform(ddc::BoundCond const bound_cond, int const nbc)
552{
553 if (bound_cond == ddc::BoundCond::PERIODIC || bound_cond == ddc::BoundCond::GREVILLE) {
554 return static_cast<int>(bsplines_type::degree()) - 1;
555 }
556
557 if (bound_cond == ddc::BoundCond::HERMITE) {
558 return nbc + 1;
559 }
560
561 throw std::runtime_error("ddc::BoundCond not handled");
562}
563
564template <
565 class ExecSpace,
566 class MemorySpace,
567 class BSplines,
568 class InterpolationDDim,
569 ddc::BoundCond BcLower,
570 ddc::BoundCond BcUpper,
571 SplineSolver Solver,
572 class... DDimX>
573void SplineBuilder<
574 ExecSpace,
575 MemorySpace,
576 BSplines,
577 InterpolationDDim,
578 BcLower,
579 BcUpper,
580 Solver,
581 DDimX...>::
582 allocate_matrix(
583 [[maybe_unused]] int lower_block_size,
584 [[maybe_unused]] int upper_block_size,
585 std::optional<std::size_t> cols_per_chunk,
586 std::optional<unsigned int> preconditioner_max_block_size)
587{
588 // Special case: linear spline
589 // No need for matrix assembly
590 // (disabled)
591 // if constexpr (bsplines_type::degree() == 1) {
592 // return;
593 // }
594
595 if constexpr (Solver == ddc::SplineSolver::LAPACK) {
596 int upper_band_width;
597 if (bsplines_type::is_uniform()) {
598 upper_band_width = bsplines_type::degree() / 2;
599 } else {
600 upper_band_width = bsplines_type::degree() - 1;
601 }
602 if constexpr (bsplines_type::is_periodic()) {
603 matrix = ddc::detail::SplinesLinearProblemMaker::make_new_periodic_band_matrix<
604 ExecSpace>(
605 ddc::discrete_space<BSplines>().nbasis(),
606 upper_band_width,
607 upper_band_width,
608 bsplines_type::is_uniform());
609 } else {
610 matrix = ddc::detail::SplinesLinearProblemMaker::
611 make_new_block_matrix_with_band_main_block<ExecSpace>(
612 ddc::discrete_space<BSplines>().nbasis(),
613 upper_band_width,
614 upper_band_width,
615 bsplines_type::is_uniform(),
616 lower_block_size,
617 upper_block_size);
618 }
619 } else if constexpr (Solver == ddc::SplineSolver::GINKGO) {
620 matrix = ddc::detail::SplinesLinearProblemMaker::make_new_sparse<ExecSpace>(
621 ddc::discrete_space<BSplines>().nbasis(),
622 cols_per_chunk,
623 preconditioner_max_block_size);
624 }
625
626 build_matrix_system();
627
628 matrix->setup_solver();
629}
630
631template <
632 class ExecSpace,
633 class MemorySpace,
634 class BSplines,
635 class InterpolationDDim,
636 ddc::BoundCond BcLower,
637 ddc::BoundCond BcUpper,
638 SplineSolver Solver,
639 class... DDimX>
640void SplineBuilder<
641 ExecSpace,
642 MemorySpace,
643 BSplines,
644 InterpolationDDim,
645 BcLower,
646 BcUpper,
647 Solver,
648 DDimX...>::build_matrix_system()
649{
650 // Hermite boundary conditions at xmin, if any
651 if constexpr (BcLower == ddc::BoundCond::HERMITE) {
652 std::array<double, (bsplines_type::degree() / 2 + 1) * (bsplines_type::degree() + 1)>
653 derivs_ptr;
654 ddc::DSpan2D const
655 derivs(derivs_ptr.data(),
656 bsplines_type::degree() + 1,
657 bsplines_type::degree() / 2 + 1);
658 ddc::discrete_space<BSplines>().eval_basis_and_n_derivs(
659 derivs,
660 ddc::discrete_space<BSplines>().rmin(),
661 s_nbc_xmin);
662
663 // In order to improve the condition number of the matrix, we normalize
664 // all derivatives by multiplying the i-th derivative by dx^i
665 for (std::size_t i = 0; i < bsplines_type::degree() + 1; ++i) {
666 for (std::size_t j = 1; j < bsplines_type::degree() / 2 + 1; ++j) {
667 DDC_MDSPAN_ACCESS_OP(derivs, i, j) *= ddc::detail::ipow(m_dx, j);
668 }
669 }
670
671 // iterate only to deg as last bspline is 0
672 for (std::size_t i = 0; i < s_nbc_xmin; ++i) {
673 for (std::size_t j = 0; j < bsplines_type::degree(); ++j) {
674 matrix->set_element(
675 i,
676 j,
677 DDC_MDSPAN_ACCESS_OP(derivs, j, s_nbc_xmin - i - 1 + s_odd));
678 }
679 }
680 }
681
682 // Interpolation points
683 std::array<double, bsplines_type::degree() + 1> values_ptr;
684 Kokkos::mdspan<double, Kokkos::extents<std::size_t, bsplines_type::degree() + 1>> const values(
685 values_ptr.data());
686
687 int start = interpolation_domain().front().uid();
688 ddc::for_each(interpolation_domain(), [&](auto ix) {
689 auto jmin = ddc::discrete_space<BSplines>().eval_basis(
690 values,
691 ddc::coordinate(ddc::DiscreteElement<interpolation_discrete_dimension_type>(ix)));
692 for (std::size_t s = 0; s < bsplines_type::degree() + 1; ++s) {
693 int const j = ddc::detail::
694 modulo(int(jmin.uid() - m_offset + s),
695 static_cast<int>(ddc::discrete_space<BSplines>().nbasis()));
696 matrix->set_element(ix.uid() - start + s_nbc_xmin, j, DDC_MDSPAN_ACCESS_OP(values, s));
697 }
698 });
699
700 // Hermite boundary conditions at xmax, if any
701 if constexpr (BcUpper == ddc::BoundCond::HERMITE) {
702 std::array<double, (bsplines_type::degree() / 2 + 1) * (bsplines_type::degree() + 1)>
703 derivs_ptr;
704 Kokkos::mdspan<
705 double,
706 Kokkos::extents<
707 std::size_t,
708 bsplines_type::degree() + 1,
709 bsplines_type::degree() / 2 + 1>> const derivs(derivs_ptr.data());
710
711 ddc::discrete_space<BSplines>().eval_basis_and_n_derivs(
712 derivs,
713 ddc::discrete_space<BSplines>().rmax(),
714 s_nbc_xmax);
715
716 // In order to improve the condition number of the matrix, we normalize
717 // all derivatives by multiplying the i-th derivative by dx^i
718 for (std::size_t i = 0; i < bsplines_type::degree() + 1; ++i) {
719 for (std::size_t j = 1; j < bsplines_type::degree() / 2 + 1; ++j) {
720 DDC_MDSPAN_ACCESS_OP(derivs, i, j) *= ddc::detail::ipow(m_dx, j);
721 }
722 }
723
724 int const i0 = ddc::discrete_space<BSplines>().nbasis() - s_nbc_xmax;
725 int const j0 = ddc::discrete_space<BSplines>().nbasis() - bsplines_type::degree();
726 for (std::size_t j = 0; j < bsplines_type::degree(); ++j) {
727 for (std::size_t i = 0; i < s_nbc_xmax; ++i) {
728 matrix->set_element(i0 + i, j0 + j, DDC_MDSPAN_ACCESS_OP(derivs, j + 1, i + s_odd));
729 }
730 }
731 }
732}
733
734template <
735 class ExecSpace,
736 class MemorySpace,
737 class BSplines,
738 class InterpolationDDim,
742 class... DDimX>
743template <class Layout>
744void SplineBuilder<
745 ExecSpace,
746 MemorySpace,
747 BSplines,
748 InterpolationDDim,
749 BcLower,
750 BcUpper,
751 Solver,
752 DDimX...>::
753operator()(
754 ddc::ChunkSpan<double, batched_spline_domain_type, Layout, memory_space> spline,
755 ddc::ChunkSpan<double const, batched_interpolation_domain_type, Layout, memory_space> vals,
756 std::optional<ddc::ChunkSpan<
757 double const,
758 batched_derivs_domain_type,
759 Layout,
760 memory_space>> const derivs_xmin,
761 std::optional<ddc::ChunkSpan<
762 double const,
763 batched_derivs_domain_type,
764 Layout,
765 memory_space>> const derivs_xmax) const
766{
767 assert(vals.template extent<interpolation_discrete_dimension_type>()
768 == ddc::discrete_space<bsplines_type>().nbasis() - s_nbc_xmin - s_nbc_xmax);
769
770 assert((BcLower == ddc::BoundCond::HERMITE)
771 != (!derivs_xmin.has_value() || derivs_xmin->template extent<deriv_type>() == 0));
772 assert((BcUpper == ddc::BoundCond::HERMITE)
773 != (!derivs_xmax.has_value() || derivs_xmax->template extent<deriv_type>() == 0));
774 if constexpr (BcLower == BoundCond::HERMITE) {
775 assert(ddc::DiscreteElement<deriv_type>(derivs_xmin->domain().front()).uid() == 1);
776 }
777 if constexpr (BcUpper == BoundCond::HERMITE) {
778 assert(ddc::DiscreteElement<deriv_type>(derivs_xmax->domain().front()).uid() == 1);
779 }
780
781 // Hermite boundary conditions at xmin, if any
782 // NOTE: For consistency with the linear system, the i-th derivative
783 // provided by the user must be multiplied by dx^i
784 if constexpr (BcLower == BoundCond::HERMITE) {
785 assert(derivs_xmin->template extent<deriv_type>() == s_nbc_xmin);
786 auto derivs_xmin_values = *derivs_xmin;
787 auto const dx_proxy = m_dx;
788 ddc::parallel_for_each(
789 "ddc_splines_hermite_compute_lower_coefficients",
790 exec_space(),
792 KOKKOS_LAMBDA(typename batch_domain_type::discrete_element_type j) {
793 for (int i = s_nbc_xmin; i > 0; --i) {
794 spline(ddc::DiscreteElement<bsplines_type>(s_nbc_xmin - i), j)
795 = derivs_xmin_values(ddc::DiscreteElement<deriv_type>(i), j)
796 * ddc::detail::ipow(dx_proxy, i + s_odd - 1);
797 }
798 });
799 }
800
801 // Fill spline with vals (to work in spline afterward and preserve vals)
802 ddc::parallel_fill(
803 exec_space(),
804 spline[ddc::DiscreteDomain<bsplines_type>(
805 ddc::DiscreteElement<bsplines_type>(s_nbc_xmin),
806 ddc::DiscreteVector<bsplines_type>(m_offset))],
807 0.);
808 // NOTE: We rely on Kokkos::deep_copy because ddc::parallel_deepcopy do not support
809 // different domain-typed Chunks.
810 Kokkos::deep_copy(
811 exec_space(),
812 spline[ddc::DiscreteDomain<bsplines_type>(
813 ddc::DiscreteElement<bsplines_type>(s_nbc_xmin + m_offset),
814 ddc::DiscreteVector<bsplines_type>(static_cast<std::size_t>(
815 vals.domain()
816 .template extent<
817 interpolation_discrete_dimension_type>())))]
818 .allocation_kokkos_view(),
819 vals.allocation_kokkos_view());
820
821
822
823 // Hermite boundary conditions at xmax, if any
824 // NOTE: For consistency with the linear system, the i-th derivative
825 // provided by the user must be multiplied by dx^i
826 auto const& nbasis_proxy = ddc::discrete_space<bsplines_type>().nbasis();
827 if constexpr (BcUpper == BoundCond::HERMITE) {
828 assert(derivs_xmax->template extent<deriv_type>() == s_nbc_xmax);
829 auto derivs_xmax_values = *derivs_xmax;
830 auto const dx_proxy = m_dx;
831 ddc::parallel_for_each(
832 "ddc_splines_hermite_compute_upper_coefficients",
833 exec_space(),
835 KOKKOS_LAMBDA(typename batch_domain_type::discrete_element_type j) {
836 for (int i = 0; i < s_nbc_xmax; ++i) {
837 spline(ddc::DiscreteElement<bsplines_type>(nbasis_proxy - s_nbc_xmax - i),
838 j)
839 = derivs_xmax_values(ddc::DiscreteElement<deriv_type>(i + 1), j)
840 * ddc::detail::ipow(dx_proxy, i + s_odd);
841 }
842 });
843 }
844
845 // Allocate and fill a transposed version of spline in order to get dimension of interest as last dimension (optimal for GPU, necessary for Ginkgo). Also select only relevant rows in case of periodic boundaries
846 auto const& offset_proxy = m_offset;
847 ddc::Chunk spline_tr_alloc(
848 batched_spline_tr_domain(),
849 ddc::KokkosAllocator<double, memory_space>());
850 ddc::ChunkSpan const spline_tr = spline_tr_alloc.span_view();
851 ddc::parallel_for_each(
852 "ddc_splines_transpose_rhs",
853 exec_space(),
855 KOKKOS_LAMBDA(typename batch_domain_type::discrete_element_type const j) {
856 for (std::size_t i = 0; i < nbasis_proxy; ++i) {
857 spline_tr(ddc::DiscreteElement<bsplines_type>(i), j)
858 = spline(ddc::DiscreteElement<bsplines_type>(i + offset_proxy), j);
859 }
860 });
861 // Create a 2D Kokkos::View to manage spline_tr as a matrix
862 Kokkos::View<double**, Kokkos::LayoutRight, exec_space> const bcoef_section(
863 spline_tr.data_handle(),
864 static_cast<std::size_t>(spline_tr.template extent<bsplines_type>()),
865 batch_domain().size());
866 // Compute spline coef
867 matrix->solve(bcoef_section, false);
868 // Transpose back spline_tr into spline.
869 ddc::parallel_for_each(
870 "ddc_splines_transpose_back_rhs",
871 exec_space(),
873 KOKKOS_LAMBDA(typename batch_domain_type::discrete_element_type const j) {
874 for (std::size_t i = 0; i < nbasis_proxy; ++i) {
875 spline(ddc::DiscreteElement<bsplines_type>(i + offset_proxy), j)
876 = spline_tr(ddc::DiscreteElement<bsplines_type>(i), j);
877 }
878 });
879
880 // Duplicate the lower spline coefficients to the upper side in case of periodic boundaries
881 if (bsplines_type::is_periodic()) {
882 ddc::parallel_for_each(
883 "ddc_splines_periodic_rows_duplicate_rhs",
884 exec_space(),
886 KOKKOS_LAMBDA(typename batch_domain_type::discrete_element_type const j) {
887 if (offset_proxy != 0) {
888 for (int i = 0; i < offset_proxy; ++i) {
889 spline(ddc::DiscreteElement<bsplines_type>(i), j) = spline(
890 ddc::DiscreteElement<bsplines_type>(nbasis_proxy + i),
891 j);
892 }
893 for (std::size_t i = offset_proxy; i < bsplines_type::degree(); ++i) {
894 spline(ddc::DiscreteElement<bsplines_type>(nbasis_proxy + i), j)
895 = spline(ddc::DiscreteElement<bsplines_type>(i), j);
896 }
897 }
898 for (std::size_t i(0); i < bsplines_type::degree(); ++i) {
899 const ddc::DiscreteElement<bsplines_type> i_start(i);
900 const ddc::DiscreteElement<bsplines_type> i_end(nbasis_proxy + i);
901
902 spline(i_end, j) = spline(i_start, j);
903 }
904 });
905 }
906}
907
908template <
909 class ExecSpace,
910 class MemorySpace,
911 class BSplines,
912 class InterpolationDDim,
916 class... DDimX>
917template <class OutMemorySpace>
918std::tuple<
919 ddc::Chunk<
920 double,
922 ddc::Deriv<typename InterpolationDDim::continuous_dimension_type>>,
923 ddc::KokkosAllocator<double, OutMemorySpace>>,
924 ddc::Chunk<
925 double,
926 ddc::DiscreteDomain<InterpolationDDim>,
927 ddc::KokkosAllocator<double, OutMemorySpace>>,
928 ddc::Chunk<
929 double,
931 ddc::Deriv<typename InterpolationDDim::continuous_dimension_type>>,
932 ddc::KokkosAllocator<double, OutMemorySpace>>>
934 ExecSpace,
935 MemorySpace,
936 BSplines,
937 InterpolationDDim,
938 BcLower,
939 BcUpper,
940 Solver,
941 DDimX...>::quadrature_coefficients() const
942{
943 // Compute integrals of bsplines
944 ddc::Chunk integral_bsplines(spline_domain(), ddc::KokkosAllocator<double, MemorySpace>());
945 ddc::integrals(ExecSpace(), integral_bsplines.span_view());
946
947 // Remove additional B-splines in the periodic case (cf. UniformBSplines::full_domain() documentation)
948 ddc::ChunkSpan const integral_bsplines_without_periodic_additional_bsplines
949 = integral_bsplines[spline_domain().take_first(
950 ddc::DiscreteVector<bsplines_type>(matrix->size()))];
951
952 // Allocate mirror with additional rows (cf. SplinesLinearProblem3x3Blocks documentation)
953 Kokkos::View<double**, Kokkos::LayoutRight, MemorySpace> const
954 integral_bsplines_mirror_with_additional_allocation(
955 "integral_bsplines_mirror_with_additional_allocation",
956 matrix->required_number_of_rhs_rows(),
957 1);
958
959 // Extract relevant subview
960 Kokkos::View<double*, Kokkos::LayoutRight, MemorySpace> const integral_bsplines_mirror
961 = Kokkos::
962 subview(integral_bsplines_mirror_with_additional_allocation,
963 std::
964 pair {static_cast<std::size_t>(0),
965 integral_bsplines_without_periodic_additional_bsplines
966 .size()},
967 0);
968
969 // Solve matrix equation A^t*X=integral_bsplines
970 Kokkos::deep_copy(
971 integral_bsplines_mirror,
972 integral_bsplines_without_periodic_additional_bsplines.allocation_kokkos_view());
973 matrix->solve(integral_bsplines_mirror_with_additional_allocation, true);
974 Kokkos::deep_copy(
975 integral_bsplines_without_periodic_additional_bsplines.allocation_kokkos_view(),
976 integral_bsplines_mirror);
977
978 // Slice into three ChunkSpan corresponding to lower derivatives, function values and upper derivatives
979 ddc::ChunkSpan const coefficients_derivs_xmin
980 = integral_bsplines_without_periodic_additional_bsplines[spline_domain().take_first(
981 ddc::DiscreteVector<bsplines_type>(s_nbc_xmin))];
982 ddc::ChunkSpan const coefficients = integral_bsplines_without_periodic_additional_bsplines
984 .remove_first(ddc::DiscreteVector<bsplines_type>(s_nbc_xmin))
985 .take_first(ddc::DiscreteVector<bsplines_type>(
986 ddc::discrete_space<bsplines_type>().nbasis() - s_nbc_xmin
987 - s_nbc_xmax))];
988 ddc::ChunkSpan const coefficients_derivs_xmax
989 = integral_bsplines_without_periodic_additional_bsplines
991 .remove_first(ddc::DiscreteVector<bsplines_type>(
992 s_nbc_xmin + coefficients.size()))
993 .take_first(ddc::DiscreteVector<bsplines_type>(s_nbc_xmax))];
994 interpolation_domain_type const interpolation_domain_proxy = interpolation_domain();
995
996 // Multiply derivatives coefficients by dx^n
997 ddc::parallel_for_each(
998 exec_space(),
999 coefficients_derivs_xmin.domain(),
1000 KOKKOS_LAMBDA(ddc::DiscreteElement<bsplines_type> i) {
1001 ddc::Coordinate<continuous_dimension_type> const dx
1002 = ddc::distance_at_right(interpolation_domain_proxy.front() + 1);
1003 coefficients_derivs_xmin(i) *= ddc::detail::
1004 ipow(dx,
1005 static_cast<std::size_t>(get<bsplines_type>(
1006 i - coefficients_derivs_xmin.domain().front() + 1)));
1007 });
1008 ddc::parallel_for_each(
1009 exec_space(),
1010 coefficients_derivs_xmax.domain(),
1011 KOKKOS_LAMBDA(ddc::DiscreteElement<bsplines_type> i) {
1012 ddc::Coordinate<continuous_dimension_type> const dx
1013 = ddc::distance_at_left(interpolation_domain_proxy.back() - 1);
1014 coefficients_derivs_xmax(i) *= ddc::detail::
1015 ipow(dx,
1016 static_cast<std::size_t>(get<bsplines_type>(
1017 i - coefficients_derivs_xmax.domain().front() + 1)));
1018 });
1019
1020 // Allocate Chunk on deriv_type and interpolation_discrete_dimension_type and copy quadrature coefficients into it
1021 ddc::Chunk coefficients_derivs_xmin_out(
1022 ddc::DiscreteDomain<deriv_type>(
1023 ddc::DiscreteElement<deriv_type>(1),
1024 ddc::DiscreteVector<deriv_type>(s_nbc_xmin)),
1025 ddc::KokkosAllocator<double, OutMemorySpace>());
1026 ddc::Chunk coefficients_out(
1027 interpolation_domain().take_first(
1028 ddc::DiscreteVector<interpolation_discrete_dimension_type>(
1029 coefficients.size())),
1030 ddc::KokkosAllocator<double, OutMemorySpace>());
1031 ddc::Chunk coefficients_derivs_xmax_out(
1032 ddc::DiscreteDomain<deriv_type>(
1033 ddc::DiscreteElement<deriv_type>(1),
1034 ddc::DiscreteVector<deriv_type>(s_nbc_xmax)),
1035 ddc::KokkosAllocator<double, OutMemorySpace>());
1036 Kokkos::deep_copy(
1037 coefficients_derivs_xmin_out.allocation_kokkos_view(),
1038 coefficients_derivs_xmin.allocation_kokkos_view());
1039 Kokkos::deep_copy(
1040 coefficients_out.allocation_kokkos_view(),
1041 coefficients.allocation_kokkos_view());
1042 Kokkos::deep_copy(
1043 coefficients_derivs_xmax_out.allocation_kokkos_view(),
1044 coefficients_derivs_xmax.allocation_kokkos_view());
1045 return std::make_tuple(
1046 std::move(coefficients_derivs_xmin_out),
1047 std::move(coefficients_out),
1048 std::move(coefficients_derivs_xmax_out));
1049}
1050
1051template <
1052 class ExecSpace,
1053 class MemorySpace,
1054 class BSplines,
1055 class InterpolationDDim,
1059 class... DDimX>
1060template <class KnotElement>
1061void SplineBuilder<
1062 ExecSpace,
1063 MemorySpace,
1064 BSplines,
1065 InterpolationDDim,
1066 BcLower,
1067 BcUpper,
1068 Solver,
1069 DDimX...>::
1070 check_n_points_in_cell(int const n_points_in_cell, KnotElement const current_cell_end_idx)
1071{
1072 if (n_points_in_cell > BSplines::degree() + 1) {
1073 KnotElement const rmin_idx = ddc::discrete_space<BSplines>().break_point_domain().front();
1074 int const failed_cell = (current_cell_end_idx - rmin_idx).value();
1075 throw std::runtime_error(
1076 "The spline problem is overconstrained. There are "
1077 + std::to_string(n_points_in_cell) + " points in the " + std::to_string(failed_cell)
1078 + "-th cell.");
1079 }
1080}
1081
1082template <
1083 class ExecSpace,
1084 class MemorySpace,
1085 class BSplines,
1086 class InterpolationDDim,
1087 ddc::BoundCond BcLower,
1088 ddc::BoundCond BcUpper,
1089 SplineSolver Solver,
1090 class... DDimX>
1091void SplineBuilder<
1092 ExecSpace,
1093 MemorySpace,
1094 BSplines,
1095 InterpolationDDim,
1096 BcLower,
1097 BcUpper,
1098 Solver,
1099 DDimX...>::check_valid_grid()
1100{
1101 std::size_t const n_interp_points = interpolation_domain().size();
1102 std::size_t const expected_npoints
1103 = ddc::discrete_space<BSplines>().nbasis() - s_nbc_xmin - s_nbc_xmax;
1104 if (n_interp_points != expected_npoints) {
1105 throw std::runtime_error(
1106 "Incorrect number of points supplied to NonUniformInterpolationPoints. "
1107 "(Received : "
1108 + std::to_string(n_interp_points)
1109 + ", expected : " + std::to_string(expected_npoints));
1110 }
1111 int n_points_in_cell = 0;
1112 auto current_cell_end_idx = ddc::discrete_space<BSplines>().break_point_domain().front() + 1;
1113 ddc::for_each(interpolation_domain(), [&](auto idx) {
1114 ddc::Coordinate<continuous_dimension_type> const point = ddc::coordinate(idx);
1115 if (point > ddc::coordinate(current_cell_end_idx)) {
1116 // Check the points found in the previous cell
1117 check_n_points_in_cell(n_points_in_cell, current_cell_end_idx);
1118 // Initialise the number of points in the subsequent cell, including the new point
1119 n_points_in_cell = 1;
1120 // Move to the next cell
1121 current_cell_end_idx += 1;
1122 } else if (point == ddc::coordinate(current_cell_end_idx)) {
1123 // Check the points found in the previous cell including the point on the boundary
1124 check_n_points_in_cell(n_points_in_cell + 1, current_cell_end_idx);
1125 // Initialise the number of points in the subsequent cell, including the point on the boundary
1126 n_points_in_cell = 1;
1127 // Move to the next cell
1128 current_cell_end_idx += 1;
1129 } else {
1130 // Indicate that the point is in the cell
1131 n_points_in_cell += 1;
1132 }
1133 });
1134 // Check the number of points in the final cell
1135 check_n_points_in_cell(n_points_in_cell, current_cell_end_idx);
1136}
1137
1138} // namespace ddc
friend class DiscreteDomain
KOKKOS_FUNCTION constexpr bool operator!=(DiscreteVector< OTags... > const &rhs) const noexcept
A class for creating a spline approximation of a function.
static constexpr ddc::BoundCond s_bc_xmax
The boundary condition implemented at the upper bound.
static constexpr SplineSolver s_spline_solver
The SplineSolver giving the backend used to perform the spline approximation.
ddc::DiscreteDomain< bsplines_type > spline_domain() const noexcept
Get the 1D domain on which spline coefficients are defined.
SplineBuilder(SplineBuilder const &x)=delete
Copy-constructor is deleted.
interpolation_domain_type interpolation_domain() const noexcept
Get the domain for the 1D interpolation mesh used by this class.
SplineBuilder(batched_interpolation_domain_type const &batched_interpolation_domain, std::optional< std::size_t > cols_per_chunk=std::nullopt, std::optional< unsigned int > preconditioner_max_block_size=std::nullopt)
Build a SplineBuilder acting on batched_interpolation_domain.
static constexpr int s_nbc_xmin
The number of equations defining the boundary condition at the lower bound.
static constexpr int s_nbc_xmax
The number of equations defining the boundary condition at the upper bound.
SplineBuilder & operator=(SplineBuilder &&x)=default
Move-assigns.
std::tuple< ddc::Chunk< double, ddc::DiscreteDomain< ddc::Deriv< typename InterpolationDDim::continuous_dimension_type > >, ddc::KokkosAllocator< double, OutMemorySpace > >, ddc::Chunk< double, ddc::DiscreteDomain< InterpolationDDim >, ddc::KokkosAllocator< double, OutMemorySpace > >, ddc::Chunk< double, ddc::DiscreteDomain< ddc::Deriv< typename InterpolationDDim::continuous_dimension_type > >, ddc::KokkosAllocator< double, OutMemorySpace > > > quadrature_coefficients() const
Compute the quadrature coefficients associated to the b-splines used by this SplineBuilder.
static constexpr bool s_odd
Indicates if the degree of the splines is odd or even.
~SplineBuilder()=default
Destructs.
batched_spline_domain_type batched_spline_domain() const noexcept
Get the whole domain on which spline coefficients are defined.
batched_interpolation_domain_type batched_interpolation_domain() const noexcept
Get the whole domain representing interpolation points.
SplineBuilder & operator=(SplineBuilder const &x)=delete
Copy-assignment is deleted.
static constexpr ddc::BoundCond s_bc_xmin
The boundary condition implemented at the lower bound.
batched_derivs_domain_type batched_derivs_xmax_domain() const noexcept
Get the whole domain on which derivatives on upper boundary are defined.
batch_domain_type batch_domain() const noexcept
Get the batch domain.
batched_derivs_domain_type batched_derivs_xmin_domain() const noexcept
Get the whole domain on which derivatives on lower boundary are defined.
SplineBuilder(SplineBuilder &&x)=default
Move-constructs.
void operator()(ddc::ChunkSpan< double, batched_spline_domain_type, Layout, memory_space > spline, ddc::ChunkSpan< double const, batched_interpolation_domain_type, Layout, memory_space > vals, std::optional< ddc::ChunkSpan< double const, batched_derivs_domain_type, Layout, memory_space > > derivs_xmin=std::nullopt, std::optional< ddc::ChunkSpan< double const, batched_derivs_domain_type, Layout, memory_space > > derivs_xmax=std::nullopt) const
Compute a spline approximation of a function.
The top-level namespace of DDC.
BoundCond
An enum representing a spline boundary condition.
@ GREVILLE
Use Greville points instead of conditions on derivative for B-Spline interpolation.
@ HERMITE
Hermite boundary condition.
@ PERIODIC
Periodic boundary condition u(1)=u(n)
SplineSolver
An enum determining the backend solver of a SplineBuilder or SplineBuilder2d.
@ LAPACK
Enum member to identify the LAPACK-based solver (direct method)
@ GINKGO
Enum member to identify the Ginkgo-based solver (iterative method)
A templated struct representing a discrete dimension storing the derivatives of a function along a co...
Definition deriv.hpp:15