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