/home/runner/work/amr-wind/amr-wind/amr-wind/utilities/linear_interpolation.H Source File

AMR-Wind API: /home/runner/work/amr-wind/amr-wind/amr-wind/utilities/linear_interpolation.H Source File
AMR-Wind API v0.1.0
CFD solver for wind plant simulations
Loading...
Searching...
No Matches
linear_interpolation.H
Go to the documentation of this file.
1#ifndef LINEAR_INTERPOLATION_H
2#define LINEAR_INTERPOLATION_H
3
4#include "AMReX_Gpu.H"
5#include "AMReX_REAL.H"
6#include "AMReX_Extension.H"
7
8using namespace amrex::literals;
9
11
12enum class Limits : int { // NOLINT(performance-enum-size)
13 LOWLIM = -2,
14 UPLIM = -1,
15 VALID = 0,
16};
17
18struct Index
19{
20 int idx;
22};
23
24template <typename It, typename T>
25AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE Index
26check_bounds(const It begin, const It end, const T& x)
27{
28 const int sz = static_cast<int>(end - begin);
29
30 if ((sz < 2) || (x < *begin)) {
31 return Index{.idx = 0, .lim = Limits::LOWLIM};
32 }
33 if (x > *(begin + (sz - 1))) {
34 return Index{.idx = sz - 1, .lim = Limits::UPLIM};
35 }
36
37 return Index{.idx = 0, .lim = Limits::VALID};
38}
39
40template <typename It, typename T>
41AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE Index
42bisection_search(const It begin, const It end, const T& x)
43{
44 auto idx = check_bounds(begin, end, x);
45 if ((idx.lim == Limits::LOWLIM) || (idx.lim == Limits::UPLIM)) {
46 return idx;
47 }
48
49 int il = 0;
50 int ir = end - begin;
51 const T xl = *begin;
52
53 while ((ir - il) > 1) {
54 int mid = (il + ir) >> 1;
55 const T xmid = *(begin + mid);
56
57 if ((x - xmid) * (x - xl) <= 0.0_rt) {
58 ir = mid;
59 } else {
60 il = mid;
61 }
62 }
63 idx.idx = il;
64 return idx;
65}
66
67template <typename It, typename T>
68AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE Index
69nearest_search(const It begin, const It end, const T& x)
70{
71
72 auto idx = bisection_search(begin, end, x);
73 if ((idx.lim == Limits::LOWLIM) || (idx.lim == Limits::UPLIM)) {
74 return idx;
75 }
76
77 if ((x - begin[idx.idx]) > (begin[idx.idx + 1] - x)) {
78 idx.idx += 1;
79 }
80
81 return idx;
82}
83
84template <typename It, typename T>
85AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE Index
86find_index(const It begin, const It end, const T& x, const int hint = 1)
87{
88 auto idx = check_bounds(begin, end, x);
89 if ((idx.lim == Limits::LOWLIM) || (idx.lim == Limits::UPLIM)) {
90 return idx;
91 }
92
93 for (It it = (begin + hint); it < end; ++it) {
94 if (x <= *it) {
95 idx.idx = it - begin - 1;
96 break;
97 }
98 }
99 return idx;
100}
101
102template <typename C1, typename C2>
103AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
104 typename std::iterator_traits<C2>::value_type
106 const C1 xbegin,
107 const C2 yinp,
108 const typename std::iterator_traits<C1>::value_type& xout,
109 const Index& idx,
110 const int ncomp = 1,
111 const int comp = 0)
112{
113 using DType1 = typename std::iterator_traits<C1>::value_type;
114
115 if ((idx.lim == Limits::LOWLIM) || (idx.lim == Limits::UPLIM)) {
116 return yinp[(ncomp * idx.idx) + comp];
117 }
118 static constexpr DType1 eps = std::numeric_limits<float>::epsilon();
119 const int j = idx.idx;
120 const auto denom = (xbegin[j + 1] - xbegin[j]);
121 const auto facR = (denom > eps) ? ((xout - xbegin[j]) / denom) : 1.0_rt;
122 const auto facL = static_cast<DType1>(1.0_rt) - facR;
123 return (facL * yinp[(ncomp * j) + comp]) +
124 (facR * yinp[(ncomp * (j + 1)) + comp]);
125}
126
127template <typename C1, typename C2>
128AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
129 typename std::iterator_traits<C2>::value_type
131 const C1 xbegin,
132 const C1 xend,
133 const C2 yinp,
134 const typename std::iterator_traits<C1>::value_type& xout,
135 const int ncomp = 1,
136 const int comp = 0)
137{
138 const auto idx = bisection_search(xbegin, xend, xout);
139 return linear_impl(xbegin, yinp, xout, idx, ncomp, comp);
140}
141
142template <typename C1, typename C2>
143typename C2::value_type linear(
144 const C1& xinp,
145 const C2& yinp,
146 const typename C1::value_type& xout,
147 const int ncomp = 1,
148 const int comp = 0)
149{
150 return linear(
151 xinp.data(), (xinp.data() + xinp.size()), yinp.data(), xout, ncomp,
152 comp);
153}
154
155template <typename C1, typename C2>
157 const C1& xinp,
158 const C2& yinp,
159 const C1& xout,
160 C2& yout,
161 const int ncomp = 1,
162 const int comp = 0)
163{
164 static constexpr typename C1::value_type eps =
165 std::numeric_limits<float>::epsilon();
166 AMREX_ASSERT(xinp.size() == yinp.size());
167 AMREX_ASSERT(xout.size() == yout.size());
168
169 int hint = 1;
170 int npts = xout.size();
171 for (int i = 0; i < npts; ++i) {
172 const auto& x = xout[i];
173 const auto idx =
174 find_index(xinp.data(), (xinp.data() + xinp.size()), x, hint);
175
176 if ((idx.lim == Limits::LOWLIM) || (idx.lim == Limits::UPLIM)) {
177 yout[i] = yinp[(ncomp * idx.idx) + comp];
178 } else if (idx.lim == Limits::VALID) {
179 int j = idx.idx;
180 const auto denom = (xinp[j + 1] - xinp[j]);
181 const auto facR = (denom > eps) ? ((x - xinp[j]) / denom) : 1.0_rt;
182 const auto facL =
183 static_cast<typename C1::value_type>(1.0_rt) - facR;
184 yout[i] = (facL * yinp[(ncomp * j) + comp]) +
185 (facR * yinp[(ncomp * (j + 1)) + comp]);
186 ;
187 }
188 hint = idx.idx + 1;
189 }
190}
191
192template <typename C1, typename C2>
194 const C1& xinp,
195 const C2& yinp,
196 const C1& xout,
197 C2& yout,
198 const int ncomp = 1,
199 const int comp = 0)
200{
201 AMREX_ASSERT(
202 static_cast<amrex::Long>(xinp.size()) ==
203 static_cast<amrex::Long>(yinp.size()));
204 AMREX_ASSERT(
205 static_cast<amrex::Long>(xout.size()) ==
206 static_cast<amrex::Long>(yout.size()));
207
208 int npts = xout.size();
209 for (int i = 0; i < npts; ++i) {
210 yout[i] = linear(xinp, yinp, xout[i], ncomp, comp);
211 }
212}
213
214// Angles in yinp should be defined between [-upper_bound, +upper_bound]
215// Use cases would be degrees (upper_bound =360) and radians (upper_bound =2pi)
216template <typename C1, typename C2>
217AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
218 typename std::iterator_traits<C2>::value_type
220 const C1 xbegin,
221 const C1 xend,
222 const C2 yinp,
223 const typename std::iterator_traits<C1>::value_type& xout,
224 const typename std::iterator_traits<C1>::value_type& upper_bound)
225{
226 using DType1 = typename std::iterator_traits<C1>::value_type;
227 const auto idx = bisection_search(xbegin, xend, xout);
228
229 if ((idx.lim == Limits::LOWLIM) || (idx.lim == Limits::UPLIM)) {
230 return yinp[idx.idx];
231 }
232 static constexpr DType1 eps = std::numeric_limits<float>::epsilon();
233 const int j = idx.idx;
234 const auto denom = (xbegin[j + 1] - xbegin[j]);
235 /* https://math.stackexchange.com/questions/2144234/interpolating-between-2-angles
236 */
237 const auto R = (denom > eps) ? ((xout - xbegin[j]) / denom) : 0.0_rt;
238 const auto ub = upper_bound;
239 const auto hb = 0.5_rt * upper_bound;
240 const auto ohb = 1.5_rt * upper_bound;
241 return yinp[j] +
242 ((std::fmod((std::fmod(yinp[j + 1] - yinp[j], ub) + ohb), ub) - hb) *
243 R);
244}
245
246template <typename C1, typename C2>
247typename C2::value_type linear_angle(
248 const C1& xinp,
249 const C2& yinp,
250 const typename C1::value_type& xout,
251 const typename C1::value_type& upper_bound)
252{
253 return linear_angle(
254 xinp.data(), (xinp.data() + xinp.size()), yinp.data(), xout,
255 upper_bound);
256}
257
258template <typename C1, typename C2>
260 const C1& xinp,
261 const C2& yinp,
262 const C1& xout,
263 C2& yout,
264 const typename C1::value_type& upper_bound)
265{
266 AMREX_ASSERT(
267 static_cast<amrex::Long>(xinp.size()) ==
268 static_cast<amrex::Long>(yinp.size()));
269 AMREX_ASSERT(
270 static_cast<amrex::Long>(xout.size()) ==
271 static_cast<amrex::Long>(yout.size()));
272
273 int npts = xout.size();
274 for (int i = 0; i < npts; ++i) {
275 yout[i] = linear_angle(xinp, yinp, xout[i], upper_bound);
276 }
277}
278
279template <typename C1, typename C2>
280AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
281 typename std::iterator_traits<C2>::value_type
283 const C1 xbegin,
284 const C1 ybegin,
285 const int ny,
286 const C2 zinp,
287 const typename std::iterator_traits<C1>::value_type& xout,
288 const typename std::iterator_traits<C1>::value_type& yout,
289 const Index& xidx,
290 const Index& yidx)
291{
292 using DType1 = typename std::iterator_traits<C1>::value_type;
293
294 if ((xidx.lim == Limits::LOWLIM) || (xidx.lim == Limits::UPLIM) ||
295 (yidx.lim == Limits::LOWLIM) || (yidx.lim == Limits::UPLIM)) {
296 return zinp[(xidx.idx * ny) + yidx.idx];
297 }
298
299 const int i = xidx.idx;
300 const int j = yidx.idx;
301
302 static constexpr DType1 eps = std::numeric_limits<float>::epsilon();
303 const auto xdenom = (xbegin[i + 1] - xbegin[i]);
304 const auto xfacR = (xdenom > eps) ? ((xout - xbegin[i]) / xdenom) : 1.0_rt;
305 const auto xfacL = static_cast<DType1>(1.0_rt) - xfacR;
306 const auto ydenom = (ybegin[j + 1] - ybegin[j]);
307 const auto yfacR = (ydenom > eps) ? ((yout - ybegin[j]) / ydenom) : 1.0_rt;
308 const auto yfacL = static_cast<DType1>(1.0_rt) - yfacR;
309
310 const auto z00 = zinp[(i * ny) + j];
311 const auto z10 = zinp[((i + 1) * ny) + j];
312 const auto z01 = zinp[(i * ny) + (j + 1)];
313 const auto z11 = zinp[((i + 1) * ny) + (j + 1)];
314
315 return (z00 * xfacL * yfacL) + (z10 * xfacR * yfacL) +
316 (z01 * xfacL * yfacR) + (z11 * xfacR * yfacR);
317}
318
319template <typename C1, typename C2>
320AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
321 typename std::iterator_traits<C2>::value_type
323 const C1 xbegin,
324 const C1 xend,
325 const C1 ybegin,
326 const C1 yend,
327 const C2 zinp,
328 const typename std::iterator_traits<C1>::value_type& xout,
329 const typename std::iterator_traits<C1>::value_type& yout)
330{
331 const auto xidx = bisection_search(xbegin, xend, xout);
332 const auto yidx = bisection_search(ybegin, yend, yout);
333 return bilinear_impl(
334 xbegin, ybegin, static_cast<int>(yend - ybegin), zinp, xout, yout, xidx,
335 yidx);
336}
337
338template <typename C1, typename C2>
339typename C2::value_type bilinear(
340 const C1& xinp,
341 const C1& yinp,
342 const C2& zinp,
343 const typename C1::value_type& xout,
344 const typename C1::value_type& yout)
345{
346 AMREX_ALWAYS_ASSERT((xinp.size() * yinp.size()) == zinp.size());
347 return bilinear(
348 xinp.data(), (xinp.data() + xinp.size()), yinp.data(),
349 (yinp.data() + yinp.size()), zinp.data(), xout, yout);
350}
351
352} // namespace amr_wind::interp
353
354#endif /* LINEAR_INTERPOLATION_H */
Definition linear_interpolation.H:10
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE Index find_index(const It begin, const It end, const T &x, const int hint=1)
Definition linear_interpolation.H:86
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE Index check_bounds(const It begin, const It end, const T &x)
Definition linear_interpolation.H:26
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE Index bisection_search(const It begin, const It end, const T &x)
Definition linear_interpolation.H:42
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE std::iterator_traits< C2 >::value_type linear_angle(const C1 xbegin, const C1 xend, const C2 yinp, const typename std::iterator_traits< C1 >::value_type &xout, const typename std::iterator_traits< C1 >::value_type &upper_bound)
Definition linear_interpolation.H:219
Limits
Definition linear_interpolation.H:12
@ UPLIM
Definition linear_interpolation.H:14
@ VALID
Definition linear_interpolation.H:15
@ LOWLIM
Definition linear_interpolation.H:13
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE std::iterator_traits< C2 >::value_type bilinear(const C1 xbegin, const C1 xend, const C1 ybegin, const C1 yend, const C2 zinp, const typename std::iterator_traits< C1 >::value_type &xout, const typename std::iterator_traits< C1 >::value_type &yout)
Definition linear_interpolation.H:322
void linear_monotonic(const C1 &xinp, const C2 &yinp, const C1 &xout, C2 &yout, const int ncomp=1, const int comp=0)
Definition linear_interpolation.H:156
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE Index nearest_search(const It begin, const It end, const T &x)
Definition linear_interpolation.H:69
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE std::iterator_traits< C2 >::value_type linear(const C1 xbegin, const C1 xend, const C2 yinp, const typename std::iterator_traits< C1 >::value_type &xout, const int ncomp=1, const int comp=0)
Definition linear_interpolation.H:130
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE std::iterator_traits< C2 >::value_type linear_impl(const C1 xbegin, const C2 yinp, const typename std::iterator_traits< C1 >::value_type &xout, const Index &idx, const int ncomp=1, const int comp=0)
Definition linear_interpolation.H:105
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE std::iterator_traits< C2 >::value_type bilinear_impl(const C1 xbegin, const C1 ybegin, const int ny, const C2 zinp, const typename std::iterator_traits< C1 >::value_type &xout, const typename std::iterator_traits< C1 >::value_type &yout, const Index &xidx, const Index &yidx)
Definition linear_interpolation.H:282
Definition linear_interpolation.H:19
Limits lim
Definition linear_interpolation.H:21
int idx
Definition linear_interpolation.H:20