SDDSlib
Loading...
Searching...
No Matches
interp.c
Go to the documentation of this file.
1/**
2 * @file interp.c
3 * @brief Implements interpolation functions including linear and Lagrange interpolation.
4 *
5 * @copyright
6 * - (c) 2002 The University of Chicago, as Operator of Argonne National Laboratory.
7 * - (c) 2002 The Regents of the University of California, as Operator of Los Alamos National Laboratory.
8 *
9 * @license
10 * This file is distributed under the terms of the Software License Agreement
11 * found in the file LICENSE included with this distribution.
12 *
13 * @author M. Borland, C. Saunders, R. Soliday, H. Shang, N. Kuklev
14 */
15
16#include "mdb.h"
17
18/**
19 * @brief Performs simple linear interpolation of data.
20 *
21 * This function interpolates the value at a given point using linear interpolation.
22 * It handles boundary conditions by returning the nearest data point value when the
23 * interpolation point is outside the data range.
24 *
25 * @param f Pointer to the array of function values.
26 * @param x Pointer to the array of independent variable values.
27 * @param n Number of data points.
28 * @param xo The point at which to interpolate.
29 * @param warnings Flag to enable or disable warning messages.
30 * @param order The order of interpolation.
31 * @param returnCode Pointer to a variable to store the return code status.
32 * @return The interpolated value at point xo.
33 */
34double interp(double *f, double *x, long n, double xo, long warnings, long order, long *returnCode) {
35 long hi, lo, mid, offset;
36
37 lo = 0;
38 hi = n - 1;
39 if (lo == hi) {
40 if (warnings)
41 printf("warning: only one point--returning value for that point\n");
42 *returnCode = 0;
43 return (f[0]);
44 }
45 if (x[lo] < x[hi]) { /* indep variable ordered from small to large */
46 if (xo < x[lo = 0]) {
47 if (warnings)
48 printf("warning: %22.15e outside [%22.15e,%22.15e] (interp)\n",
49 xo, x[0], x[n - 1]);
50 *returnCode = 0;
51 return (f[lo]);
52 }
53 if (xo > x[hi = n - 1]) {
54 if (warnings)
55 printf("warning: %22.15e outside [%22.15e,%22.15e] (interp)\n",
56 xo, x[0], x[n - 1]);
57 *returnCode = 0;
58 return (f[hi]);
59 }
60
61 /* do binary search for closest point */
62 while ((hi - lo) > 1) {
63 mid = (lo + hi) / 2;
64 if (xo < x[mid])
65 hi = mid;
66 else
67 lo = mid;
68 }
69 } else { /* indep variable ordered from large to small */
70 if (xo > x[lo = 0]) {
71 if (warnings)
72 printf("warning: %22.15e outside [%22.15e,%22.15e] (interp)\n",
73 xo, x[n - 1], x[0]);
74 *returnCode = 0;
75 return (f[lo]);
76 }
77 if (xo < x[hi = n - 1]) {
78 if (warnings)
79 printf("warning: %22.15e outside [%22.15e,%22.15e] (interp)\n",
80 xo, x[n - 1], x[0]);
81 *returnCode = 0;
82 return (f[hi]);
83 }
84
85 /* do binary search for closest point */
86 while ((hi - lo) > 1) {
87 mid = (lo + hi) / 2;
88 if (xo > x[mid])
89 hi = mid;
90 else
91 lo = mid;
92 }
93 }
94 /* L.Emery's contribution */
95 offset = lo - (order - 1) / 2; /* offset centers the argument in the set of points. */
96 offset = MAX(offset, 0);
97 offset = MIN(offset, n - order - 1);
98 offset = MAX(offset, 0);
99 return LagrangeInterp(x + offset, f + offset, order + 1, xo, returnCode);
100}
101
102/**
103 * @brief Performs Lagrange interpolation of data.
104 *
105 * This function computes the interpolated value at a given point using Lagrange
106 * polynomial interpolation of a specified order.
107 *
108 * @param x Pointer to the array of independent variable values.
109 * @param f Pointer to the array of function values.
110 * @param order1 The order of the Lagrange polynomial.
111 * @param x0 The point at which to interpolate.
112 * @param returnCode Pointer to a variable to store the return code status.
113 * @return The interpolated value at point x0.
114 */
115double LagrangeInterp(double *x, double *f, long order1, double x0, long *returnCode) {
116 long i, j;
117 double denom, numer, sum;
118
119 for (i = sum = 0; i < order1; i++) {
120 denom = 1;
121 numer = 1;
122 for (j = 0; j < order1; j++) {
123 if (i != j) {
124 denom *= (x[i] - x[j]);
125 numer *= (x0 - x[j]);
126 if (numer == 0) {
127 *returnCode = 1;
128 return f[j];
129 }
130 }
131 }
132 if (denom == 0) {
133 *returnCode = 0;
134 return 0.0;
135 }
136 sum += f[i] * numer / denom;
137 }
138 *returnCode = 1;
139 return sum;
140}
141
142/**
143 * @brief Performs interpolation with range control options.
144 *
145 * This function interpolates the value at a given point with additional control
146 * over out-of-range conditions, such as skipping, aborting, warning, wrapping,
147 * saturating, or using a specified value.
148 *
149 * @param f Pointer to the array of function values.
150 * @param x Pointer to the array of independent variable values.
151 * @param n Number of data points.
152 * @param xo The point at which to interpolate.
153 * @param belowRange Pointer to structure controlling behavior below the data range.
154 * @param aboveRange Pointer to structure controlling behavior above the data range.
155 * @param order The order of interpolation.
156 * @param returnCode Pointer to a variable to store the return code status.
157 * @param M Multiplier to adjust the interpolation condition based on the order.
158 * @return The interpolated value at point xo.
159 */
160double interpolate(double *f, double *x, int64_t n, double xo, OUTRANGE_CONTROL *belowRange,
161 OUTRANGE_CONTROL *aboveRange, long order, unsigned long *returnCode, long M) {
162 long code;
163 int64_t hi, lo, mid, offset;
164 double result, below, above;
165
166 *returnCode = 0;
167
168 lo = 0;
169 hi = n - 1;
170 if (M > 0) {
171 above = f[n - 1];
172 below = f[0];
173 } else {
174 above = f[0];
175 below = f[n - 1];
176 }
177 if ((xo * M > x[hi] * M && M > 0) || (xo * M < x[lo] * M && M < 0)) {
178 if (aboveRange->flags & OUTRANGE_SKIP) {
179 *returnCode = OUTRANGE_SKIP;
180 return above;
181 } else if (aboveRange->flags & OUTRANGE_ABORT) {
182 *returnCode = OUTRANGE_ABORT;
183 return above;
184 } else if (aboveRange->flags & OUTRANGE_WARN)
185 *returnCode = OUTRANGE_WARN;
186 if (aboveRange->flags & OUTRANGE_VALUE) {
187 *returnCode |= OUTRANGE_VALUE;
188 return aboveRange->value;
189 }
190 if (aboveRange->flags & OUTRANGE_WRAP) {
191 double delta;
192 *returnCode |= OUTRANGE_WRAP;
193 if ((delta = x[hi] - x[lo]) == 0)
194 return f[0];
195 while (xo * M > x[hi] * M)
196 xo -= delta;
197 } else if (aboveRange->flags & OUTRANGE_SATURATE || !(aboveRange->flags & OUTRANGE_EXTRAPOLATE)) {
198 *returnCode |= OUTRANGE_SATURATE;
199 return above;
200 }
201 }
202 if ((xo * M < x[lo] * M && M > 0) || (xo * M > x[hi] * M && M < 0)) {
203 if (belowRange->flags & OUTRANGE_SKIP) {
204 *returnCode = OUTRANGE_SKIP;
205 return below;
206 } else if (belowRange->flags & OUTRANGE_ABORT) {
207 *returnCode = OUTRANGE_ABORT;
208 return below;
209 } else if (belowRange->flags & OUTRANGE_WARN)
210 *returnCode = OUTRANGE_WARN;
211 if (belowRange->flags & OUTRANGE_VALUE) {
212 *returnCode |= OUTRANGE_VALUE;
213 return belowRange->value;
214 }
215 if (belowRange->flags & OUTRANGE_WRAP) {
216 double delta;
217 *returnCode |= OUTRANGE_WRAP;
218 if ((delta = x[hi] - x[lo]) == 0)
219 return below;
220 while (xo * M < x[lo] * M)
221 xo += delta;
222 } else if (belowRange->flags & OUTRANGE_SATURATE || !(belowRange->flags & OUTRANGE_EXTRAPOLATE)) {
223 *returnCode |= OUTRANGE_SATURATE;
224 return below;
225 }
226 }
227
228 if (lo == hi) {
229 if (xo == x[lo]) {
230 if (aboveRange->flags & OUTRANGE_WARN || belowRange->flags & OUTRANGE_WARN)
231 *returnCode = OUTRANGE_WARN;
232 }
233 return f[0];
234 }
235
236 lo = 0;
237 hi = n - 1;
238 if (xo * M < x[0] * M)
239 hi = 1;
240 else if (xo * M > x[n - 1] * M)
241 lo = hi - 1;
242 else {
243 /* do binary search for closest point */
244 while ((hi - lo) > 1) {
245 mid = (lo + hi) / 2;
246 if (xo * M < x[mid] * M)
247 hi = mid;
248 else
249 lo = mid;
250 }
251 }
252
253 /* L.Emery's contribution */
254 if (order > n - 1)
255 order = n - 1;
256 offset = lo - (order - 1) / 2; /* offset centers the argument in the set of points. */
257 offset = MAX(offset, 0);
258 offset = MIN(offset, n - order - 1);
259 result = LagrangeInterp(x + offset, f + offset, order + 1, xo, &code);
260 if (!code)
261 bomb("zero denominator in LagrangeInterp", NULL);
262 return result;
263}
264
265/**
266 * @brief Performs interpolation for short integer data types.
267 *
268 * This function interpolates the value at a given point for short integer data,
269 * handling boundary conditions and allowing for different interpolation orders.
270 *
271 * @param f Pointer to the array of short integer function values.
272 * @param x Pointer to the array of independent variable values.
273 * @param n Number of data points.
274 * @param xo The point at which to interpolate.
275 * @param warnings Flag to enable or disable warning messages.
276 * @param order The order of interpolation.
277 * @param returnCode Pointer to a variable to store the return code status.
278 * @param next_start_pos Pointer to store the next starting position for interpolation.
279 * @return The interpolated short integer value at point xo.
280 */
281short interp_short(short *f, double *x, int64_t n, double xo, long warnings, short order,
282 unsigned long *returnCode, long *next_start_pos) {
283 int64_t hi, lo, mid, i;
284 short value;
285
286 lo = 0;
287 hi = n - 1;
288
289 *returnCode = 0;
290 /*if the interpolate point is less or equal to the start point, return the value of the start point */
291 if (xo <= x[0]) {
292 *next_start_pos = 0;
293 return f[0];
294 }
295
296 /*if the value is in one of the indepent, return the corresponding f value */
297 for (i = 0; i < n; i++)
298 if (xo == x[i]) {
299 *next_start_pos = i;
300 return f[i];
301 }
302 if (lo == hi) {
303 if (warnings)
304 printf("warning: only one point--returning value for that point\n");
305 *returnCode = 0;
306 *next_start_pos = lo;
307 return (f[0]);
308 }
309 if (x[lo] < x[hi]) { /* indep variable ordered from small to large */
310 if (xo < x[lo = 0]) {
311 if (warnings)
312 printf("warning: %22.15e outside [%22.15e,%22.15e] (interp)\n",
313 xo, x[0], x[n - 1]);
314 *returnCode = 0;
315 *next_start_pos = lo;
316 return (f[lo]);
317 }
318 if (xo > x[hi = n - 1]) {
319 if (warnings)
320 printf("warning: %22.15e outside [%22.15e,%22.15e] (interp)\n",
321 xo, x[0], x[n - 1]);
322 *returnCode = 0;
323 *next_start_pos = hi;
324 return (f[hi]);
325 }
326
327 /* do binary search for closest point */
328 while ((hi - lo) > 1) {
329 mid = (lo + hi) / 2;
330 if (xo < x[mid])
331 hi = mid;
332 else
333 lo = mid;
334 }
335 } else { /* indep variable ordered from large to small */
336 if (xo > x[lo = 0]) {
337 if (warnings)
338 printf("warning: %22.15e outside [%22.15e,%22.15e] (interp)\n",
339 xo, x[n - 1], x[0]);
340 *returnCode = 0;
341 *next_start_pos = lo;
342 return (f[lo]);
343 }
344 if (xo < x[hi = n - 1]) {
345 if (warnings)
346 printf("warning: %22.15e outside [%22.15e,%22.15e] (interp)\n",
347 xo, x[n - 1], x[0]);
348 *returnCode = 0;
349 *next_start_pos = hi;
350 return (f[hi]);
351 }
352
353 /* do binary search for closest point */
354 while ((hi - lo) > 1) {
355 mid = (lo + hi) / 2;
356 if (xo > x[mid])
357 hi = mid;
358 else
359 lo = mid;
360 }
361 }
362 /*remember this position so that one can start from her to speed up the interp of
363 other points assume the interping points are sorted.*/
364 *next_start_pos = lo;
365 *returnCode = 0;
366 if (order == -1) {
367 /* inherit value from previous point*/
368 value = (short)f[lo];
369 } else if (order == -2) {
370 /* inherit value from next point */
371 value = (short)f[hi];
372 } else {
373 value = (f[hi] - f[lo]) / (xo - x[lo]);
374 }
375 return value;
376}
void bomb(char *error, char *usage)
Reports error messages to the terminal and aborts the program.
Definition bomb.c:26
short interp_short(short *f, double *x, int64_t n, double xo, long warnings, short order, unsigned long *returnCode, long *next_start_pos)
Performs interpolation for short integer data types.
Definition interp.c:281
double LagrangeInterp(double *x, double *f, long order1, double x0, long *returnCode)
Performs Lagrange interpolation of data.
Definition interp.c:115
double interpolate(double *f, double *x, int64_t n, double xo, OUTRANGE_CONTROL *belowRange, OUTRANGE_CONTROL *aboveRange, long order, unsigned long *returnCode, long M)
Performs interpolation with range control options.
Definition interp.c:160
double interp(double *f, double *x, long n, double xo, long warnings, long order, long *returnCode)
Performs simple linear interpolation of data.
Definition interp.c:34