/* Author: G. Jungman * RCS: $Id: linear.c,v 1.10 1999/10/06 05:43:44 jungman Exp $ */ #include #include #include #include "gsl_interp.h" /* linear interpolation object */ typedef struct { int (*eval_impl) (const gsl_interp_obj *, const double xa[], const double ya[], double x, gsl_interp_accel *, double *y); int (*eval_d_impl) (const gsl_interp_obj *, const double xa[], const double ya[], double x, gsl_interp_accel *, double *dydx); int (*eval_i_impl) (const struct _gsl_interp_obj_struct *, const double xa[], const double ya[], gsl_interp_accel *, double a, double b, double * result); void (*free) (gsl_interp_obj *); double xmin; double xmax; size_t size; } gsl_interp_linear; static gsl_interp_obj * linear_create (const double xa[], const double ya[], size_t size); static void linear_free (gsl_interp_obj * interp); static int linear_eval_impl (const gsl_interp_obj *, const double xa[], const double ya[], double x, gsl_interp_accel *, double *y); static int linear_eval_d_impl (const gsl_interp_obj *, const double xa[], const double ya[], double x, gsl_interp_accel *, double *dydx); static int linear_eval_i_impl (const gsl_interp_obj *, const double xa[], const double ya[], gsl_interp_accel *, double, double, double *); const gsl_interp_factory gsl_interp_factory_linear = { "linear", linear_create }; static gsl_interp_obj * linear_create (const double x_array[], const double y_array[], size_t size) { y_array = 0; /* prevent warning about unused parameter */ if (size <= 1) return 0; else { gsl_interp_linear *interp = (gsl_interp_linear *) malloc (sizeof (gsl_interp_linear)); if (interp != 0) { interp->eval_impl = linear_eval_impl; interp->eval_d_impl = linear_eval_d_impl; interp->eval_i_impl = linear_eval_i_impl; interp->free = linear_free; interp->xmin = x_array[0]; interp->xmax = x_array[size - 1]; interp->size = size; } return (gsl_interp_obj *) interp; } } static void linear_free (gsl_interp_obj * linear_interp) { if (linear_interp != 0) free ((gsl_interp_linear *) linear_interp); } static int linear_eval_impl (const gsl_interp_obj * linear_interp, const double x_array[], const double y_array[], double x, gsl_interp_accel * a, double *y) { const gsl_interp_linear *interp = (const gsl_interp_linear *) linear_interp; if (x < interp->xmin) { *y = y_array[0]; return GSL_EDOM; } else if (x > interp->xmax) { *y = y_array[interp->size - 1]; return GSL_EDOM; } else { double x_lo, x_hi; double y_lo, y_hi; double dx; size_t index; if (a != 0) { index = gsl_interp_accel_find (a, x_array, interp->size, x); } else { index = gsl_interp_bsearch (x_array, x, 0, interp->size - 1); } /* evaluate */ x_lo = x_array[index]; x_hi = x_array[index + 1]; y_lo = y_array[index]; y_hi = y_array[index + 1]; dx = x_hi - x_lo; if (dx > 0.0) { *y = y_lo + (x - x_lo) / dx * (y_hi - y_lo); return GSL_SUCCESS; } else { *y = 0.0; return GSL_EINVAL; } } } static int linear_eval_d_impl (const gsl_interp_obj * linear_interp, const double x_array[], const double y_array[], double x, gsl_interp_accel * a, double *dydx) { const gsl_interp_linear *interp = (const gsl_interp_linear *) linear_interp; if (x < interp->xmin) { *dydx = 0.0; return GSL_EDOM; } else if (x > interp->xmax) { *dydx = 0.0; return GSL_EDOM; } else { double x_lo, x_hi; double y_lo, y_hi; double dx; double dy; size_t index; if (a != 0) { index = gsl_interp_accel_find (a, x_array, interp->size, x); } else { index = gsl_interp_bsearch (x_array, x, 0, interp->size - 1); } /* evaluate */ x_lo = x_array[index]; x_hi = x_array[index + 1]; y_lo = y_array[index]; y_hi = y_array[index + 1]; dx = x_hi - x_lo; dy = y_hi - y_lo; if (dx > 0.0) { *dydx = dy / dx;; return GSL_SUCCESS; } else { *dydx = 0.0; return GSL_EINVAL; } } } static int linear_eval_i_impl (const gsl_interp_obj * linear_interp, const double x_array[], const double y_array[], gsl_interp_accel * acc, double a, double b, double * result) { const gsl_interp_linear *interp = (const gsl_interp_linear *) linear_interp; if (a > b || a < interp->xmin || b > interp->xmax) { *result = 0.0; return GSL_EDOM; } else if(a == b) { *result = 0.0; return GSL_SUCCESS; } else { size_t index_a, index_b; if (acc != 0) { index_a = gsl_interp_accel_find (acc, x_array, interp->size, a); index_b = gsl_interp_accel_find (acc, x_array, interp->size, b); } else { index_a = gsl_interp_bsearch (x_array, a, 0, interp->size - 1); index_b = gsl_interp_bsearch (x_array, b, 0, interp->size - 1); } if(index_a == index_b) { /* endpoints inside same interval */ const double x_hi = x_array[index_a + 1]; const double x_lo = x_array[index_a]; const double y_lo = y_array[index_a]; const double y_hi = y_array[index_a + 1]; const double dx = x_hi - x_lo; const double dy = y_hi - y_lo; if(dx != 0.0) { const double D = dy/dx; *result = (b-a) * (y_lo + 0.5*D*(b+a - 2.0*x_lo)); return GSL_SUCCESS; } else { *result = 0.0; return GSL_FAILURE; } } else { /* endpoints span more than one interval */ size_t i; *result = 0.0; /* interior intervals */ for(i=index_a+1; i