Loading [MathJax]/extensions/TeX/AMSsymbols.js
LALSimulation 6.2.0.1-5e288d3
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
gsl_interpolation_steffen.c
Go to the documentation of this file.
1/* This file is a slightly modified version of GSL's
2 * interpolation/steffen.c
3 *
4 * Copyright (C) 2014 Jean-François Caron
5 * Modified by Jolien Creighton
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or (at
10 * your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 */
21
22/* Author: J.-F. Caron
23 *
24 * This interpolation method is taken from
25 * M.Steffen, "A simple method for monotonic interpolation in one dimension",
26 * Astron. Astrophys. 239, 443-450 (1990).
27 *
28 * This interpolation method guarantees monotonic interpolation functions between
29 * the given data points. A consequence of this is that extremal values can only
30 * occur at the data points. The interpolating function and its first derivative
31 * are guaranteed to be continuous, but the second derivative is not.
32 *
33 * The implementation is modelled on the existing Akima interpolation method
34 * previously included in GSL by Gerard Jungman.
35 */
36
37/* Modifications: Jolien Creighton
38 *
39 * This file is included in LAL to provide the functionality present in newer
40 * versions of GSL. The only functional modification is to prepend lal_ to
41 * avoid namespace collisions. Other modifications are to suppress compiler
42 * warnings about shadowed variables and unused parameters.
43 */
44
45/* JC - MODIFIED */
46#ifdef __GNUC__
47#define UNUSED __attribute__ ((unused))
48#else
49#define UNUSED
50#endif
51/* #include <config.h> */
52#define RETURN_IF_NULL(x) if (!x) { return ; }
53
54#include <stdlib.h>
55#include <math.h>
56#include <gsl/gsl_math.h>
57#include <gsl/gsl_errno.h>
58#include "gsl_interpolation_integ_eval.h" /* JC - MODIFIED */
59#include <gsl/gsl_interp.h>
60
61typedef struct
62{
63 double * a; /* eqs 2-5 of paper */
64 double * b;
65 double * c;
66 double * d;
67
68 double * y_prime; /* eq 11 of paper */
70
71static void steffen_free (void * vstate);
72static double steffen_copysign(const double x, const double y);
73
74static void *
75steffen_alloc (size_t size)
76{
77 steffen_state_t *state;
78
79 state = (steffen_state_t *) calloc (1, sizeof (steffen_state_t));
80
81 if (state == NULL)
82 {
83 GSL_ERROR_NULL("failed to allocate space for state", GSL_ENOMEM);
84 }
85
86 state->a = (double *) malloc (size * sizeof (double));
87
88 if (state->a == NULL)
89 {
90 steffen_free(state);
91 GSL_ERROR_NULL("failed to allocate space for a", GSL_ENOMEM);
92 }
93
94 state->b = (double *) malloc (size * sizeof (double));
95
96 if (state->b == NULL)
97 {
98 steffen_free(state);
99 GSL_ERROR_NULL("failed to allocate space for b", GSL_ENOMEM);
100 }
101
102 state->c = (double *) malloc (size * sizeof (double));
103
104 if (state->c == NULL)
105 {
106 steffen_free(state);
107 GSL_ERROR_NULL("failed to allocate space for c", GSL_ENOMEM);
108 }
109
110 state->d = (double *) malloc (size * sizeof (double));
111
112 if (state->d == NULL)
113 {
114 steffen_free(state);
115 GSL_ERROR_NULL("failed to allocate space for d", GSL_ENOMEM);
116 }
117
118 state->y_prime = (double *) malloc (size * sizeof (double));
119 if (state->y_prime == NULL)
120 {
121 steffen_free(state);
122 GSL_ERROR_NULL("failed to allocate space for y_prime", GSL_ENOMEM);
123 }
124
125 return state;
126}
127
128static int
129steffen_init (void * vstate, const double x_array[],
130 const double y_array[], size_t size)
131{
132 steffen_state_t *state = (steffen_state_t *) vstate;
133 size_t i;
134 double *a = state->a;
135 double *b = state->b;
136 double *c = state->c;
137 double *d = state->d;
138 double *y_prime = state->y_prime;
139
140 /*
141 * first assign the interval and slopes for the left boundary.
142 * We use the "simplest possibility" method described in the paper
143 * in section 2.2
144 */
145 double h0 = (x_array[1] - x_array[0]);
146 double s0 = (y_array[1] - y_array[0]) / h0;
147
148 y_prime[0] = s0;
149
150 /* Now we calculate all the necessary s, h, p, and y' variables
151 from 1 to N-2 (0 to size - 2 inclusive) */
152 for (i = 1; i < (size - 1); i++)
153 {
154 double pi;
155
156 /* equation 6 in the paper */
157 double hi = (x_array[i+1] - x_array[i]);
158 double him1 = (x_array[i] - x_array[i - 1]);
159
160 /* equation 7 in the paper */
161 double si = (y_array[i+1] - y_array[i]) / hi;
162 double sim1 = (y_array[i] - y_array[i - 1]) / him1;
163
164 /* equation 8 in the paper */
165 pi = (sim1*hi + si*him1) / (him1 + hi);
166
167 /* This is a C equivalent of the FORTRAN statement below eqn 11 */
168 y_prime[i] = (steffen_copysign(1.0,sim1) + steffen_copysign(1.0,si)) *
169 GSL_MIN(fabs(sim1),
170 GSL_MIN(fabs(si), 0.5*fabs(pi)));
171 }
172
173 /*
174 * we also need y' for the rightmost boundary; we use the
175 * "simplest possibility" method described in the paper in
176 * section 2.2
177 *
178 * y' = s_{n-1}
179 */
180 y_prime[size-1] = (y_array[size - 1] - y_array[size - 2]) /
181 (x_array[size - 1] - x_array[size - 2]);
182
183 /* Now we can calculate all the coefficients for the whole range. */
184 for (i = 0; i < (size - 1); i++)
185 {
186 double hi = (x_array[i+1] - x_array[i]);
187 double si = (y_array[i+1] - y_array[i]) / hi;
188
189 /* These are from equations 2-5 in the paper. */
190 a[i] = (y_prime[i] + y_prime[i+1] - 2*si) / hi / hi;
191 b[i] = (3*si - 2*y_prime[i] - y_prime[i+1]) / hi;
192 c[i] = y_prime[i];
193 d[i] = y_array[i];
194 }
195
196 return GSL_SUCCESS;
197}
198
199static void
200steffen_free (void * vstate)
201{
202 steffen_state_t *state = (steffen_state_t *) vstate;
203
204 RETURN_IF_NULL(state);
205
206 if (state->a)
207 free (state->a);
208
209 if (state->b)
210 free (state->b);
211
212 if (state->c)
213 free (state->c);
214
215 if (state->d)
216 free (state->d);
217
218 if (state->y_prime)
219 free (state->y_prime);
220
221 free (state);
222}
223
224static int
225steffen_eval (const void * vstate,
226 const double x_array[], const double UNUSED y_array[], size_t size,
227 double x, gsl_interp_accel * a, double *y) /* JC - MODIFIED */
228{
229 const steffen_state_t *state = (const steffen_state_t *) vstate;
230
231 size_t index;
232
233 if (a != 0)
234 {
235 index = gsl_interp_accel_find (a, x_array, size, x);
236 }
237 else
238 {
239 index = gsl_interp_bsearch (x_array, x, 0, size - 1);
240 }
241
242 /* evaluate */
243 {
244 const double x_lo = x_array[index];
245 const double delx = x - x_lo;
246 const double a_ = state->a[index]; /* JC - MODIFIED */
247 const double b = state->b[index];
248 const double c = state->c[index];
249 const double d = state->d[index];
250 /* Use Horner's scheme for efficient evaluation of polynomials. */
251 /* *y = a*delx*delx*delx + b*delx*delx + c*delx + d; */
252 *y = d + delx*(c + delx*(b + delx*a_)); /* JC - MODIFIED */
253
254 return GSL_SUCCESS;
255 }
256}
257
258static int
259steffen_eval_deriv (const void * vstate,
260 const double x_array[], const double UNUSED y_array[], size_t size,
261 double x, gsl_interp_accel * a, double *dydx)
262{
263 const steffen_state_t *state = (const steffen_state_t *) vstate;
264
265 size_t index;
266
267 /* DISCARD_POINTER(y_array); /\* prevent warning about unused parameter *\/ */
268
269 if (a != 0)
270 {
271 index = gsl_interp_accel_find (a, x_array, size, x);
272 }
273 else
274 {
275 index = gsl_interp_bsearch (x_array, x, 0, size - 1);
276 }
277
278 /* evaluate */
279 {
280 double x_lo = x_array[index];
281 double delx = x - x_lo;
282 double a_ = state->a[index]; /* JC - MODIFIED */
283 double b = state->b[index];
284 double c = state->c[index];
285 /*double d = state->d[index];*/
286 /* *dydx = 3*a*delx*delx*delx + 2*b*delx + c; */
287 *dydx = c + delx*(2*b + delx*3*a_);
288 return GSL_SUCCESS;
289 }
290}
291
292static int
293steffen_eval_deriv2 (const void * vstate,
294 const double x_array[], const double UNUSED y_array[], size_t size,
295 double x, gsl_interp_accel * a, double *y_pp)
296{
297 const steffen_state_t *state = (const steffen_state_t *) vstate;
298
299 size_t index;
300
301 /* DISCARD_POINTER(y_array); /\* prevent warning about unused parameter *\/ */
302
303 if (a != 0)
304 {
305 index = gsl_interp_accel_find (a, x_array, size, x);
306 }
307 else
308 {
309 index = gsl_interp_bsearch (x_array, x, 0, size - 1);
310 }
311
312 /* evaluate */
313 {
314 const double x_lo = x_array[index];
315 const double delx = x - x_lo;
316 const double a_ = state->a[index]; /* JC - MODIFIED */
317 const double b = state->b[index];
318 *y_pp = 6*a_*delx + 2*b; /* JC - MODIFIED */
319 return GSL_SUCCESS;
320 }
321}
322
323static int
324steffen_eval_integ (const void * vstate,
325 const double x_array[], const double UNUSED y_array[], size_t size,
326 gsl_interp_accel * acc, double a, double b,
327 double * result)
328{
329 /* a and b are the boundaries of the integration. */
330
331 const steffen_state_t *state = (const steffen_state_t *) vstate;
332
333 size_t i, index_a, index_b;
334
335 /* Find the data points in the x_array that are nearest to the desired */
336 /* a and b integration boundaries. */
337
338 if (acc != 0)
339 {
340 index_a = gsl_interp_accel_find (acc, x_array, size, a);
341 index_b = gsl_interp_accel_find (acc, x_array, size, b);
342 }
343 else
344 {
345 index_a = gsl_interp_bsearch (x_array, a, 0, size - 1);
346 index_b = gsl_interp_bsearch (x_array, b, 0, size - 1);
347 }
348
349 *result = 0.0;
350
351 /* Iterate over all the segments between data points and sum the */
352 /* contributions into result. */
353 for(i=index_a; i<=index_b; i++)
354 {
355 const double x_hi = x_array[i + 1];
356 const double x_lo = x_array[i];
357 const double dx = x_hi - x_lo;
358 if(dx != 0.0)
359 {
360 /*
361 * check if we are at a boundary point, so take the
362 * a and b parameters instead of the data points.
363 */
364 double x1 = (i == index_a) ? a-x_lo : 0.0;
365 double x2 = (i == index_b) ? b-x_lo : x_hi-x_lo;
366
367 *result += (1.0/4.0)*state->a[i]*(x2*x2*x2*x2 - x1*x1*x1*x1)
368 +(1.0/3.0)*state->b[i]*(x2*x2*x2 - x1*x1*x1)
369 +(1.0/2.0)*state->c[i]*(x2*x2 - x1*x1)
370 +state->d[i]*(x2-x1);
371 }
372 else /* if the interval was zero, i.e. consecutive x values in data. */
373 {
374 *result = 0.0;
375 return GSL_EINVAL;
376 }
377 }
378
379 return GSL_SUCCESS;
380}
381
382static double
383steffen_copysign(const double x, const double y)
384{
385 if ((x < 0 && y > 0) || (x > 0 && y < 0))
386 return -x;
387
388 return x;
389}
390
391static const gsl_interp_type steffen_type =
392{
393 "steffen",
394 3,
402};
403
404const gsl_interp_type * lal_gsl_interp_steffen = &steffen_type; /* JC - MODIFIED*/
static vector d(const double L_norm, const double J_norm, const vector roots)
Internal function that returns the coefficients "d_0", "d_2" and "d_4" from 1703.03967 corresponding ...
#define pi
#define c
double i
Definition: bh_ringdown.c:118
static const INT4 a
static int steffen_eval_integ(const void *vstate, const double x_array[], const double UNUSED y_array[], size_t size, gsl_interp_accel *acc, double a, double b, double *result)
static int steffen_eval_deriv2(const void *vstate, const double x_array[], const double UNUSED y_array[], size_t size, double x, gsl_interp_accel *a, double *y_pp)
static int steffen_eval(const void *vstate, const double x_array[], const double UNUSED y_array[], size_t size, double x, gsl_interp_accel *a, double *y)
static void * steffen_alloc(size_t size)
static int steffen_init(void *vstate, const double x_array[], const double y_array[], size_t size)
#define RETURN_IF_NULL(x)
const gsl_interp_type * lal_gsl_interp_steffen
static const gsl_interp_type steffen_type
static void steffen_free(void *vstate)
static double steffen_copysign(const double x, const double y)
static int steffen_eval_deriv(const void *vstate, const double x_array[], const double UNUSED y_array[], size_t size, double x, gsl_interp_accel *a, double *dydx)
list y
x