cubic_spline.cxx

Go to the documentation of this file.
00001 #include <cxxtls/cubic_spline.h>
00002 #include <vector>
00003 
00004 namespace cxxtls
00005 {
00006 
00009 
00010 // this routine was originally fortran, I wrote it in the following
00011 // goofy way to keep the algorithm the same.  My arrays don't use
00012 // location 0 and the indexing thus runs from 1 to n like fortran.
00013 
00014 // This implementation of cubic spline came from the book
00015 //
00016 //  Numerical Computing:  an introduction
00017 //  by Shampine and Allen, 1973.
00018 
00019 // yes this file needs to be rewrite not to have to copy these arrays...
00020 
00021 void 
00022 cubic_spline::
00023 compute_coefficients()
00027 {
00028   using std::vector;
00029 
00030   dirty_ = false;
00031 
00032   size_t n = rep_.size();
00033 
00034   // copy the map to arrays, doh!
00035 
00036   vector<double> xn(n+1), fn(n+1), rho(n+1), tau(n+1), s(n+1); 
00037 
00038     {
00039       const_iterator first = rep_.begin(),
00040                                       last  = rep_.end();
00041 
00042       vector<double>::iterator xout = xn.begin() + 1;
00043       vector<double>::iterator yout = fn.begin() + 1;
00044 
00045       while(first != last)
00046       {
00047                  *xout++ = first->first;
00048                  *yout++ = first->second.y_;
00049 
00050                  ++first;
00051       }
00052 
00053     }
00054 
00055   // the two vectors, xn and fn are have undefined values in location 0
00056 
00057   size_t nm1 = n-1;
00058   
00059   rho[2] = 0;
00060   tau[2] = 0;
00061 
00062   int i;
00063 
00064   for(i=2; i <= static_cast<int>(nm1); ++i)
00065   {
00066     size_t iim1 = i-1;
00067     size_t ii   = i;
00068     size_t iip1 = i+1;
00069 
00070     double him1 = xn[ii] - xn[iim1];
00071     double hi   = xn[iip1]-xn[ii];
00072     double temp = (him1/hi)*(rho[i]+2)+2;
00073                                    
00074     rho[i+1]=-1.0/temp;
00075 
00076     double d = 6.0 *((fn[iip1]-fn[ii])/hi-(fn[ii]-fn[iim1])/him1)/hi;
00077 
00078     tau[i+1] = (d-him1*tau[i]/hi)/temp;
00079 
00080   }
00081 
00082   s[1] = 0;
00083   s[n] = 0;
00084 
00085   int nm2 = n-2;
00086 
00087   for(i=1; i <= nm2; ++i)
00088   {
00089     size_t ib = n-i;
00090     s[ib] = rho[ib+1] * s[ib+1] +tau[ib+1];
00091   }
00092 
00093   {
00094     vector<double>::iterator first = s.begin() + 1,
00095                                                       last  = s.end();
00096 
00097     rep_t::iterator output = rep_.begin();
00098 
00099     while(first != last)
00100     {
00101       output->second.s_ = *first++;
00102       ++output;
00103     }
00104 
00105   }
00106 
00107 
00108 }
00109 
00110 double 
00111 cubic_spline::
00112 evaluate(double x) const
00113 {
00114   using std::vector;
00115 
00116   if(dirty_)
00117   {
00118     cubic_spline* me = const_cast<cubic_spline*>(this);
00119     me->compute_coefficients();
00120   }
00121 
00122   size_t n = rep_.size();
00123   
00124   if(n == 0)
00125     return 0;
00126 
00127   if(rep_.size() == 1)
00128   {
00129     return rep_.begin()->second.y_;
00130   }
00131 
00132   if( x < rep_.begin()->first )
00133   {
00134     const_iterator lb = rep_.begin();
00135     const_iterator ub = lb; ++ub;
00136 
00137     double m = (ub->second.y_ - lb->second.y_) / 
00138                         (ub->first     - lb->first );
00139 
00140     double deltax = lb->first  - x;
00141     double deltay = m * deltax;
00142 
00143     return lb->second.y_ - deltay;
00144   }
00145 
00146   rep_t::const_iterator end = rep_.end(); --end;
00147 
00148   if( x >= end->first)
00149   {
00150     const_iterator ub = rep_.end(); --ub;
00151     const_iterator lb = ub; --lb;
00152 
00153     double m = (ub->second.y_ - lb->second.y_) / 
00154                         (ub->first     - lb->first );
00155 
00156     double deltax = x - ub->first ;
00157     double deltay = m * deltax;
00158 
00159     return ub->second.y_ + deltay;
00160   }
00161 
00162   const_iterator ilp1 = ceil(x);
00163   const_iterator il   = floor(x);
00164 
00165   double a = ilp1->first - x;
00166   double b = x - il->first;
00167   double h = ilp1->first - il->first;
00168 
00169   return  a * il->second.s_ * (a * a / h - h)/6.0 +
00170                    b * ilp1->second.s_ * (b * b / h - h)/6.0 +
00171                    ( a * il->second.y_ + b * ilp1->second.y_)/h;
00172 
00173 }
00174 
00175 cubic_spline::const_iterator
00176 cubic_spline::
00177 floor(double x) const
00178   //
00188 
00189 {
00190   const_iterator ub    = rep_.upper_bound(x);
00191   const_iterator begin = rep_.begin();
00192 
00193   while(ub != begin)
00194   {
00195     --ub;                    // at most one iteration is realistic
00196 
00197     if(ub->first <= x)
00198       return ub;
00199 
00200   }
00201 
00202   return rep_.end();
00203 
00204 }
00205 
00206 } // namespace cxxtls
Generated on Wed Feb 29 22:50:04 2012 for CXXUtilities by  doxygen 1.6.3