Gyselalib++
 
Loading...
Searching...
No Matches
Lagrange.hpp
1// SPDX-License-Identifier: MIT
2#pragma once
3
4#include <ddc/ddc.hpp>
5
6#include "ddc_aliases.hpp"
7#include "ddc_helper.hpp"
8
9enum class BCond { PERIODIC, DIRICHLET };
10
17template <class Execspace, class GridInterp, BCond BcMin, BCond BcMax>
19{
20 static_assert((BcMin == BCond::PERIODIC) == (BcMax == BCond::PERIODIC));
21 using IdxInterp = Idx<GridInterp>;
22 using IdxStepInterp = IdxStep<GridInterp>;
23 using IdxRangeInterp = IdxRange<GridInterp>;
24
25 using CoordDimI = Coord<typename GridInterp::continuous_dimension_type>;
26
27private:
28 IdxRangeInterp m_idx_range;
29 IdxRangeInterp m_inner_idx_range;
30 Field<double, IdxRangeInterp, typename Execspace::memory_space> m_lagrange_coeffs;
31 CoordDimI m_left_bound;
32 CoordDimI m_right_bound;
33 IdxStepInterp m_poly_support;
34
35public:
44 KOKKOS_FUNCTION Lagrange(
45 int degree,
46 Field<double, IdxRangeInterp, typename Execspace::memory_space> x_nodes_fnodes,
47 IdxRangeInterp idx_range,
48 IdxStepInterp ghost)
49 : m_idx_range(idx_range)
50 , m_inner_idx_range(idx_range.remove(ghost, ghost))
51 , m_lagrange_coeffs(x_nodes_fnodes)
52 , m_left_bound(ddc::coordinate(m_inner_idx_range.front()))
53 , m_right_bound(ddc::coordinate(m_inner_idx_range.back()))
54 , m_poly_support(degree + 1)
55 {
56 }
57
66 KOKKOS_FUNCTION double evaluate(CoordDimI x_interp) const;
67
68private:
69 IdxInterp getclosest(CoordDimI value) const;
70
71 KOKKOS_FUNCTION IdxInterp getclosest_binsearch(CoordDimI value) const;
72
73 KOKKOS_FUNCTION double evaluate_lagrange(CoordDimI x_interp) const;
74
75 KOKKOS_FUNCTION double apply_bc(CoordDimI x_interp) const;
76
77 KOKKOS_FUNCTION double compute_basis(
78 CoordDimI x_interp,
79 IdxInterp j,
80 IdxRangeInterp polynom_subidx_range) const;
81};
82
83template <typename Execspace, class GridInterp, BCond BcMin, BCond BcMax>
84Idx<GridInterp> Lagrange<Execspace, GridInterp, BcMin, BcMax>::getclosest(CoordDimI value) const
85{
86 assert(value >= m_left_bound && value <= m_right_bound);
87 auto it = std::
88 min_element(m_idx_range.begin(), m_idx_range.end(), [=](IdxInterp x, IdxInterp y) {
89 return std::abs(ddc::coordinate(x) - value) < std::abs(ddc::coordinate(y) - value);
90 });
91 return *it;
92}
93template <typename Execspace, class GridInterp, BCond BcMin, BCond BcMax>
94KOKKOS_INLINE_FUNCTION Idx<GridInterp> Lagrange<Execspace, GridInterp, BcMin, BcMax>::
95 getclosest_binsearch(CoordDimI x_interp) const
96{
97 assert(x_interp >= m_left_bound && x_interp <= m_right_bound);
98 IdxInterp begin = m_idx_range.front();
99 IdxInterp end = m_idx_range.back();
100 IdxInterp elm_cell = begin + (end - begin) / 2;
101 while (x_interp < ddc::coordinate(elm_cell)
102 || x_interp > ddc::coordinate(elm_cell + IdxStepInterp(1))) {
103 if (x_interp < ddc::coordinate(elm_cell)) {
104 end = elm_cell;
105 } else {
106 begin = elm_cell;
107 }
108
109 elm_cell = begin + (end - begin) / 2;
110 }
111 return elm_cell;
112}
113
123template <typename Execspace, class GridInterp, BCond BcMin, BCond BcMax>
125 CoordDimI x_interp,
126 IdxInterp j,
127 IdxRangeInterp polynom_subidx_range) const
128{
129 double w(1);
130 CoordDimI coord_j = ddc::coordinate(j);
131 for (IdxInterp const i : polynom_subidx_range) {
132 CoordDimI coord_i = ddc::coordinate(i);
133 if (coord_i != coord_j) {
134 w *= (x_interp - coord_i) / (coord_j - coord_i);
135 }
136 }
137 return w;
138}
139
140template <typename Execspace, class GridInterp, BCond BcMin, BCond BcMax>
142 CoordDimI x_interp) const
143{
144 CoordDimI bc_val = x_interp;
145 const double d = m_right_bound - m_left_bound;
146 if constexpr (BcMin == BCond::PERIODIC) {
147 bc_val -= Kokkos::floor((x_interp - m_left_bound) / d) * d;
148 } else {
149 if (x_interp < m_left_bound && BcMin == BCond::DIRICHLET) {
150 bc_val = m_left_bound;
151 } else if (x_interp > m_right_bound && BcMax == BCond::DIRICHLET) {
152 bc_val = m_right_bound;
153 }
154 }
155 return evaluate_lagrange(bc_val);
156}
157
158template <typename Execspace, class GridInterp, BCond BcMin, BCond BcMax>
160 CoordDimI x_interp) const
161{
162 if (x_interp < m_left_bound || m_right_bound < x_interp) {
163 return apply_bc(x_interp);
164 } else {
165 return evaluate_lagrange(x_interp);
166 }
167}
168
169template <typename Execspace, class GridInterp, BCond BcMin, BCond BcMax>
171 CoordDimI x_intern) const
172{
173 assert(x_intern >= m_left_bound && x_intern <= m_right_bound);
174
175 IdxInterp begin, end;
176 IdxInterp icell = getclosest_binsearch(x_intern);
177 IdxInterp mid = icell;
178 if (mid >= m_inner_idx_range.back() && BcMax == BCond::PERIODIC) {
179 begin = mid - m_poly_support / 2;
180 end = Kokkos::min(m_inner_idx_range.back(), begin + m_poly_support);
181 } else if (mid <= m_inner_idx_range.front() && BcMin == BCond::PERIODIC) {
182 begin = Kokkos::max(m_idx_range.front(), mid - m_poly_support / 2);
183 end = begin + m_poly_support;
184 } else {
185 if (m_inner_idx_range.front() + m_poly_support / 2 > mid) {
186 begin = m_inner_idx_range.front();
187 } else {
188 begin = mid - m_poly_support / 2;
189 }
190 end = Kokkos::min(m_idx_range.back() + IdxStepInterp(1), begin + m_poly_support);
191 }
192
193 if (end == m_idx_range.back())
194 begin = end - m_poly_support;
195 IdxStepInterp npoints_subidx_range(end - begin);
196 IdxRangeInterp subidx_range(begin, npoints_subidx_range);
197 double p = 0;
198 for (IdxInterp const ix : subidx_range) {
199 p += compute_basis(x_intern, ix, subidx_range) * m_lagrange_coeffs(ix);
200 }
201 return p;
202}
A class which implements Lagrange polynomials.
Definition Lagrange.hpp:19
KOKKOS_FUNCTION double evaluate(CoordDimI x_interp) const
Evaluates the approximated value of a function on a point current values at a known set of interpolat...
Definition Lagrange.hpp:159
KOKKOS_FUNCTION Lagrange(int degree, Field< double, IdxRangeInterp, typename Execspace::memory_space > x_nodes_fnodes, IdxRangeInterp idx_range, IdxStepInterp ghost)
Usual Constructor.
Definition Lagrange.hpp:44