File: spl-array.c

package info (click to toggle)
xmorph 1%3A17nov97-2
  • links: PTS
  • area: main
  • in suites: potato
  • size: 916 kB
  • ctags: 725
  • sloc: ansic: 9,326; makefile: 630; tcl: 476
file content (123 lines) | stat: -rw-r--r-- 3,419 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
/* spl-array.c: Spline interpolation support routines for matrices
//
// Written and Copyright (C) 1993-1997 by Michael J. Gourlay
//
// PROVIDED AS IS.  NO WARRANTEES, EXPRESS OR IMPLIED.
*/

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#include "my_malloc.h"
#include "spline.h"
#include "spl-array.h"

/* --------------------------------------------------------------- */

#define NEAR(x1, x2) (((x2)!=0.0) && (((x1)/(x2)) >= 0.999) && (((x1)/(x2))<1.001))

#ifndef FALSE
#define FALSE 0
#endif




/* --------------------------------------------------------------- */

/* derivative_hack: compute 1st derivative of x,y data (len entries)
//
// Written and Copyright (C) 1994-1997 by Michael J. Gourlay
//
// PROVIDED AS IS.  NO WARRANTEES, EXPRESS OR IMPLIED.
//
// Mathematically, it's a hack to prevent overshooting knots, but
// maintain smoothness and it works more intuitively.  Besides, we all
// know that mathematicians are too worried about rigor, and the
// physicists end up creating the right math. -- MJG
*/
static void derivative_hack(const double *x, const double *y, double *yd, int len)
{
  int indx;

  if(x[0]==x[1]) {
    yd[0] = 0.0; /* avoid division by zero */
  } else {
    yd[0] = (y[1]-y[0])/(x[1]-x[0]);
  }
  if(x[len-2] == x[len-1]) {
    yd[len-1] = 0.0; /* avoid division by zero */
  } else {
    yd[len-1] = (y[len-1]-y[len-2])/(x[len-1]-x[len-2]);
  }
  for(indx=1; indx<(len-1); indx++) {
    if(x[indx-1]==x[indx] || x[indx]==x[indx+1]) {
      yd[indx] = 0.0; /* avoid division by zero */
    } else {
      if( (y[indx-1] - y[indx]) * (y[indx+1] - y[indx]) >= 0.0) {
        /* There was a change in the sign of yd so force it zero */
        /* This will prevent the spline from overshooting this knot */
        yd[indx] = 0.0;
      } else {
        /* Set slope at this knot to slope between two adjacent knots */
        yd[indx] = (y[indx-1]-y[indx+1]) / (x[indx-1]-x[indx+1]);
      }
    }
  }
}




/* --------------------------------------------------------------- */

/* hermite3_array : cubic hermite interpolation for an array of points
//
// Uses derivative_hack to find derivatives.
//
//
// kx, ky (in):  arrays of knots
// nk (in):      number of knots
// sx (in):      evaluation points array
// sy (out):     spline values at evaluation pts sx.  Must already be allocated.
// ns (in):      number of evaluation points
*/
int
hermite3_array(const double *kx, const double *ky, long nk, double *sx,
double *sy, long ns)
{
  register long xi;
  double *kyd;

  if((kyd=MY_CALLOC(nk, double))==NULL)
    return 1;

  /* Test bounds. */
  /* As of 18jul94, this test was triggering for cases
  // where the bounds were nearly equal, but slightly out of range, in
  // which case the spline should work anyway, which is why I let it run
  // even if the spline abcissas are out of range.
  */
  if((sx[0] < kx[0]) || (sx[ns-1] > kx[nk-1])) {
    if(!NEAR(sx[ns-1], kx[nk-1])) {
      fprintf(stderr, "hermite3_array: out of range:\n");
      fprintf(stderr,
       "hermite3_array: eval=%.20g < knot=%.20g | %.20g>%.20g\n",
        sx[0], kx[0], sx[ns-1], kx[nk-1]);
    }
  }

  /* Find array of derivatives */
  derivative_hack(kx, ky, kyd, nk);

  /* Evaluate the spline */
  for(xi=0; xi<ns; xi++) {
    sy[xi]=hermite3_interp(sx[xi], kx, ky, kyd, nk, NULL, FALSE, NULL, NULL);
  }

  /* Free the derivatives array */
  FREE(kyd);

  return 0;
}