Object-oriented Scientific Computing Library: Version 0.910
interp.h
00001 /*
00002   -------------------------------------------------------------------
00003   
00004   Copyright (C) 2006-2012, Andrew W. Steiner
00005   
00006   This file is part of O2scl.
00007   
00008   O2scl is free software; you can redistribute it and/or modify
00009   it under the terms of the GNU General Public License as published by
00010   the Free Software Foundation; either version 3 of the License, or
00011   (at your option) any later version.
00012   
00013   O2scl is distributed in the hope that it will be useful,
00014   but WITHOUT ANY WARRANTY; without even the implied warranty of
00015   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016   GNU General Public License for more details.
00017   
00018   You should have received a copy of the GNU General Public License
00019   along with O2scl. If not, see <http://www.gnu.org/licenses/>.
00020 
00021   -------------------------------------------------------------------
00022 */
00023 #ifndef O2SCL_INTERP_H
00024 #define O2SCL_INTERP_H
00025 
00026 #include <iostream>
00027 #include <string>
00028 
00029 #include <o2scl/err_hnd.h>
00030 #include <o2scl/ovector_tlate.h>
00031 #include <o2scl/ovector_rev_tlate.h>
00032 #include <o2scl/search_vec.h>
00033 #include <o2scl/tridiag.h>
00034 
00035 #ifndef DOXYGENP
00036 namespace o2scl {
00037 #endif
00038   
00039   /** \brief Base low-level interpolation class [abstract base]
00040       
00041       For any pair of vectors \c x and \c y into which you would like
00042       to interpolate, you need to call allocate() and init() first,
00043       and then the interpolation functions, and then free(). If the
00044       next pair of vectors has the same size, then you need only to
00045       call init() before the next call to an interpolation function
00046       (you don't need to reallocate). If the \c x and \c y vectors do
00047       not change, then you may call the interpolation functions in
00048       succession.
00049 
00050       These interpolation class work so long as the vector \c x is
00051       either monotonically increasing or monotonically decreasing. All
00052       of the descendants give identical results to the GSL
00053       interpolation routines when the vector is monotonically
00054       increasing. 
00055   */
00056   template<class vec_t> class base_interp {
00057 
00058 #ifndef DOXYGEN_INTERNAL
00059 
00060   protected:
00061 
00062     /// To perform binary searches
00063     search_vec <vec_t> *sv;
00064     
00065     /// The size of the allocated \ref search_vec object
00066     size_t n_sv;
00067 
00068     /// True if memory has been allocated
00069     bool mem_alloc;
00070 
00071     /** \brief An internal function to assist in computing the 
00072         integral for both the cspline and Akima types
00073     */
00074     double integ_eval(double ai, double bi, double ci, double di, double xi, 
00075                       double a, double b) {
00076 
00077       const double r1=a-xi;
00078       const double r2=b-xi;
00079       const double r12=r1+r2;
00080       const double bterm=0.5*bi*r12;
00081       const double cterm=(1.0/3.0)*ci*(r1*r1+r2*r2+r1*r2);
00082       const double dterm=0.25*di*r12*(r1*r1+r2*r2);
00083       
00084       return (b-a)*(ai+bterm+cterm+dterm);
00085     }
00086 
00087 #endif
00088 
00089   public:
00090 
00091     // This empty constructor is required since the 
00092     // default copy constructor is private.
00093     base_interp() {
00094       sv=0;
00095       n_sv=0;
00096       mem_alloc=false;
00097     }
00098 
00099     virtual ~base_interp() {
00100       if (sv!=0) delete sv;
00101       if (mem_alloc) free();
00102     }
00103 
00104     /** \brief The minimum size of the vectors to interpolate between
00105 
00106         This needs to be set in the constructor of the children for
00107         access by the class user
00108     */
00109     size_t min_size;
00110 
00111     /// Allocate memory, assuming x and y have size \c size
00112     virtual int allocate(size_t size) { return 0; }
00113 
00114     /// Free allocated memory
00115     virtual int free() { return 0; }
00116 
00117     /// Initialize interpolation routine
00118     virtual int init(const vec_t &x, const vec_t &y, size_t size) {
00119       return 0;
00120     }
00121     
00122     /// Give the value of the function \f$ y(x=x_0) \f$ .
00123     virtual int interp(const vec_t &x, const vec_t &y, size_t size, 
00124                        double x0, double &y0)=0;
00125     
00126     /// Give the value of the derivative \f$ y^{\prime}(x=x_0) \f$ .
00127     virtual int deriv(const vec_t &x, const vec_t &y, size_t size,
00128                       double x0, double &dydx)=0;
00129     
00130     /** \brief Give the value of the second derivative 
00131         \f$ y^{\prime \prime}(x=x_0) \f$ .
00132     */
00133     virtual int deriv2(const vec_t &x, const vec_t &y, size_t size, 
00134                        double x0, double &d2ydx2)=0;
00135     
00136     /// Give the value of the integral \f$ \int_a^{b}y(x)~dx \f$ .
00137     virtual int integ(const vec_t &x, const vec_t &y, size_t size, 
00138                       double a, double b, double &result)=0;
00139 
00140     /// Return the type, \c "base_interp".
00141     virtual const char *type() { return "base_interp"; }
00142 
00143 #ifndef DOXYGEN_INTERNAL
00144 
00145   private:
00146 
00147     base_interp<vec_t>(const base_interp<vec_t> &);
00148     base_interp<vec_t>& operator=(const base_interp<vec_t>&);
00149 
00150 #endif
00151 
00152   };
00153   
00154   /** \brief Linear interpolation (GSL) 
00155 
00156       Linear interpolation requires no calls to allocate() or free()
00157       as there is no internal storage required.
00158   */
00159   template<class vec_t> class linear_interp : public base_interp<vec_t> {
00160     
00161   public:
00162     
00163     linear_interp() {
00164       this->min_size=2;
00165     }
00166 
00167     virtual ~linear_interp() {}
00168     
00169     /// Initialize interpolation routine
00170     virtual int init(const vec_t &x, const vec_t &y, size_t size) {
00171       if (this->sv!=0) delete this->sv;
00172       this->sv=new search_vec<vec_t>(size,x);
00173       return 0;
00174     }
00175     
00176     /// Give the value of the function \f$ y(x=x_0) \f$ .
00177     virtual int interp(const vec_t &x_array, const vec_t &y_array, 
00178                        size_t size, double x, double &y) {
00179 
00180       double x_lo, x_hi;
00181       double y_lo, y_hi;
00182       double dx;
00183       size_t index;
00184 
00185       index=this->sv->find(x);
00186       
00187       /* evaluate */
00188       x_lo=x_array[index];
00189       x_hi=x_array[index+1];
00190       y_lo=y_array[index];
00191       y_hi=y_array[index+1];
00192       dx=x_hi-x_lo;
00193 
00194       y=y_lo+(x-x_lo)/dx*(y_hi-y_lo);
00195       return gsl_success;
00196     }
00197     
00198     /// Give the value of the derivative \f$ y^{\prime}(x=x_0) \f$ .
00199     virtual int deriv(const vec_t &x_array, const vec_t &y_array, 
00200                       size_t size, double x, double &dydx) {
00201       
00202       double x_lo, x_hi;
00203       double y_lo, y_hi;
00204       double dx;
00205       double dy;
00206       size_t index;
00207       
00208       index=this->sv->find(x);
00209       
00210       /* evaluate */
00211       x_lo=x_array[index];
00212       x_hi=x_array[index+1];
00213       y_lo=y_array[index];
00214       y_hi=y_array[index+1];
00215       dx=x_hi-x_lo;
00216       dy=y_hi-y_lo;
00217 
00218       dydx=dy/dx;
00219       return gsl_success;
00220     }
00221 
00222     /** \brief Give the value of the second derivative  
00223         \f$ y^{\prime \prime}(x=x_0) \f$ (always zero)
00224     */
00225     virtual int deriv2(const vec_t &x, const vec_t &y, size_t size, 
00226                        double x0, double &d2ydx2) {
00227       d2ydx2=0.0;
00228       return gsl_success;
00229     }
00230 
00231     /// Give the value of the integral \f$ \int_a^{b}y(x)~dx \f$ .
00232     virtual int integ(const vec_t &x_array, const vec_t &y_array, 
00233                       size_t size, double a, double b, 
00234                       double &result) {
00235 
00236       size_t i, index_a, index_b;
00237       
00238       double tmp;
00239       bool flip=false;
00240       if ((x_array[0]<x_array[size-1] && a>b) ||
00241           (x_array[0]>x_array[size-1] && a<b)) {
00242         tmp=a;
00243         a=b;
00244         b=tmp;
00245         flip=true;
00246       }
00247 
00248       index_a=this->sv->find(a);
00249       index_b=this->sv->find(b);
00250       
00251       /* endpoints span more than one interval */
00252       
00253       result=0.0;
00254       
00255       /* interior intervals */
00256       for(i=index_a; i<=index_b; i++) {
00257         const double x_hi=x_array[i+1];
00258         const double x_lo=x_array[i];
00259         const double y_lo=y_array[i];
00260         const double y_hi=y_array[i+1];
00261         const double dx=x_hi-x_lo;
00262         
00263         if(dx != 0.0) {
00264           if (i == index_a || i == index_b) {
00265             double x1=(i == index_a) ? a : x_lo;
00266             double x2=(i == index_b) ? b : x_hi;
00267             const double D=(y_hi-y_lo)/dx;
00268             result += (x2-x1)*(y_lo+0.5*D*((x2-x_lo)+(x1-x_lo)));
00269           } else  {
00270             result += 0.5*dx*(y_lo+y_hi);
00271           }
00272         }
00273       }
00274       
00275       if (flip) result*=-1.0;
00276       return gsl_success;
00277     }
00278 
00279     /// Return the type, \c "linear_interp".
00280     virtual const char *type() { return "linear_interp"; }
00281 
00282 #ifndef DOXYGEN_INTERNAL
00283 
00284   private:
00285 
00286     linear_interp<vec_t>(const linear_interp<vec_t> &);
00287     linear_interp<vec_t>& operator=(const linear_interp<vec_t>&);
00288 
00289 #endif
00290 
00291   };
00292   
00293   /** \brief Cubic spline interpolation (GSL)
00294       
00295       By default, this class uses natural boundary conditions, where
00296       the second derivative vanishes at each end point. Extrapolation
00297       effectively assumes that the second derivative is linear outside
00298       of the endpoints. 
00299   */
00300   template<class vec_t> class cspline_interp : public base_interp<vec_t> {
00301     
00302 #ifndef DOXYGEN_INTERNAL
00303     
00304   protected:
00305 
00306     /// \name Storage for cubic spline interpolation
00307     //@{
00308     double *c;
00309     double *g;
00310     double *diag;
00311     double *offdiag;
00312     //@}
00313 
00314     /// Memory for the tridiagonalization
00315     o2scl_linalg::uvector_4_mem p4m;
00316 
00317     /// Compute coefficients for cubic spline interpolation
00318     void coeff_calc(const double c_array[], double dy, double dx, 
00319                     size_t index, double *b, double *c2, double *d) {
00320 
00321       const double c_i=c_array[index];
00322       const double c_ip1=c_array[index+1];
00323       *b=(dy/dx)-dx*(c_ip1+2.0*c_i)/3.0;
00324       *c2=c_i;
00325       *d=(c_ip1-c_i)/(3.0*dx);
00326     }
00327 
00328 #endif
00329     
00330   public:
00331 
00332     /** \brief Create a base interpolation object with natural or
00333         periodic boundary conditions
00334     */
00335     cspline_interp() {
00336       this->min_size=3;
00337     }
00338 
00339     virtual ~cspline_interp() {}
00340 
00341     /// Allocate memory, assuming x and y have size \c size
00342     virtual int allocate(size_t size) {
00343       
00344       c=(double *)malloc(size*sizeof(double));
00345       if (c == 0) {
00346         O2SCL_ERR2_RET("Failed to allocate space for c",
00347                        " in cspline_interp::allocate().",gsl_enomem);
00348       }
00349       
00350       g=(double *)malloc(size*sizeof(double));
00351       if (g == 0) {
00352         std::free(c);
00353         O2SCL_ERR2_RET("Failed to allocate space for g",
00354                        " in cspline_interp::allocate().",gsl_enomem);
00355       }
00356       
00357       diag=(double *)malloc(size*sizeof(double));
00358       if (diag == 0) {
00359         std::free(g);
00360         std::free(c);
00361         O2SCL_ERR2_RET("Failed to allocate space for diag",
00362                        " in cspline_interp::allocate().",gsl_enomem);
00363       }
00364       
00365       offdiag=(double *)malloc(size*sizeof(double));
00366       if (offdiag == 0) {
00367         std::free(diag);
00368         std::free(g);
00369         std::free(c);
00370         O2SCL_ERR2_RET("Failed to allocate space for offdiag",
00371                        " in cspline_interp::allocate().",gsl_enomem);
00372       }
00373 
00374       p4m.allocate(size);
00375 
00376       this->mem_alloc=true;
00377       
00378       return 0;
00379     }
00380     
00381     /** \brief Initialize interpolation routine
00382      */
00383     virtual int init(const vec_t &xa, const vec_t &ya, size_t size) {
00384 
00385       if (this->mem_alloc==false) {
00386         O2SCL_ERR2_RET("Memory allocation not performed in ",
00387                        "cspline_interp::init().",gsl_efailed);
00388       }
00389 
00390       if (this->sv!=0) delete this->sv;
00391       this->sv=new search_vec<vec_t>(size,xa);
00392 
00393       /// Natural boundary conditions
00394 
00395       size_t i;
00396       size_t num_points=size;
00397       size_t max_index=num_points-1;
00398       size_t sys_size=max_index-1;
00399 
00400       c[0]=0.0;
00401       c[max_index]=0.0;
00402 
00403       for (i=0; i < sys_size; i++) {
00404         const double h_i=xa[i+1]-xa[i];
00405         const double h_ip1=xa[i+2]-xa[i+1];
00406         const double ydiff_i=ya[i+1]-ya[i];
00407         const double ydiff_ip1=ya[i+2]-ya[i+1];
00408         const double g_i=(h_i != 0.0) ? 1.0/h_i : 0.0;
00409         const double g_ip1=(h_ip1 != 0.0) ? 1.0/h_ip1 : 0.0;
00410         offdiag[i]=h_ip1;
00411         diag[i]=2.0*(h_ip1+h_i);
00412         g[i]=3.0*(ydiff_ip1*g_ip1- ydiff_i*g_i);
00413       }
00414 
00415       if (sys_size == 1) {
00416 
00417         c[1]= g[0]/ diag[0];
00418         return gsl_success;
00419 
00420       } else {
00421 
00422         double *cp1=c+1;
00423         o2scl_linalg::solve_tridiag_sym<double *,double *,double *,
00424           double *,o2scl_linalg::uvector_4_mem,uvector>
00425           (diag,offdiag,g,cp1,sys_size,p4m);
00426         return 0;
00427 
00428       }
00429     }
00430           
00431     /// Free allocated memory
00432     virtual int free() {
00433       p4m.free();
00434       std::free(c);
00435       std::free(g);
00436       std::free(diag);
00437       std::free(offdiag);
00438       this->mem_alloc=false;
00439       return 0;
00440     }
00441 
00442     /// Give the value of the function \f$ y(x=x_0) \f$ .
00443     virtual int interp(const vec_t &x_array, const vec_t &y_array, 
00444                        size_t size, double x, double &y) {
00445       
00446       double x_lo, x_hi;
00447       double dx;
00448       size_t index;
00449       
00450       index=this->sv->find(x);
00451   
00452       /* evaluate */
00453       x_hi=x_array[index+1];
00454       x_lo=x_array[index];
00455       dx=x_hi-x_lo;
00456 
00457       const double y_lo=y_array[index];
00458       const double y_hi=y_array[index+1];
00459       const double dy=y_hi-y_lo;
00460       double delx=x-x_lo;
00461       double b_i, c_i, d_i; 
00462       coeff_calc(c, dy, dx, index, &b_i, &c_i, &d_i);
00463       y=y_lo+delx*(b_i+delx*(c_i+delx*d_i));
00464       return gsl_success;
00465     }
00466 
00467     /// Give the value of the derivative \f$ y^{\prime}(x=x_0) \f$ .
00468     virtual int deriv(const vec_t &x_array, const vec_t &y_array, 
00469                       size_t size, double x, double &dydx) {
00470 
00471       double x_lo, x_hi;
00472       double dx;
00473       size_t index;
00474   
00475       index=this->sv->find(x);
00476   
00477       /* evaluate */
00478       x_hi=x_array[index+1];
00479       x_lo=x_array[index];
00480       dx=x_hi-x_lo;
00481 
00482       const double y_lo=y_array[index];
00483       const double y_hi=y_array[index+1];
00484       const double dy=y_hi-y_lo;
00485       double delx=x-x_lo;
00486       double b_i, c_i, d_i; 
00487       coeff_calc(c, dy, dx, index, &b_i, &c_i, &d_i);
00488       dydx=b_i+delx*(2.0*c_i+3.0*d_i*delx);
00489       return gsl_success;
00490     }
00491 
00492     /** \brief Give the value of the second derivative  
00493         \f$ y^{\prime \prime}(x=x_0) \f$ .
00494     */
00495     virtual int deriv2(const vec_t &x_array, const vec_t &y_array, 
00496                        size_t size, double x, double &d2ydx2) {
00497 
00498       double x_lo, x_hi;
00499       double dx;
00500       size_t index;
00501   
00502       index=this->sv->find(x);
00503   
00504       /* evaluate */
00505       x_hi=x_array[index+1];
00506       x_lo=x_array[index];
00507       dx=x_hi-x_lo;
00508 
00509       const double y_lo=y_array[index];
00510       const double y_hi=y_array[index+1];
00511       const double dy=y_hi-y_lo;
00512       double delx=x-x_lo;
00513       double b_i, c_i, d_i;
00514       coeff_calc(c, dy, dx, index, &b_i, &c_i, &d_i);
00515       d2ydx2=2.0*c_i+6.0*d_i*delx;
00516       return gsl_success;
00517     }
00518 
00519   public:
00520     
00521     /// Give the value of the integral \f$ \int_a^{b}y(x)~dx \f$ .
00522     virtual int integ(const vec_t &x_array, const vec_t &y_array, 
00523                       size_t size, double a, double b, double &result) {
00524 
00525       size_t i, index_a, index_b;
00526   
00527       double tmp;
00528       bool flip=false;
00529       if ((x_array[0]<x_array[size-1] && a>b) ||
00530           (x_array[0]>x_array[size-1] && a<b)) {
00531         tmp=a;
00532         a=b;
00533         b=tmp;
00534         flip=true;
00535       }
00536 
00537       index_a=this->sv->find(a);
00538       index_b=this->sv->find(b);
00539 
00540       result=0.0;
00541   
00542       /* interior intervals */
00543       for(i=index_a; i<=index_b; i++) {
00544 
00545         const double x_hi=x_array[i+1];
00546         const double x_lo=x_array[i];
00547         const double y_lo=y_array[i];
00548         const double y_hi=y_array[i+1];
00549         const double dx=x_hi-x_lo;
00550         const double dy=y_hi-y_lo;
00551 
00552         if(dx != 0.0) {
00553           double b_i, c_i, d_i; 
00554           coeff_calc(c, dy, dx, i, &b_i, &c_i, &d_i);
00555           if (i == index_a || i == index_b) {
00556             double x1=(i == index_a) ? a : x_lo;
00557             double x2=(i == index_b) ? b : x_hi;
00558             result += this->integ_eval(y_lo, b_i, c_i, d_i, x_lo, x1, x2);
00559           } else {
00560             result += dx*(y_lo+dx*(0.5*b_i+
00561                                    dx*(c_i/3.0+0.25*d_i*dx)));
00562           }
00563         } else {
00564           result=0.0;
00565           // We don't throw an error here so smart_interp classes can
00566           // attempt to recover.
00567           return gsl_failure;
00568         }
00569 
00570       }
00571   
00572       if (flip) result*=-1.0;
00573       return gsl_success;
00574     }
00575 
00576     /// Return the type, \c "cspline_interp".
00577     virtual const char *type() { return "cspline_interp"; }
00578 
00579 #ifndef DOXYGEN_INTERNAL
00580 
00581   private:
00582 
00583     cspline_interp<vec_t>(const cspline_interp<vec_t> &);
00584     cspline_interp<vec_t>& operator=(const cspline_interp<vec_t>&);
00585 
00586 #endif
00587 
00588   };
00589   
00590   /** \brief Cubic spline interpolation with periodic 
00591       boundary conditions (GSL)
00592   */
00593   template<class vec_t> class cspline_peri_interp : 
00594   public cspline_interp<vec_t> {
00595 
00596   protected:
00597 
00598     /// Desc
00599     o2scl_linalg::uvector_5_mem p5m;
00600     
00601   public:
00602     
00603   cspline_peri_interp() : cspline_interp<vec_t>() {
00604       this->min_size=3;
00605     }
00606       
00607     virtual ~cspline_peri_interp() {}
00608 
00609     /// Allocate memory, assuming x and y have size \c size
00610     virtual int allocate(size_t size) {
00611       
00612       this->c=(double *)malloc(size*sizeof(double));
00613       if (this->c == 0) {
00614         O2SCL_ERR2_RET("Failed to allocate space for c",
00615                        " in cspline_interp::allocate().",gsl_enomem);
00616       }
00617       
00618       this->g=(double *)malloc(size*sizeof(double));
00619       if (this->g == 0) {
00620         std::free(this->c);
00621         O2SCL_ERR2_RET("Failed to allocate space for g",
00622                        " in cspline_interp::allocate().",gsl_enomem);
00623       }
00624       
00625       this->diag=(double *)malloc(size*sizeof(double));
00626       if (this->diag == 0) {
00627         std::free(this->g);
00628         std::free(this->c);
00629         O2SCL_ERR2_RET("Failed to allocate space for diag",
00630                        " in cspline_interp::allocate().",gsl_enomem);
00631       }
00632       
00633       this->offdiag=(double *)malloc(size*sizeof(double));
00634       if (this->offdiag == 0) {
00635         std::free(this->diag);
00636         std::free(this->g);
00637         std::free(this->c);
00638         O2SCL_ERR2_RET("Failed to allocate space for offdiag",
00639                        " in cspline_interp::allocate().",gsl_enomem);
00640       }
00641 
00642       p5m.allocate(size);
00643 
00644       this->mem_alloc=true;
00645       
00646       return 0;
00647     }
00648 
00649     /// Return the type, \c "cspline_peri_interp".
00650     virtual const char *type() { return "cspline_peri_interp"; }
00651 
00652     virtual int init(const vec_t &xa, const vec_t &ya, size_t size) {
00653 
00654       if (this->mem_alloc==false) {
00655         O2SCL_ERR2_RET("Memory allocation not performed in ",
00656                        "cspline_peri_interp::init().",gsl_efailed);
00657       }
00658 
00659       if (this->sv!=0) delete this->sv;
00660       this->sv=new search_vec<vec_t>(size,xa);
00661 
00662       double *lc=this->c;
00663       double *lg=this->g;
00664       double *ldiag=this->diag;
00665       double *loffdiag=this->offdiag;
00666 
00667       /// Periodic boundary conditions
00668          
00669       size_t i;
00670       size_t num_points=size;
00671       /* Engeln-Mullges+Uhlig "n" */
00672       size_t max_index=num_points-1;  
00673       /* linear system is sys_size x sys_size */
00674       size_t sys_size=max_index;    
00675         
00676       if (sys_size == 2) {
00677         /* solve 2x2 system */
00678           
00679         const double h0=xa[1]-xa[0];
00680         const double h1=xa[2]-xa[1];
00681         const double h2=xa[3]-xa[2];
00682         const double A=2.0*(h0+h1);
00683         const double B=h0+h1;
00684         double gx[2];
00685         double det;
00686           
00687         gx[0]=3.0*((ya[2]-ya[1])/h1-(ya[1]-ya[0])/h0);
00688         gx[1]=3.0*((ya[1]-ya[2])/h2-(ya[2]-ya[1])/h1);
00689           
00690         det=3.0*(h0+h1)*(h0+h1);
00691         lc[1]=( A*gx[0]-B*gx[1])/det;
00692         lc[2]=(-B*gx[0]+A*gx[1])/det;
00693         lc[0]=lc[2];
00694           
00695         return gsl_success;
00696 
00697       } else {
00698           
00699         for (i=0; i < sys_size-1; i++) {
00700           const double h_i=xa[i+1]-xa[i];
00701           const double h_ip1=xa[i+2]-xa[i+1];
00702           const double ydiff_i=ya[i+1]-ya[i];
00703           const double ydiff_ip1=ya[i+2]-ya[i+1];
00704           const double g_i=(h_i != 0.0) ? 1.0/h_i : 0.0;
00705           const double g_ip1=(h_ip1 != 0.0) ? 1.0/h_ip1 : 0.0;
00706           loffdiag[i]=h_ip1;
00707           ldiag[i]=2.0*(h_ip1+h_i);
00708           lg[i]=3.0*(ydiff_ip1*g_ip1-ydiff_i*g_i);
00709         }
00710           
00711         i=sys_size-1;
00712         {
00713           const double h_i=xa[i+1]-xa[i];
00714           const double h_ip1=xa[1]-xa[0];
00715           const double ydiff_i=ya[i+1]-ya[i];
00716           const double ydiff_ip1=ya[1]-ya[0];
00717           const double g_i=(h_i != 0.0) ? 1.0/h_i : 0.0;
00718           const double g_ip1=(h_ip1 != 0.0) ? 1.0/h_ip1 : 0.0;
00719           loffdiag[i]=h_ip1;
00720           ldiag[i]=2.0*(h_ip1+h_i);
00721           lg[i]=3.0*(ydiff_ip1*g_ip1-ydiff_i*g_i);
00722         }
00723 
00724         double *cp1=lc+1;
00725         o2scl_linalg::solve_cyc_tridiag_sym<double *,double *,double *,
00726           double *,o2scl_linalg::uvector_5_mem,uvector>
00727           (ldiag,loffdiag,lg,cp1,sys_size,p5m);
00728         lc[0]=lc[max_index];
00729         return gsl_success;
00730 
00731       }
00732 
00733     }
00734 
00735     /// Free allocated memory
00736     virtual int free() {
00737       p5m.free();
00738       std::free(this->c);
00739       std::free(this->g);
00740       std::free(this->diag);
00741       std::free(this->offdiag);
00742       this->mem_alloc=false;
00743       return 0;
00744     }
00745 
00746 #ifndef DOXYGEN_INTERNAL
00747 
00748   private:
00749 
00750     cspline_peri_interp<vec_t>(const cspline_peri_interp<vec_t> &);
00751     cspline_peri_interp<vec_t>& operator=(const cspline_peri_interp<vec_t>&);
00752 
00753 #endif
00754 
00755   };
00756 
00757   /** \brief Akima spline interpolation (GSL)
00758       
00759       This class uses natural boundary conditions, where the second
00760       derivative vanishes at each end point. Extrapolation effectively
00761       assumes that the second derivative is linear outside of the
00762       endpoints. Use \ref akima_peri_interp for perodic boundary
00763       conditions.
00764   */
00765   template<class vec_t> class akima_interp : public base_interp<vec_t> {
00766     
00767 #ifndef DOXYGEN_INTERNAL
00768     
00769   protected:
00770 
00771     /// \name Storage for Akima spline interpolation
00772     //@{
00773     double *b;
00774     double *c;
00775     double *d;
00776     double *um;
00777     //@}
00778 
00779     /// For initializing the interpolation
00780     void akima_calc(const vec_t &x_array, size_t size, double m[]) {
00781       
00782       for(size_t i=0; i < (size-1); i++) {
00783 
00784         const double NE=fabs(m[i+1]-m[i])+fabs(m[i-1]-m[i-2]);
00785         
00786         if (NE == 0.0) {
00787           b[i]=m[i];
00788           c[i]=0.0;
00789           d[i]=0.0;
00790         } else {
00791           const double h_i=x_array[i+1]-x_array[i];
00792           const double NE_next=fabs(m[i+2]-m[i+1])+
00793             fabs(m[i]-m[i-1]);
00794           const double alpha_i=fabs(m[i-1]-m[i-2])/NE;
00795           double alpha_ip1;
00796           double tL_ip1;
00797           if (NE_next == 0.0) {
00798             tL_ip1=m[i];
00799           } else {
00800             alpha_ip1=fabs(m[i]-m[i-1])/NE_next;
00801             tL_ip1=(1.0-alpha_ip1)*m[i]+alpha_ip1*m[i+1];
00802           }
00803           b[i]=(1.0-alpha_i)*m[i-1]+alpha_i*m[i];
00804           c[i]=(3.0*m[i]-2.0*b[i]-tL_ip1)/h_i;
00805           d[i]=(b[i]+tL_ip1-2.0*m[i])/(h_i*h_i);
00806         }
00807       }
00808     }
00809     
00810 #endif
00811     
00812   public:
00813 
00814     /** \brief Create a base interpolation object with or without
00815         periodic boundary conditions
00816     */
00817     akima_interp() {
00818       this->min_size=5;
00819     }
00820 
00821     virtual ~akima_interp() {}
00822     
00823     /// Allocate memory, assuming x and y have size \c size
00824     virtual int allocate(size_t size) {
00825       
00826       b=(double *)malloc(size*sizeof (double));
00827       if (b==0) {
00828         O2SCL_ERR2_RET("Failed to allocate space for c",
00829                        " in akima_interp::allocate().",gsl_enomem);
00830       }
00831       
00832       c=(double *)malloc(size*sizeof (double));
00833       if (c==0) {
00834         std::free(b);
00835         O2SCL_ERR2_RET("Failed to allocate space for g",
00836                        " in akima_interp::allocate().",gsl_enomem);
00837       }
00838       
00839       d=(double *)malloc(size*sizeof (double));
00840       if (d==0) {
00841         std::free(b);
00842         std::free(c);
00843         O2SCL_ERR2_RET("Failed to allocate space for diag",
00844                        " in akima_interp::allocate().",gsl_enomem);
00845       }
00846       
00847       um=(double *)malloc((size+4)*sizeof (double));
00848       if (um==0) {
00849         std::free(b);
00850         std::free(c);
00851         std::free(d);
00852         O2SCL_ERR2_RET("Failed to allocate space for offdiag",
00853                        " in akima_interp::allocate().",gsl_enomem);
00854       }
00855 
00856       this->mem_alloc=true;
00857 
00858       return 0;
00859     }
00860     
00861     /// Initialize interpolation routine
00862     virtual int init(const vec_t &xa, const vec_t &ya, size_t size) {
00863       
00864       if (this->mem_alloc==false) {
00865         O2SCL_ERR2_RET("Memory allocation not performed in ",
00866                        "akima_interp::init().",gsl_efailed);
00867       }
00868 
00869       if (this->sv!=0) delete this->sv;
00870       this->sv=new search_vec<vec_t>(size,xa);
00871 
00872       /// Non-periodic boundary conditions
00873 
00874       double *m=um+2;
00875       size_t i;
00876       for (i=0; i <= size-2; i++) {
00877         m[i]=(ya[i+1]-ya[i])/(xa[i+1]-xa[i]);
00878       }
00879         
00880       /* non-periodic boundary conditions */
00881       m[-2]=3.0*m[0]-2.0*m[1];
00882       m[-1]=2.0*m[0]-m[1];
00883       m[size-1]=2.0*m[size-2]-m[size-3];
00884       m[size]=3.0*m[size-2]-2.0*m[size-3];
00885         
00886       akima_calc (xa, size, m);
00887 
00888       return 0;
00889     }
00890           
00891     /// Free allocated memory
00892     virtual int free() {
00893       std::free(b);
00894       std::free(c);
00895       std::free(d);
00896       std::free(um);
00897       this->mem_alloc=false;
00898       return 0;
00899     }
00900 
00901     /// Give the value of the function \f$ y(x=x_0) \f$ .
00902     virtual int interp(const vec_t &x_array, const vec_t &y_array, 
00903                        size_t size, double x, double &y) {
00904       
00905       size_t index;
00906       
00907       index=this->sv->find(x);
00908   
00909       const double x_lo=x_array[index];
00910       const double delx=x-x_lo;
00911       const double bb=b[index];
00912       const double cc=c[index];
00913       const double dd=d[index];
00914       y=y_array[index]+delx*(bb+delx*(cc+dd*delx));
00915       return gsl_success;
00916     }
00917 
00918     /// Give the value of the derivative \f$ y^{\prime}(x=x_0) \f$ .
00919     virtual int deriv(const vec_t &x_array, const vec_t &y_array, 
00920                       size_t size, double x, double &dydx) {
00921 
00922       size_t index;
00923   
00924       index=this->sv->find(x);
00925 
00926       double x_lo=x_array[index];
00927       double delx=x-x_lo;
00928       double bb=b[index];
00929       double cc=c[index];
00930       double dd=d[index];
00931       dydx=bb+delx*(2.0*cc+3.0*dd*delx);
00932       return gsl_success;
00933 
00934     }
00935 
00936     /** \brief Give the value of the second derivative  
00937         \f$ y^{\prime \prime}(x=x_0) \f$ .
00938     */
00939     virtual int deriv2(const vec_t &x_array, const vec_t &y_array, 
00940                        size_t size, double x, double &d2ydx2) {
00941 
00942       size_t index;
00943   
00944       index=this->sv->find(x);
00945   
00946       const double x_lo=x_array[index];
00947       const double delx=x-x_lo;
00948       const double cc=c[index];
00949       const double dd=d[index];
00950       d2ydx2=2.0*cc+6.0*dd*delx;
00951       return gsl_success;
00952 
00953     }
00954 
00955     /// Give the value of the integral \f$ \int_a^{b}y(x)~dx \f$ .
00956     virtual int integ(const vec_t &x_array, const vec_t &y_array, 
00957                       size_t size, double aa, double bb, 
00958                       double &result) {
00959 
00960       size_t i, index_a, index_b;
00961   
00962       double tmp;
00963       bool flip=false;
00964       if ((x_array[0]<x_array[size-1] && aa>bb) ||
00965           (x_array[0]>x_array[size-1] && aa<bb)) {
00966         tmp=aa;
00967         aa=bb;
00968         bb=tmp;
00969         flip=true;
00970       }
00971 
00972       index_a=this->sv->find(aa);
00973       index_b=this->sv->find(bb);
00974 
00975       result=0.0;
00976   
00977       /* interior intervals */
00978 
00979       for(i=index_a; i<=index_b; i++) {
00980 
00981         const double x_hi=x_array[i+1];
00982         const double x_lo=x_array[i];
00983         const double y_lo=y_array[i];
00984         const double dx=x_hi-x_lo;
00985 
00986         if (dx != 0.0) {
00987           
00988           if (i==index_a || i==index_b) {
00989             double x1=(i==index_a) ? aa : x_lo;
00990             double x2=(i==index_b) ? bb : x_hi;
00991             result += this->integ_eval(y_lo,b[i],c[i],d[i],x_lo,x1,x2);
00992           } else {
00993             result+=dx*(y_lo+dx*(0.5*b[i]+dx*(c[i]/3.0+0.25*d[i]*dx)));
00994           }
00995 
00996         } else {
00997           result=0.0;
00998           // We don't throw an error here so smart_interp classes can
00999           // attempt to recover.
01000           return gsl_failure;
01001         }
01002       }
01003   
01004       if (flip) result*=-1.0;
01005       return gsl_success;
01006     }
01007 
01008     /// Return the type, \c "akima_interp".
01009     virtual const char *type() { return "akima_interp"; }
01010 
01011 #ifndef DOXYGEN_INTERNAL
01012 
01013   private:
01014 
01015     akima_interp<vec_t>(const akima_interp<vec_t> &);
01016     akima_interp<vec_t>& operator=(const akima_interp<vec_t>&);
01017 
01018 #endif
01019 
01020   };
01021   
01022   /** \brief Akima spline interpolation with periodic  
01023       boundary conditions (GSL)
01024   */
01025   template<class vec_t> class akima_peri_interp : 
01026   public akima_interp<vec_t> {
01027     
01028   public:
01029     
01030   akima_peri_interp() : akima_interp<vec_t>() {
01031     }
01032     
01033     virtual ~akima_peri_interp() {}
01034     
01035     /// Return the type, \c "akima_peri_interp".
01036     virtual const char *type() { return "akima_peri_interp"; }
01037 
01038     /// Initialize interpolation routine
01039     virtual int init(const vec_t &xa, const vec_t &ya, size_t size) {
01040       
01041       if (this->mem_alloc==false) {
01042         O2SCL_ERR2_RET("Memory allocation not performed in ",
01043                        "akima_peri_interp::init().",gsl_efailed);
01044       }
01045 
01046       if (this->sv!=0) delete this->sv;
01047       this->sv=new search_vec<vec_t>(size,xa);
01048 
01049       /// Periodic boundary conditions
01050       
01051       double *m=this->um+2;
01052       size_t i;
01053       // Form the required set of divided differences
01054       for (i=0;i<=size-2;i++) {
01055         m[i]=(ya[i+1]-ya[i])/(xa[i+1]-xa[i]);
01056       }
01057       
01058       /* periodic boundary conditions */
01059       m[-2]=m[size-1-2];
01060       m[-1]=m[size-1-1];
01061       m[size-1]=m[0];
01062       m[size]=m[1];
01063       
01064       akima_calc (xa,size, m);
01065       
01066       return 0;
01067     }
01068       
01069 #ifndef DOXYGEN_INTERNAL
01070 
01071   private:
01072 
01073     akima_peri_interp<vec_t>(const akima_peri_interp<vec_t> &);
01074     akima_peri_interp<vec_t>& operator=(const akima_peri_interp<vec_t>&);
01075 
01076 #endif
01077 
01078   };
01079 
01080   /** \brief A base interpolation object manager [abstract base]
01081    */
01082   template<class vec_t> class base_interp_mgr {
01083 
01084   public:
01085 
01086     virtual ~base_interp_mgr() {}
01087 
01088     /// Create a new interpolation object
01089     virtual base_interp<vec_t> *new_interp()=0;
01090 
01091     /// Deallocate an interpolation object
01092     virtual int free_interp(base_interp<vec_t> *b) {
01093       delete b;
01094       return 0;
01095     }
01096   };
01097   
01098   /** \brief A base interpolation object manager template 
01099    */
01100   template<class vec_t, template<class> class interp_t> class def_interp_mgr :
01101   public base_interp_mgr<vec_t> {
01102     
01103   public:
01104 
01105     virtual ~def_interp_mgr() {}
01106 
01107     /// Create a new interpolation object
01108     virtual base_interp<vec_t> *new_interp() {
01109       interp_t<vec_t> *b=new interp_t<vec_t>;
01110       return b;
01111     }
01112 
01113   };
01114 
01115   /** \brief Interpolation class 
01116       
01117       Interpolation of \ref ovector like objects is performed with the
01118       default template parameters, and \ref array_interp is provided
01119       for simple interpolation on C-style arrays.
01120 
01121       The type of interpolation to be performed can be specified using
01122       the set_type() function or in the constructor.  The default is
01123       cubic splines with natural boundary conditions.
01124   */
01125   template<class vec_t=ovector_const_view> class o2scl_interp {
01126     
01127 #ifndef DOXYGEN_INTERNAL
01128     
01129   protected:
01130   
01131   /// Pointer to base interpolation object
01132   base_interp<vec_t> *itp;
01133   
01134   /// Pointer to base interpolation manager
01135   base_interp_mgr<vec_t> *bim1;
01136   
01137 #endif
01138       
01139   public:
01140       
01141   /** \brief Default base interpolation object (cubic spline with
01142       natural boundary conditions)
01143   */
01144   def_interp_mgr<vec_t,cspline_interp> dim1;
01145   
01146   /// Create with base interpolation object \c it
01147   o2scl_interp(base_interp_mgr<vec_t> &it) {
01148     bim1=&it;
01149     itp=bim1->new_interp();
01150   }
01151 
01152   /** \brief Create an interpolator using the default
01153       cubic spline interpolation
01154   */
01155   o2scl_interp() {
01156     bim1=&dim1;
01157     itp=bim1->new_interp();
01158   }
01159 
01160   virtual ~o2scl_interp() {
01161     bim1->free_interp(itp);
01162   }
01163 
01164   /// Give the value of the function \f$ y(x=x_0) \f$ .
01165   virtual double interp(const double x0, size_t n, const vec_t &x, 
01166                         const vec_t &y) {
01167     
01168     double ret=0.0;
01169     
01170     if (n<itp->min_size) {
01171       O2SCL_ERR("Vector size too small in interp().",gsl_edom);
01172     }
01173       
01174     int r1=itp->allocate(n);
01175     if (r1==0) {
01176       int r2=itp->init(x,y,n);
01177       if (r2==0) {
01178         itp->interp(x,y,n,x0,ret);
01179       }
01180       itp->free();
01181     }
01182           
01183     return ret;
01184   }                   
01185     
01186   /// Give the value of the derivative \f$ y^{\prime}(x=x_0) \f$ .
01187   virtual double deriv(const double x0, size_t n, const vec_t &x, 
01188                        const vec_t &y) {
01189       
01190     double ret=0.0;
01191       
01192     if (n<itp->min_size) {
01193       O2SCL_ERR("Vector size too small in deriv().",gsl_edom);
01194     }
01195       
01196     int r1=itp->allocate(n);
01197     if (r1==0) {
01198       int r2=itp->init(x,y,n);
01199       if (r2==0) {
01200         itp->deriv(x,y,n,x0,ret);
01201       }
01202       itp->free();
01203     }
01204       
01205     return ret;
01206   }                   
01207     
01208   /** \brief Give the value of the second derivative  
01209       \f$ y^{\prime \prime}(x=x_0) \f$ .
01210   */
01211   virtual double deriv2(const double x0, size_t n, const vec_t &x, 
01212                         const vec_t &y) {
01213       
01214     double ret=0.0;
01215       
01216     if (n<itp->min_size) {
01217       O2SCL_ERR("Vector size too small in deriv2().",gsl_edom);
01218     }
01219       
01220     // Increasing case
01221 
01222     int r1=itp->allocate(n);
01223     if (r1==0) {
01224       int r2=itp->init(x,y,n);
01225       if (r2==0) {
01226         itp->deriv2(x,y,n,x0,ret);
01227       }
01228       itp->free();
01229     }
01230 
01231     return ret;
01232   }                   
01233     
01234   /// Give the value of the integral \f$ \int_a^{b}y(x)~dx \f$ .
01235   virtual double integ(const double x1, const double x2, size_t n, 
01236                        const vec_t &x, const vec_t &y) {
01237       
01238     double ret=0.0;
01239       
01240     if (n<itp->min_size) {
01241       O2SCL_ERR("Vector size too small in integ().",gsl_edom);
01242     }
01243       
01244     // Increasing case
01245             
01246     int r1=itp->allocate(n);
01247     if (r1==0) {
01248       int r2=itp->init(x,y,n);
01249       if (r2==0) {
01250         itp->integ(x,y,n,x1,x2,ret);
01251       }
01252       itp->free();
01253     }
01254 
01255     return ret;
01256   }                   
01257     
01258   /// Set base interpolation object
01259   int set_type(base_interp_mgr<vec_t> &it) {
01260     bim1->free_interp(itp);
01261     bim1=&it;
01262     itp=bim1->new_interp();
01263     return 0;
01264   }
01265       
01266 #ifndef DOXYGEN_INTERNAL
01267 
01268   private:
01269 
01270   o2scl_interp<vec_t>(const o2scl_interp<vec_t> &);
01271   o2scl_interp<vec_t>& operator=(const o2scl_interp<vec_t>&);
01272 
01273 #endif
01274 
01275   };
01276   
01277   /** \brief Interpolation class for pre-specified vector
01278       
01279       This interpolation class is intended to be sufficiently general
01280       to handle any vector type. Interpolation of \ref ovector like
01281       objects is performed with the default template parameters, and
01282       \ref array_interp_vec is provided for simple interpolation on
01283       C-style arrays.
01284 
01285       This class does not double check the vector to ensure that 
01286       all of the intervals for the abcissa are all increasing or
01287       all decreasing. 
01288 
01289       The type of interpolation to be performed can be specified 
01290       using the set_type() function. The default is cubic splines
01291       with natural boundary conditions. 
01292   */
01293   template<class vec_t=ovector_const_view> class o2scl_interp_vec {
01294       
01295 #ifndef DOXYGEN_INTERNAL
01296       
01297   protected:
01298       
01299   /// Base interpolation object
01300   base_interp<vec_t> *itp;
01301 
01302   /// The interpolation manager
01303   base_interp_mgr<vec_t> *bim;
01304       
01305   /// True if the original array was increasing
01306   bool inc;
01307 
01308   /// Pointer to the user-specified x vector
01309   const vec_t *lx;
01310 
01311   /// Pointer to the user-specified x vector
01312   const vec_t *ly;
01313 
01314   /// Size of user-specified vectors
01315   size_t ln;
01316 
01317 #endif
01318       
01319   public:
01320     
01321   /// Create with base interpolation object \c it
01322   o2scl_interp_vec(base_interp_mgr<vec_t> &it, 
01323                    size_t n, const vec_t &x, const vec_t &y) {
01324 
01325     bim=&it;
01326     itp=bim->new_interp();
01327     ln=0;
01328     lx=0;
01329     ly=0;
01330         
01331     if (n<itp->min_size) {
01332       O2SCL_ERR("Vector size too small in o2scl_interp_vec().",gsl_edom);
01333     }
01334       
01335     size_t iend=n-1;
01336 
01337     if (x[0]==x[iend]) {
01338       O2SCL_ERR("Vector endpoints equal in o2scl_interp_vec().",
01339                 gsl_einval);
01340     }
01341       
01342     int r1=itp->allocate(n);
01343     if (r1==0) {
01344       int r2=itp->init(x,y,n);
01345       if (r2==0) {
01346         ln=n;
01347         lx=&x;
01348         ly=&y;
01349         inc=true;
01350       } else {
01351         itp->free();
01352       }
01353     }
01354       
01355   }
01356       
01357   virtual ~o2scl_interp_vec() {
01358     if (ln>0) {
01359       itp->free();
01360     }
01361     bim->free_interp(itp);
01362   }
01363     
01364   /// Give the value of the function \f$ y(x=x_0) \f$ .
01365   virtual double interp(const double x0) {
01366     double ret=0.0;
01367     if (ln>0) {
01368       itp->interp(*lx,*ly,ln,x0,ret);
01369       return ret;
01370     }
01371     O2SCL_ERR2_RET("No data to interpolate in ",
01372                    "o2scl_interp_vec::interp().",gsl_efailed);
01373     return ret;
01374   }                   
01375     
01376   /// Give the value of the derivative \f$ y^{\prime}(x=x_0) \f$ .
01377   virtual double deriv(const double x0) {
01378     double ret=0.0;
01379     if (ln>0) {
01380       itp->deriv(*lx,*ly,ln,x0,ret);
01381       return ret;
01382     }
01383     O2SCL_ERR2_RET("No data to interpolate in ",
01384                    "o2scl_interp_vec::deriv().",gsl_efailed);
01385     return ret;
01386   }                   
01387     
01388   /** \brief Give the value of the second derivative  
01389       \f$ y^{\prime \prime}(x=x_0) \f$ .
01390   */
01391   virtual double deriv2(const double x0) {
01392     double ret=0.0;
01393     if (ln>0) {
01394       itp->deriv2(*lx,*ly,ln,x0,ret);
01395       return ret;
01396     }
01397     O2SCL_ERR2_RET("No data to interpolate in ",
01398                    "o2scl_interp_vec::deriv2().",gsl_efailed);
01399     return ret;
01400   }                   
01401     
01402   /// Give the value of the integral \f$ \int_a^{b}y(x)~dx \f$ .
01403   virtual double integ(const double x1, const double x2) {
01404     double ret=0.0;
01405     if (ln>0) {
01406       itp->integ(*lx,*ly,ln,x1,x2,ret);
01407       return ret;
01408     }
01409     O2SCL_ERR2_RET("No data to interpolate in ",
01410                    "o2scl_interp_vec::integ().",gsl_efailed);
01411     return ret;
01412   }                   
01413     
01414   /// Set base interpolation object
01415   int set_type(base_interp_mgr<vec_t> &it) {
01416     bim=&it;
01417     return 0;
01418   }
01419   
01420 #ifndef DOXYGEN_INTERNAL
01421 
01422   private:
01423   
01424   o2scl_interp_vec<vec_t>(const o2scl_interp_vec<vec_t> &);
01425   o2scl_interp_vec<vec_t>& operator=(const o2scl_interp_vec<vec_t>&);
01426     
01427   
01428 #endif
01429   
01430   };
01431   
01432   /** \brief A specialization of o2scl_interp for C-style double arrays
01433    */
01434   template<size_t n> class array_interp : public o2scl_interp<double[n]> {
01435     
01436   public:
01437     
01438     /// Create with base interpolation objects \c it and \c rit
01439   array_interp(base_interp_mgr<double[n]> &it) 
01440     : o2scl_interp<double[n]>(it) {}
01441     
01442     /** \brief Create an interpolator using the default base
01443         interpolation objects
01444     */
01445   array_interp() : o2scl_interp<double[n]>() {}
01446     
01447   };
01448   
01449   /** \brief A specialization of o2scl_interp_vec for C-style arrays
01450    */
01451   template<class arr_t> class array_interp_vec : 
01452   public o2scl_interp_vec<arr_t> {
01453     
01454   public:
01455     
01456     /// Create with base interpolation object \c it
01457   array_interp_vec(base_interp_mgr<arr_t> &it, 
01458                    size_t nv, const arr_t &x, const arr_t &y) :
01459     o2scl_interp_vec<arr_t>(it,nv,x,y) {}
01460       
01461   };
01462   
01463 #ifndef DOXYGENP
01464 }
01465 #endif
01466 
01467 #endif
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Documentation generated with Doxygen. Provided under the GNU Free Documentation License (see License Information).

Get Object-oriented Scientific Computing
Lib at SourceForge.net. Fast, secure and Free Open Source software
downloads.