Gowdy solver
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
numMethods/cubicSpline.h
Go to the documentation of this file.
00001 /**
00002  *  @file      cubicSpline.h
00003  *  @brief     The natural cubic spline of degree 3 with continuity C2.
00004  *  @author    Mikica Kocic
00005  *  @copyright GNU General Public License (GPLv3).
00006  */
00007 
00008 /////////////////////////////////////////////////////////////////////////////////////////
00009 /** @defgroup g11 Numerical Methods                                                    */
00010 /////////////////////////////////////////////////////////////////////////////////////////
00011                                                                                    /*@{*/
00012 /** CubicSpline encapsulates the natural cubic spline of degree 3 with continuity C2.
00013  *  (Natural means that the second derivatives of the spline polynomials are set
00014  *  equal to zero at the endpoints of the interval of interpolation.)
00015  *
00016  *  Input: a set of N = k+1 coordinates.
00017  *  Output: a spline as a set of polynomial pieces.
00018  *
00019  *  @see <a href="https://en.wikipedia.org/wiki/Spline_(mathematics)">
00020  *       Algorithm for computing natural cubic splines </a>
00021  *  @see <a href="http://mathfaculty.fullerton.edu/mathews/n2003/CubicSplinesMod.html">
00022  *       Cubic splines module </a>
00023  *  @see Mathmatica notebook `Natural cubic spline.nb` used for tests
00024  */
00025 class CubicSpline
00026 {
00027     Int  k;              //!< Dimension: k+1 points
00028     VecReal x;           //!< The intervals: x[0]..x[1], x[1]..x[2], ...
00029     VecReal a, b, c, d;  //!< The polynomial coefficients, i = 0,...,k-1
00030 
00031     VecReal h, alp, l, z, mu; // Temporary
00032 
00033 public:
00034 
00035     /** Constructor. Only allocates memory for the arrays.
00036      */
00037     CubicSpline( Int N )
00038         : k( N - 1 )
00039         , x(N), a(N), b(N), c(N), d(N)
00040         , h(N), alp(N), l(N), z(N), mu(N)
00041     {}
00042 
00043     /** Calculates the spline based on the endpoints of the interval of interpolation.
00044      */
00045     void initialize( Real pts[][2] )
00046     {
00047         for( Int i = 0; i < k + 1; ++i ) {
00048             x[i] = pts[i][0];
00049             a[i] = pts[i][1];
00050         }
00051 
00052         // Calculate the differences
00053 
00054         for( Int i = 0; i < k; ++i ) {
00055             h[i] = x[i+1] - x[i];
00056         }
00057 
00058         for( Int i = 1; i < k; ++i ) {
00059             alp[i] =  3 * ( a[i+1] - a[i] ) / h[i] - 3 * ( a[i] - a[i-1] ) / h[i-1];
00060         }
00061 
00062         // Solve the tridiagonal linear equation (Crout's factorization)
00063 
00064         l[0] = 1;  mu[0] = z[0] = 0;
00065 
00066         for( Int i = 1; i < k; ++i ) {
00067             l[i] = 2 * ( x[i+1] - x[i-1] ) - h[i-1] * mu[i-1];
00068             mu[i] = h[i] / l[i];
00069             z[i] = ( alp[i] - h[i-1] * z[i-1] ) / l[i];
00070         }
00071 
00072         // Compute the polynomial coefficients
00073 
00074         l[k] = 1;  z[k] = c[k] = 0;
00075 
00076         for( Int j = k - 1; j >= 0; --j ) {
00077             c[j] = z[j] - mu[j] * c[j+1];
00078             b[j] = ( a[j+1] - a[j] ) / h[j] - h[j] * ( c[j+1] + 2 * c[j] ) / 3;
00079             d[j] = ( c[j+1] - c[j] ) / ( 3 * h[j] );
00080         }
00081     }
00082 
00083     /** Dumps the polynomial coefficients
00084      */
00085     void dump ()
00086     {
00087         std::cout << "Polynomial coefficients:" << std::endl << std::endl;
00088 
00089         for( Int i = 0; i < k; ++i ) {
00090             std::cout << a[i] << "\t" << b[i] << "\t" << c[i] << "\t" << d[i]
00091                  << " x-range " << x[i] << " .. " << x[i+1] << std::endl;
00092         }
00093     }
00094     /** Returns a value approximated by the cubic splice.
00095      */
00096     Real operator()( Real v )
00097     {
00098         // Find the polynomial. The polynomial index i goes from 0 to k-1.
00099         // The interval where the polynomial is valid is x[i-1]..x[i]
00100         //
00101         Int i = 0;
00102         while( i < k - 1 && v >= x[i+1] ) {
00103             ++i;
00104         }
00105 
00106         // The interval has not been found. Use the last polynomial for approximation.
00107         if ( i >= k - 1 ) {
00108             i = k - 1;
00109         }
00110 
00111         v -= x[i]; // Subtract the x-value from the reference value
00112 
00113         return a[i] + v * ( b[i] + v * ( c[i] + v * d[i] ) );
00114     }
00115 };
00116 
00117 void CubicSpline_sanityCheck ()
00118 {
00119     Real pts[5][2] =
00120     {
00121         {0.005,   4.892186615295462}, {0.045, 44.02967953765916},
00122         {0.105, 102.7359189212047  }, {0.145, 40.74442799816186},
00123         {0.195,  10.719645882407347}
00124     };
00125 
00126     CubicSpline ncs( 5 );
00127     ncs.initialize( pts );
00128     ncs.dump ();
00129 
00130     for( Real x = 0; x < 0.2001; x += 0.01 ) {
00131         std::cout << x << "\t" << ncs( x ) << std::endl;
00132     }
00133 }
00134                                                                                    /*@}*/
00135 /////////////////////////////////////////////////////////////////////////////////////////