$treeview $search $mathjax
Palabos  Version 1.1
$projectbrief
$projectbrief
$searchbox

spline.hh

Go to the documentation of this file.
00001 /* This file is part of the Palabos library.
00002  *
00003  * Copyright (C) 2011 FlowKit Sarl
00004  * Avenue de Chailly 23
00005  * 1012 Lausanne, Switzerland
00006  * E-mail contact: contact@flowkit.com
00007  *
00008  * The most recent release of Palabos can be downloaded at 
00009  * <http://www.palabos.org/>
00010  *
00011  * The library Palabos is free software: you can redistribute it and/or
00012  * modify it under the terms of the GNU Affero General Public License as
00013  * published by the Free Software Foundation, either version 3 of the
00014  * License, or (at your option) any later version.
00015  *
00016  * The library is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  * GNU Affero General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU Affero General Public License
00022  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
00023 */
00024 
00025 #ifndef SPLINE_HH
00026 #define SPLINE_HH
00027 
00028 #include "core/runTimeDiagnostics.h"
00029 #include "core/util.h"
00030 #include "spline.h"
00031 #include <cstdio>
00032 #include <limits>
00033 
00034 namespace plb {
00035 
00036 template<typename T>
00037 Spline<T>::Spline(std::string fname)
00038 { 
00039     FILE *fp = fopen(fname.c_str(), "r");
00040     PLB_ASSERT(fp != NULL);
00041 
00042     long double tmp0, tmp1;
00043     while (!feof(fp))
00044         if (fscanf(fp, "%Lf%Lf", &tmp0, &tmp1) != EOF) {
00045             x.push_back((T) tmp0);
00046             y.push_back((T) tmp1);
00047         }
00048 
00049     fclose(fp);
00050 
00051     PLB_ASSERT(x.size() == y.size());
00052 #ifdef PLB_DEBUG
00053     T eps = 100.0 * std::numeric_limits<T>::epsilon();
00054     for (plint i = 1; i < (plint) x.size(); i++)
00055         if (x[i] < x[i - 1] || util::fpequal(x[i], x[i - 1], eps)) {
00056                 plbLogicError("The abscissa of the interpolation points must be monotonically increasing.");
00057         }
00058 #endif // PLB_DEBUG
00059 }
00060 
00061 template<typename T>
00062 Spline<T>::Spline(std::vector<T> const& x_, std::vector<T> const& y_)
00063     : x(x_),
00064       y(y_)
00065 { 
00066     PLB_ASSERT(x.size() == y.size());
00067 #ifdef PLB_DEBUG
00068     T eps = 100.0 * std::numeric_limits<T>::epsilon();
00069     for (plint i = 1; i < (plint) x.size(); i++)
00070         if (x[i] < x[i - 1] || util::fpequal(x[i], x[i - 1], eps)) {
00071                 plbLogicError("The abscissa of the interpolation points must be monotonically increasing.");
00072         }
00073 #endif // PLB_DEBUG
00074 }
00075 
00076 template<typename T>
00077 NaturalCubicSpline<T>::NaturalCubicSpline(std::string fname)
00078     : Spline<T>(fname)
00079 { 
00080     icache = 0;
00081     constructSpline();
00082 }
00083 
00084 template<typename T>
00085 NaturalCubicSpline<T>::NaturalCubicSpline(std::vector<T> const& x_, std::vector<T> const& y_)
00086     : Spline<T>(x_, y_)
00087 { 
00088     icache = 0;
00089     constructSpline();
00090 }
00091 
00092 template<typename T>
00093 NaturalCubicSpline<T>* NaturalCubicSpline<T>::clone() const {
00094     return new NaturalCubicSpline<T>(*this);
00095 }
00096 
00097 template<typename T>
00098 void NaturalCubicSpline<T>::constructSpline()
00099 {
00100     std::vector<T> const& x = this->getAbscissae();
00101     std::vector<T> const& y = this->getOrdinates();
00102     plint n = (plint) x.size();
00103     PLB_ASSERT( n>=2 );
00104     std::vector<T> a1(n-1), a2(n-1), a3(n), a4(n), a5(n);
00105 
00106     y1.resize(n-1);
00107     y2.resize(n);
00108     y3.resize(n-1);
00109 
00110     // Calculate the spline coefficients for polynomials of the form:
00111     // S_j(x) = y_j + y1_j * (x - x_j) + y2_j * (x - x_j)^2 + y3_j * (x - x_j)^3 
00112 
00113     for (plint i = 0; i < n - 1; i++)
00114         a1[i] = x[i + 1] - x[i];
00115 
00116     for (plint i = 1; i < n - 1; i++)
00117         a2[i] = 3.0 * (y[i + 1] - y[i]) / a1[i] - 3.0 * (y[i] - y[i - 1]) / a1[i - 1];
00118 
00119     a3[0] = 1.0;
00120     a4[0] = 0.0;
00121     a5[0] = 0.0;
00122 
00123     for (plint i = 1; i < n - 1; i++) {
00124         a3[i] = 2.0 * (x[i + 1] - x[i - 1]) - a1[i - 1] * a4[i - 1];
00125         a4[i] = a1[i] / a3[i];
00126         a5[i] = (a2[i] - a1[i - 1] * a5[i - 1]) / a3[i];
00127     }
00128 
00129     a3[n - 1] = 1.0;
00130     a5[n - 1] = 0.0;
00131     y2[n - 1] = 0.0;
00132 
00133     for (plint i = n - 2; i > -1; i--) {
00134         y2[i] = a5[i] - a4[i] * y2[i + 1];
00135         y1[i] = (y[i + 1] - y[i]) / a1[i] - a1[i] * (y2[i + 1] + 2.0 * y2[i]) / 3.0;
00136         y3[i] = (y2[i + 1] - y2[i]) / (3.0 * a1[i]);
00137     }
00138 
00139     y2.resize(n-1);
00140 }
00141 
00142 // return an index i in the range from il to ih for which x[i] <= t < x[i + 1]
00143 template<typename T>
00144 plint NaturalCubicSpline<T>::bsrch(T t, plint il, plint ih) const
00145 {
00146     std::vector<T> const& x = this->getAbscissae();
00147     plint ilo = il;
00148     plint ihi = ih;
00149 
00150     plint i;
00151     while (ihi > (ilo + 1)) {
00152         i = (ihi + ilo) / 2;
00153 
00154         if (x[i] > t)
00155             ihi = i;
00156         else
00157             ilo = i;
00158     }
00159 
00160     return ilo;
00161 }
00162 
00163 template<typename T>
00164 T NaturalCubicSpline<T>::getFunctionValue(T t) const
00165 {
00166     std::vector<T> const& x = this->getAbscissae();
00167     std::vector<T> const& y = this->getOrdinates();
00168     plint n = (plint) x.size();
00169     PLB_ASSERT( n>=1 );
00170 
00171 #ifdef PLB_DEBUG
00172     T x1 = x[0];
00173     T x2 = x[n-1];
00174     static T eps = 100.0 * std::numeric_limits<T>::epsilon();
00175     if ((t < x1 && !util::fpequal(t, x1, eps)) ||
00176         (t > x2 && !util::fpequal(t, x2, eps)))
00177         plbLogicError("Argument out of bounds.");
00178 #endif // PLB_DEBUG
00179 
00180     if (t < x[icache] || t >= x[icache + 1]) {
00181         if (t > x[icache]) {
00182             icache = bsrch(t, icache, n - 1);
00183         } else {
00184             icache = bsrch(t, 0, icache);
00185         }
00186     }
00187 
00188     T xtmp = t - x[icache];
00189     T ytmp = y[icache] + xtmp * (y1[icache] + xtmp * (y2[icache] + xtmp * (y3[icache])));
00190     return ytmp;
00191 }
00192 
00193 template<typename T>
00194 T NaturalCubicSpline<T>::getDerivativeValue(T t) const
00195 {
00196     std::vector<T> const& x = this->getAbscissae();
00197     plint n = (plint) x.size();
00198     PLB_ASSERT( n>=1 );
00199     T x1 = x[0];
00200     T x2 = x[n-1];
00201 
00202 #ifdef PLB_DEBUG
00203     static T eps = 100.0 * std::numeric_limits<T>::epsilon();
00204     if ((t < x1 && !util::fpequal(t, x1, eps)) ||
00205         (t > x2 && !util::fpequal(t, x2, eps)))
00206         plbLogicError("Argument out of bounds.");
00207 #endif // PLB_DEBUG
00208 
00209     if (t < x[icache] || t >= x[icache + 1]) {
00210         if (t > x[icache]) {
00211             icache = bsrch(t, icache, n - 1);
00212         } else {
00213             icache = bsrch(t, 0, icache);
00214         }
00215     }
00216 
00217     T xtmp = t - x[icache];
00218     T ydtmp = y1[icache] + xtmp * (2.0 * y2[icache] + xtmp * (3.0 * y3[icache]));
00219     return ydtmp;
00220 }
00221 
00222 template<typename T>
00223 T NaturalCubicSpline<T>::getSecondDerivativeValue(T t) const
00224 {
00225     std::vector<T> const& x = this->getAbscissae();
00226     plint n = (plint) x.size();
00227     PLB_ASSERT( n>=1 );
00228     T x1 = x[0];
00229     T x2 = x[n-1];
00230 
00231 #ifdef PLB_DEBUG
00232     static T eps = 100.0 * std::numeric_limits<T>::epsilon();
00233     if ((t < x1 && !util::fpequal(t, x1, eps)) ||
00234         (t > x2 && !util::fpequal(t, x2, eps)))
00235         plbLogicError("Argument out of bounds.");
00236 #endif // PLB_DEBUG
00237 
00238     if (t < x[icache] || t >= x[icache + 1]) {
00239         if (t > x[icache]) {
00240             icache = bsrch(t, icache, n - 1);
00241         } else {
00242             icache = bsrch(t, 0, icache);
00243         }
00244     }
00245 
00246     T xtmp = t - x[icache];
00247     T yd2tmp = 2.0 * y2[icache] + 6.0 * y3[icache] * xtmp;
00248     return yd2tmp;
00249 }
00250 
00251 template<typename T>
00252 T NaturalCubicSpline<T>::getThirdDerivativeValue(T t) const
00253 {
00254     std::vector<T> const& x = this->getAbscissae();
00255     plint n = (plint) x.size();
00256     PLB_ASSERT( n>=1 );
00257     T x1 = x[0];
00258     T x2 = x[n-1];
00259 
00260 #ifdef PLB_DEBUG
00261     static T eps = 100.0 * std::numeric_limits<T>::epsilon();
00262     if ((t < x1 && !util::fpequal(t, x1, eps)) ||
00263         (t > x2 && !util::fpequal(t, x2, eps)))
00264         plbLogicError("Argument out of bounds.");
00265 #endif // PLB_DEBUG
00266 
00267     if (t < x[icache] || t >= x[icache + 1]) {
00268         if (t > x[icache]) {
00269             icache = bsrch(t, icache, n - 1);
00270         } else {
00271             icache = bsrch(t, 0, icache);
00272         }
00273     }
00274 
00275     T yd3tmp = 6.0 * y3[icache];
00276     return yd3tmp;
00277 }
00278 
00279 template<typename T>
00280 T NaturalCubicSpline<T>::getIntegralValue() const
00281 {
00282     std::vector<T> const& x = this->getAbscissae();
00283     std::vector<T> const& y = this->getOrdinates();
00284     plint n = (plint) x.size();
00285 
00286     T integral = (T) 0;
00287     for (plint i = 0; i < n-1; i++) {
00288         T dx = x[i + 1] - x[i];
00289         integral += dx * (y[i] + dx * (y1[i] / 2.0 + dx * (y2[i] / 3.0 + dx * (y3[i] / 4.0))));
00290     } 
00291 
00292     return integral;
00293 }
00294 
00295 template<typename T>
00296 T NaturalCubicSpline<T>::getIntegralValue(T tmin, T tmax) const
00297 {
00298     static T eps = 100.0 * std::numeric_limits<T>::epsilon();
00299     std::vector<T> const& x = this->getAbscissae();
00300     std::vector<T> const& y = this->getOrdinates();
00301     plint n = (plint) x.size();
00302     T x1 = x[0];
00303     T x2 = x[n-1];
00304 
00305 #ifdef PLB_DEBUG
00306     if (tmin > tmax)
00307         plbLogicError("Invalid arguments.");
00308     if ((tmin < x1 && !util::fpequal(tmin, x1, eps)) ||
00309         (tmin > x2 && !util::fpequal(tmin, x2, eps)))
00310         plbLogicError("Argument out of bounds.");
00311     if ((tmax < x1 && !util::fpequal(tmax, x1, eps)) ||
00312         (tmax > x2 && !util::fpequal(tmax, x2, eps)))
00313         plbLogicError("Argument out of bounds.");
00314 #endif // PLB_DEBUG
00315 
00316     if (util::fpequal(tmin, tmax, eps))
00317         return ((T) 0);
00318 
00319     if (tmin < x[icache] || tmin >= x[icache + 1]) {
00320         if (tmin > x[icache]) {
00321             icache = bsrch(tmin, icache, n - 1);
00322         } else {
00323             icache = bsrch(tmin, 0, icache);
00324         }
00325     }
00326     plint imin = icache;
00327 
00328     if (tmax < x[icache] || tmax >= x[icache + 1]) {
00329         if (tmax > x[icache]) {
00330             icache = bsrch(tmax, icache, n - 1);
00331         } else {
00332             icache = bsrch(tmax, 0, icache);
00333         }
00334     }
00335     plint imax = icache;
00336 
00337     plint i;
00338     T dxmin, dxmax, integral;
00339 
00340     if (imin == imax) {
00341         i = imin;
00342         dxmin = tmin - x[i];
00343         dxmax = tmax - x[i];
00344         integral = y[i] * (tmax - tmin) +
00345             (y1[i]/2.0) * (dxmax*dxmax - dxmin*dxmin) +
00346             (y2[i]/3.0) * (dxmax*dxmax*dxmax - dxmin*dxmin*dxmin) +
00347             (y3[i]/4.0) * (dxmax*dxmax*dxmax*dxmax - dxmin*dxmin*dxmin*dxmin);
00348         return integral;
00349     }
00350 
00351     i = imin;
00352     dxmin = tmin - x[i];
00353     dxmax = x[i + 1] - x[i];
00354     integral = y[i] * (x[i + 1] - tmin) +
00355         (y1[i]/2.0) * (dxmax*dxmax - dxmin*dxmin) +
00356         (y2[i]/3.0) * (dxmax*dxmax*dxmax - dxmin*dxmin*dxmin) +
00357         (y3[i]/4.0) * (dxmax*dxmax*dxmax*dxmax - dxmin*dxmin*dxmin*dxmin);
00358 
00359     T dx;
00360     for (i = imin + 1; i < imax; i++) {
00361         dx = x[i + 1] - x[i];
00362         integral += dx * (y[i] + dx * (y1[i] / 2.0 + dx * (y2[i] / 3.0 + dx * (y3[i] / 4.0))));
00363     } 
00364 
00365     i = imax;
00366     dx = tmax - x[i];
00367     integral += dx * (y[i] + dx * (y1[i] / 2.0 + dx * (y2[i] / 3.0 + dx * (y3[i] / 4.0))));
00368 
00369     return integral;
00370 }
00371 
00372 }  // namespace plb
00373 
00374 #endif  // SPLINE_HH