Canoe
Comprehensive Atmosphere N' Ocean Engine
spline.c
Go to the documentation of this file.
1 #include <stdio.h>
2 #include <stdlib.h>
3 
4 #include "core.h"
5 #include "linalg.h"
6 
7 #define WITHOUT_PIVOTING 0
8 #define WITH_PIVOTING 1
9 
10 /*
11  * Cubic spline routine.
12  * Adapted from Numerical Recipes in C, p. 96.
13  * The tridiagonal system is solved with pivoting
14  * to avoid numerical instability.
15  * Assumes zero-offset arrays.
16  *
17  * NOTE: We stripe the data into one array with float_triplet to get
18  * a cache-aware memory layout.
19  */
20 
21 void spline(int n, struct float_triplet *table, double y1_bot, double y1_top) {
22  int j, jm1, jp1;
23  double dx_a, dx_b, dx_c, *a, *b, *c, *r, *y2;
24  /*
25  * The following are part of DEBUG_MILESTONE(.) statements:
26  */
27  int idbms = 0;
28  static char dbmsname[] = "spline";
29 
30  /*
31  * Check validity of n.
32  */
33  if (n < 3) {
34  fprintf(stderr, "**error:%s, n=%d < 3\n", dbmsname, n);
35  exit(1);
36  }
37 
38  /*
39  * Allocate memory.
40  */
41  a = (double *)malloc(n * sizeof(double));
42  b = (double *)malloc(n * sizeof(double));
43  c = (double *)malloc(n * sizeof(double));
44  r = (double *)malloc(n * sizeof(double));
45  y2 = (double *)malloc(n * sizeof(double));
46 
47  for (j = 0; j < n; j++) {
48  y2[j] = (table + j)->z;
49  }
50 
51  for (j = 0; j < n; j++) {
52  jm1 = j - 1;
53  jp1 = j + 1;
54  if (jm1 >= 0) {
55  dx_a = (table + j)->x - (table + jm1)->x;
56  if (dx_a <= 0.) {
57  fprintf(stderr, "**error:%s, x[%d]=%g x[%d]=%g\n", dbmsname, jm1,
58  (table + jm1)->x, j, (table + j)->x);
59  exit(1);
60  }
61  if (jp1 < n) {
62  dx_b = (table + jp1)->x - (table + jm1)->x;
63  if (dx_b <= 0.) {
64  fprintf(stderr, "**error:%s, x[%d]=%g x[%d]=%g\n", dbmsname, jm1,
65  (table + jm1)->x, jp1, (table + jp1)->x);
66  exit(1);
67  }
68  }
69  }
70  if (jp1 < n) {
71  dx_c = (table + jp1)->x - (table + j)->x;
72  if (dx_c <= 0.) {
73  fprintf(stderr, "**error:%s, x[%d]=%g x[%d]= %g\n", dbmsname, j,
74  (table + j)->x, jp1, (table + jp1)->x);
75  exit(1);
76  }
77  }
78 
79  if (j == 0) {
80  if (y1_bot > 0.99e+30) {
81  y2[j] = 0.;
82  } else {
83  b[j] = dx_c / 3.;
84  c[j] = dx_c / 6.;
85  r[j] = ((table + jp1)->y - (table + j)->y) / dx_c - y1_bot;
86  }
87  } else if (j == n - 1) {
88  if (y1_top > 0.99e+30) {
89  y2[j] = 0.;
90  } else {
91  a[j] = dx_a / 6.;
92  b[j] = dx_a / 3.;
93  r[j] = y1_top - ((table + j)->y - (table + jm1)->y) / dx_a;
94  }
95  } else {
96  a[j] = dx_a / 6.;
97  b[j] = dx_b / 3.;
98  c[j] = dx_c / 6.;
99  r[j] = ((table + jp1)->y - (table + j)->y) / dx_c -
100  ((table + j)->y - (table + jm1)->y) / dx_a;
101  }
102  }
103 
104  if (y1_bot > 0.99e+30) {
105  if (y1_top > 0.99e+30) {
106  /* y2 = 0 on both ends. */
107  tridiag(n - 2, a + 1, b + 1, c + 1, r + 1, y2 + 1, WITH_PIVOTING);
108  } else {
109  /* y2 = 0 at start. */
110  tridiag(n - 1, a + 1, b + 1, c + 1, r + 1, y2 + 1, WITH_PIVOTING);
111  }
112  } else {
113  if (y1_top > 0.99e+30) {
114  /* y2 = 0 at end. */
115  tridiag(n - 1, a, b, c, r, y2, WITH_PIVOTING);
116  } else {
117  /* y2 needed at both ends */
118  tridiag(n, a, b, c, r, y2, WITH_PIVOTING);
119  }
120  }
121 
122  for (j = 0; j < n; j++) {
123  (table + j)->z = y2[j];
124  }
125 
126  /*
127  * Free allocated memory.
128  */
129  free(y2);
130  free(r);
131  free(c);
132  free(b);
133  free(a);
134 
135  return;
136 }
137 
138 /*======================= end of spline() ===================================*/
139 
140 /*======================= splint() ==========================================*/
141 
142 /*
143  * Evaluates cubic-spline interpolations.
144  * This version assumes you have already found the correct position
145  * in the tables, unlike the Numerical Recipes version.
146  * The function find_place_in_table() may be used to find the position.
147  *
148  * NOTE: We stripe the data into one array with float_triplet to get
149  * a cache-aware memory layout.
150  */
151 
152 double splint(double xx, struct float_triplet *table, double dx) {
153  double a, b, ans;
154 
155  a = ((table + 1)->x - xx) / dx;
156  b = (xx - table->x) / dx;
157 
158  ans = a * table->y + b * (table + 1)->y +
159  ((a * a * a - a) * (table)->z + (b * b * b - b) * (table + 1)->z) * dx *
160  dx / 6;
161 
162  return ans;
163 }
164 
165 /*======================= end of splint() ===================================*/
void tridiag(int n, double *a, double *b, double *c, double *r, double *u, int pivot_type)
Definition: tridiag.c:25
#define WITH_PIVOTING
Definition: spline.c:8
double splint(double xx, struct float_triplet *table, double dx)
Definition: spline.c:152
void spline(int n, struct float_triplet *table, double y1_bot, double y1_top)
Definition: spline.c:21
double y
Definition: core.h:11
double x
Definition: core.h:11