LALSimulation  5.4.0.1-fe68b98
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 
61 typedef 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 
71 static void steffen_free (void * vstate);
72 static double steffen_copysign(const double x, const double y);
73 
74 static void *
75 steffen_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 
128 static int
129 steffen_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 
199 static void
200 steffen_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 
224 static int
225 steffen_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 
258 static int
259 steffen_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 
292 static int
293 steffen_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 
323 static int
324 steffen_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 
382 static double
383 steffen_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 
391 static const gsl_interp_type steffen_type =
392 {
393  "steffen",
394  3,
395  &steffen_alloc,
396  &steffen_init,
397  &steffen_eval,
401  &steffen_free
402 };
403 
404 const 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 x
list y