spline.h

00001 /*************************************************************************************
00002  * MechSys - A C++ library to simulate (Continuum) Mechanical Systems                *
00003  * Copyright (C) 2005 Dorival de Moraes Pedroso <dorival.pedroso at gmail.com>       *
00004  * Copyright (C) 2005 Raul Dario Durand Farfan  <raul.durand at gmail.com>           *
00005  *                                                                                   *
00006  * This file is part of MechSys.                                                     *
00007  *                                                                                   *
00008  * MechSys is free software; you can redistribute it and/or modify it under the      *
00009  * terms of the GNU General Public License as published by the Free Software         *
00010  * Foundation; either version 2 of the License, or (at your option) any later        *
00011  * version.                                                                          *
00012  *                                                                                   *
00013  * MechSys is distributed in the hope that it will be useful, but WITHOUT ANY        *
00014  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A   *
00015  * PARTICULAR PURPOSE. See the GNU General Public License for more details.          *
00016  *                                                                                   *
00017  * You should have received a copy of the GNU General Public License along with      *
00018  * MechSys; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, *
00019  * Fifth Floor, Boston, MA 02110-1301, USA                                           *
00020  *************************************************************************************/
00021 
00022 #ifndef MECHSYS_SPLINE_H
00023 #define MECHSYS_SPLINE_H
00024 
00025 #ifdef HAVE_CONFIG_H
00026   #include "config.h"
00027 #else
00028   #ifndef REAL
00029     #define REAL double
00030   #endif
00031 #endif
00032 
00033 #define H_ZERO 1.0e-4
00034 
00035 #include "util/exception.h"
00036 #include "util/numstreams.h"
00037 
00038 using Util::_4;
00039 using Util::_6_3;
00040 
00041 using std::cout;
00042 using std::endl;
00043 
00044 class Spline
00045 {
00046     friend std::ostream & operator<< (std::ostream & os, Spline const & S);
00047 public:
00048     // Constructor & Destructor
00049      Spline (REAL const X[], REAL const Y[], int Size);
00050     ~Spline ();
00051     // Methods
00052     REAL Eval       (REAL x) const;
00053     bool CheckRange (REAL x) const;
00054     REAL YRange     ()       const;
00055 private:
00056     int    _n;
00057     REAL * _x; // size == _n
00058     REAL * _a; // size == _n
00059     REAL * _b; // size == _n - 1
00060     REAL * _c; // size == _n
00061     REAL * _d; // size == _n - 1
00062 }; // class Spline
00063 
00064 
00066 
00067 
00068 inline Spline::Spline(REAL const X[], REAL const Y[], int Size) // {{{
00069     : _n (Size)
00070 {
00071     // Check
00072     if (_n<2) throw new Fatal(_("Spline::Spline: The size or arrays (%d) must be 2 or greater"), _n);
00073 
00074     // Allocate internal arrays
00075     _x = new REAL [_n];
00076     _a = new REAL [_n];
00077     _b = new REAL [_n-1];
00078     _c = new REAL [_n];
00079     _d = new REAL [_n-1];
00080 
00081     // Initialize arrays (x must be increasing)
00082     if (X[_n-1]<X[0]) // X decreasing
00083     {
00084         for (int i=0; i<_n; ++i)
00085         {
00086             _x[_n-1-i] = X[i];
00087             _a[_n-1-i] = Y[i];
00088         }
00089     }
00090     else
00091     {
00092         for (int i=0; i<_n; ++i)
00093         {
00094             _x[i] = X[i];
00095             _a[i] = Y[i];
00096         }
00097     }
00098 
00099     // Allocate temporary arrays
00100     REAL * h = new REAL [_n-1];
00101     REAL * A = new REAL [_n-1];
00102     REAL * l = new REAL [_n  ];
00103     REAL * m = new REAL [_n-1];
00104     REAL * z = new REAL [_n  ];
00105 
00106     // Calculate alpha (A)
00107     A[0] = 0.0; // not used
00108     for (int i=0; i<_n-1; ++i)
00109     {
00110         h[i] = _x[i+1] - _x[i];
00111         if (fabs(h[i])<H_ZERO) throw new Fatal(_("Spline::Spline: h == 0"));
00112         if (i>0)
00113             A[i] = 3.0*(_a[i+1]-_a[i])/h[i] - 3.0*(_a[i]-_a[i-1])/h[i-1];
00114     }
00115 
00116     // Solve tridiagonal system by Crout Factorization method
00117     l[0] = 1.0;
00118     m[0] = 0.0;
00119     z[0] = 0.0;
00120     for (int i=1; i<_n-1; ++i)
00121     {
00122         l[i] = 2.0*(_x[i+1]-_x[i-1]) - h[i-1]*m[i-1];
00123         m[i] = h[i]/l[i];
00124         z[i] = (A[i]-h[i-1]*z[i-1])/l[i];
00125     }
00126      l[_n-1] = 1.0;
00127      z[_n-1] = 0.0;
00128     _c[_n-1] = 0.0;
00129     for (int i=_n-2; i>=0; --i)
00130     {
00131         _c[i] = z[i] - m[i]*_c[i+1];
00132         _b[i] = (_a[i+1]-_a[i])/h[i] - h[i]*(_c[i+1]+2.0*_c[i])/3.0;
00133         _d[i] = (_c[i+1]-_c[i])/(3.0*h[i]);
00134     }
00135 
00136     // Clean up
00137     delete [] h;
00138     delete [] A;
00139     delete [] l;
00140     delete [] m;
00141     delete [] z;
00142 
00143 } // }}}
00144 
00145 inline Spline::~Spline() // {{{
00146 {
00147     delete [] _x;
00148     delete [] _a;
00149     delete [] _b;
00150     delete [] _c;
00151     delete [] _d;
00152 } // }}}
00153 
00154 inline REAL Spline::Eval(REAL x) const // {{{
00155 {
00156     // Find bounds for x
00157     int k;
00158     int lo = 0;
00159     int hi = _n-1;
00160     while (hi-lo>1)
00161     {
00162         k = (hi+lo) >> 1;
00163         if (_x[k]>x) hi = k;
00164         else         lo = k;
00165     }
00166 
00167     // Check
00168     //std::cout << "x_lo=" << _x[lo] << "  x=" << x << "  x_hi=" << _x[hi] << std::endl;
00169     if (x<_x[lo]) throw new Fatal(_("Spline::Eval: Value (x=%.6f < %.6f) is not valid"), x, _x[lo]);
00170     if (x>_x[hi]) throw new Fatal(_("Spline::Eval: Value (x=%.6f > %.6f) is not valid"), x, _x[hi]);
00171 
00172     // Interpolate
00173     REAL h = x-_x[lo];
00174     return _a[lo] + _b[lo]*h + _c[lo]*h*h + _d[lo]*h*h*h;
00175 
00176 } // }}}
00177 
00178 inline bool Spline::CheckRange(REAL x) const // {{{
00179 {
00180     if (x<_x[0]   ) return false;
00181     if (x>_x[_n-1]) return false;
00182     return true;
00183 } // }}}
00184 
00185 inline REAL Spline::YRange() const // {{{
00186 {
00187     return _a[_n-1]-_a[0];
00188 } // }}}
00189 
00190 std::ostream & operator<< (std::ostream & os, Spline const & S) // {{{
00191 {
00192     os << _4()<< "i" << _6_3()<< "x" << _6_3()<< "a" << _6_3()<< "b" << _6_3()<< "c" << _6_3()<< "d" << std::endl;
00193     for (int i=0; i<S._n; ++i)
00194     {
00195         os << _4()<< i << _6_3()<< S._x[i] << _6_3()<< S._a[i];
00196         if (i<S._n-1) os << _6_3()<< S._b[i] << _6_3()<< S._c[i] << _6_3()<< S._d[i] << std::endl;
00197         else os << std::endl;
00198     }
00199     return os;
00200 } // }}}
00201 
00202 #endif // MECHSYS_SPLINE_H
00203 
00204 // vim:fdm=marker

Generated on Wed Jan 24 15:56:27 2007 for MechSys by  doxygen 1.4.7