| [2727] | 1 | //
 | 
|---|
 | 2 | // C++ Implementation: CubicSplineInterpolator1D
 | 
|---|
 | 3 | //
 | 
|---|
 | 4 | // Description:
 | 
|---|
 | 5 | //
 | 
|---|
 | 6 | //
 | 
|---|
 | 7 | // Author: Takeshi Nakazato <takeshi.nakazato@nao.ac.jp>, (C) 2012
 | 
|---|
 | 8 | //
 | 
|---|
 | 9 | // Copyright: See COPYING file that comes with this distribution
 | 
|---|
 | 10 | //
 | 
|---|
 | 11 | //
 | 
|---|
 | 12 | #include <assert.h>
 | 
|---|
 | 13 | 
 | 
|---|
 | 14 | #include <iostream>
 | 
|---|
 | 15 | using namespace std;
 | 
|---|
 | 16 | 
 | 
|---|
 | 17 | #include "CubicSplineInterpolator1D.h"
 | 
|---|
 | 18 | 
 | 
|---|
 | 19 | namespace asap {
 | 
|---|
 | 20 | 
 | 
|---|
 | 21 | CubicSplineInterpolator1D::CubicSplineInterpolator1D()
 | 
|---|
 | 22 |   : Interpolator1D(),
 | 
|---|
 | 23 |     y2_(0),
 | 
|---|
 | 24 |     ny2_(0),
 | 
|---|
 | 25 |     reusable_(false)
 | 
|---|
 | 26 | {}
 | 
|---|
 | 27 | 
 | 
|---|
 | 28 | CubicSplineInterpolator1D::~CubicSplineInterpolator1D()
 | 
|---|
 | 29 | {
 | 
|---|
 | 30 |   if (y2_) 
 | 
|---|
 | 31 |     delete[] y2_;
 | 
|---|
 | 32 | }
 | 
|---|
 | 33 | 
 | 
|---|
| [2730] | 34 | void CubicSplineInterpolator1D::setData(double *x, float *y, unsigned int n)
 | 
|---|
 | 35 | {
 | 
|---|
 | 36 |   Interpolator1D::setData(x, y, n);
 | 
|---|
 | 37 |   reusable_ = false;
 | 
|---|
 | 38 | }
 | 
|---|
 | 39 | 
 | 
|---|
| [2727] | 40 | void CubicSplineInterpolator1D::setY(float *y, unsigned int n)
 | 
|---|
 | 41 | {
 | 
|---|
 | 42 |   Interpolator1D::setY(y, n);
 | 
|---|
 | 43 |   reusable_ = false;
 | 
|---|
 | 44 | }
 | 
|---|
 | 45 | 
 | 
|---|
 | 46 | float CubicSplineInterpolator1D::interpolate(double x)
 | 
|---|
 | 47 | {
 | 
|---|
 | 48 |   assert(isready());
 | 
|---|
 | 49 |   if (n_ == 1)
 | 
|---|
 | 50 |     return y_[0];
 | 
|---|
 | 51 | 
 | 
|---|
 | 52 |   unsigned int i = locator_->locate(x);
 | 
|---|
 | 53 | 
 | 
|---|
 | 54 |   // do not perform extrapolation
 | 
|---|
 | 55 |   if (i == 0) {
 | 
|---|
 | 56 |     return y_[i];
 | 
|---|
 | 57 |   }
 | 
|---|
 | 58 |   else if (i == n_) {
 | 
|---|
 | 59 |     return y_[i-1];
 | 
|---|
 | 60 |   }
 | 
|---|
 | 61 | 
 | 
|---|
 | 62 |   // determine second derivative of each point
 | 
|---|
 | 63 |   if (!reusable_) {
 | 
|---|
| [2730] | 64 |     evaly2();
 | 
|---|
| [2727] | 65 |     reusable_ = true;
 | 
|---|
 | 66 |   }
 | 
|---|
 | 67 | 
 | 
|---|
 | 68 |   // cubic spline interpolation
 | 
|---|
| [2730] | 69 |   float y = dospline(x, i);
 | 
|---|
| [2727] | 70 |   return y;
 | 
|---|
 | 71 | }
 | 
|---|
 | 72 | 
 | 
|---|
| [2730] | 73 | void CubicSplineInterpolator1D::evaly2()
 | 
|---|
| [2727] | 74 | {
 | 
|---|
 | 75 |   if (n_ > ny2_) {
 | 
|---|
 | 76 |     if (y2_) 
 | 
|---|
 | 77 |       delete[] y2_;
 | 
|---|
 | 78 |     y2_ = new float[n_];
 | 
|---|
 | 79 |     ny2_ = n_;
 | 
|---|
 | 80 |   }
 | 
|---|
 | 81 | 
 | 
|---|
 | 82 |   float *u = new float[ny2_-1];
 | 
|---|
| [2730] | 83 | 
 | 
|---|
 | 84 |   // Natural cubic spline.
 | 
|---|
| [2727] | 85 |   y2_[0] = 0.0;
 | 
|---|
| [2730] | 86 |   y2_[ny2_-1] = 0.0;
 | 
|---|
| [2727] | 87 |   u[0] = 0.0;
 | 
|---|
 | 88 | 
 | 
|---|
| [2730] | 89 |   // Solve tridiagonal system.
 | 
|---|
 | 90 |   // Here, tridiagonal matrix is decomposed to triangular matrix
 | 
|---|
 | 91 |   // u stores upper triangular components while y2_ stores 
 | 
|---|
 | 92 |   // right-hand side vector.
 | 
|---|
 | 93 |   double a1 = x_[1] - x_[0];
 | 
|---|
 | 94 |   double a2, bi;
 | 
|---|
| [2727] | 95 |   for (unsigned int i = 1; i < ny2_ - 1; i++) {
 | 
|---|
| [2730] | 96 |     a2 = x_[i+1] - x_[i];
 | 
|---|
 | 97 |     bi = 1.0 / (x_[i+1] - x_[i-1]);
 | 
|---|
 | 98 |     y2_[i] = 3.0 * bi * ((y_[i+1] - y_[i]) / a2 - (y_[i] - y_[i-1]) / a1 
 | 
|---|
 | 99 |                          - y2_[i-1] * 0.5 * a1);
 | 
|---|
 | 100 |     a1 = 1.0 / (1.0 - u[i-1] * 0.5 * a1 * bi);
 | 
|---|
 | 101 |     y2_[i] *= a1;
 | 
|---|
 | 102 |     u[i] = 0.5 * a2 * bi * a1;
 | 
|---|
 | 103 |     a1 = a2;
 | 
|---|
| [2727] | 104 |   }
 | 
|---|
| [2730] | 105 |   
 | 
|---|
 | 106 |   // Then, solve the system by backsubstitution and store solution 
 | 
|---|
 | 107 |   // vector to y2_.
 | 
|---|
| [2727] | 108 |   for (int k = ny2_ - 2; k >= 0; k--)
 | 
|---|
| [2730] | 109 |     y2_[k] -= u[k] * y2_[k+1];
 | 
|---|
| [2727] | 110 | 
 | 
|---|
 | 111 |   delete[] u;
 | 
|---|
 | 112 | }
 | 
|---|
 | 113 | 
 | 
|---|
| [2730] | 114 | float CubicSplineInterpolator1D::dospline(double x, unsigned int i)
 | 
|---|
| [2727] | 115 | {
 | 
|---|
 | 116 |   unsigned int j = i - 1;
 | 
|---|
 | 117 |   double h = x_[i] - x_[j];
 | 
|---|
 | 118 |   double a = (x_[i] - x) / h;
 | 
|---|
 | 119 |   double b = (x - x_[j]) / h;
 | 
|---|
 | 120 |   float y = a * y_[j] + b * y_[i] + 
 | 
|---|
 | 121 |     ((a * a * a - a) * y2_[j] + (b * b * b - b) * y2_[i]) * (h * h) / 6.0;
 | 
|---|
 | 122 |   return y;
 | 
|---|
 | 123 | }
 | 
|---|
 | 124 | 
 | 
|---|
 | 125 | }
 | 
|---|