Object-oriented Scientific Computing Library: Version 0.910
smart_interp.h
Go to the documentation of this file.
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_SMART_INTERP_H
00024 #define O2SCL_SMART_INTERP_H
00025 
00026 /** \file smart_interp.h
00027     \brief File for "smart" interpolation routines
00028 
00029     In addition to the smart interpolation routines, this file
00030     contains the template functions \ref vector_find_level(), \ref
00031     vector_integ_linear() and \ref vector_invert_enclosed_sum().
00032 */
00033 
00034 #include <o2scl/interp.h>
00035 #include <o2scl/vector.h>
00036 
00037 #ifndef DOXYGENP
00038 namespace o2scl {
00039 #endif
00040 
00041   /** \brief Smart interpolation class
00042       
00043       This class can semi-intelligently handle arrays which are
00044       not-well formed outside the interpolation region. In particular,
00045       if an initial interpolation or derivative calculation fails, the
00046       arrays are searched for the largest neighborhood around the
00047       point \c x for which an interpolation or differentiation will
00048       likely produce a finite result.
00049   */
00050   template<class vec_t=ovector_const_view, 
00051     class svec_t=ovector_const_subvector> class smart_interp {
00052       
00053 #ifndef DOXYGEN_INTERNAL
00054     
00055   protected:
00056   
00057   /// \name Storage internally created subvectors
00058   //@{
00059   bool sxalloc;
00060   const svec_t *sx;
00061   const svec_t *sy;
00062   //@}
00063 
00064   /// \name Pointers to interpolation objects
00065   //@{
00066   base_interp<vec_t> *rit1;
00067   base_interp<svec_t> *rit3;
00068   //@}
00069 
00070   /// \name Pointers to interpolation managers
00071   //@{
00072   base_interp_mgr<vec_t> *bim1;
00073   base_interp_mgr<svec_t> *bim3;
00074   //@}
00075 
00076 #endif
00077 
00078   public:
00079     
00080   /** \brief Create a new interpolation object with the specified 
00081       interpolation managers
00082   */
00083   smart_interp(base_interp_mgr<vec_t> &im1,
00084                base_interp_mgr<svec_t> &im3) {
00085     
00086     sxalloc=false;
00087     sx=0;
00088     sy=0;
00089 
00090     bim1=&im1;
00091     bim3=&im3;
00092 
00093     rit1=bim1->new_interp();
00094     rit3=bim3->new_interp();
00095   };
00096 
00097   /** \brief Create an interpolation object with the default 
00098       cubic spline interpolation managers
00099   */
00100   smart_interp() {
00101     sxalloc=false;
00102     sx=0;
00103     sy=0;
00104 
00105     bim1=&dim1;
00106     bim3=&dim3;
00107 
00108     rit1=bim1->new_interp();
00109     rit3=bim3->new_interp();
00110   };
00111     
00112   virtual ~smart_interp() {
00113     if (sxalloc) {
00114       delete sx;
00115       delete sy;
00116     } 
00117 
00118     /*
00119       We don't want to use "bim1->free_interp(rit1)" here instead
00120       of "delete rit1" because the pointer "bim1" may refer to 
00121       a user-defined interpolation manager, and it may have gone
00122       out of scope earlier.
00123     */
00124     delete rit1;
00125     delete rit3;
00126   }
00127 
00128   /** \brief Give the value of the function \f$ y(x=x_0) \f$ .
00129 
00130       \todo After calling find_subset, I think we might need
00131       to double check that \c nn is larger than the minimum
00132       interpolation size.
00133   */
00134   virtual double interp(const double x0, size_t n, const vec_t &x, 
00135                         const vec_t &y) {
00136       
00137     bool to_subset=false;
00138     double ret=0.0;
00139     int err0, err1, err2;
00140       
00141     if (x[0]==x[n-1]) {
00142       to_subset=true;
00143     }
00144 
00145     if (n<rit1->min_size) {
00146       O2SCL_ERR("Vector size too small in interp().",gsl_edom);
00147       return 0.0;
00148     }
00149     err0=rit1->allocate(n);
00150     if (err0==0) {
00151       err1=rit1->init(x,y,n);
00152       if (err1==0) {
00153         err2=rit1->interp(x,y,n,x0,ret);
00154         if (err2!=0) to_subset=true;
00155       } else {
00156         to_subset=true;
00157       }
00158       rit1->free();
00159     }
00160       
00161     if (!gsl_finite(ret)) to_subset=true;
00162       
00163     if (to_subset) {
00164         
00165       size_t nn=0;
00166       int retfs=find_subset(x0,x0,n,x,y,nn);
00167       
00168       if (retfs!=0 || nn<=1) {
00169         O2SCL_ERR("Interpolation failed in interp().",gsl_efailed);
00170         return 0;
00171       }
00172 
00173       if (nn>=rit3->min_size) {
00174         err0=rit3->allocate(nn);
00175         if (err0==0) {
00176           err1=rit3->init(*sx,*sy,nn);
00177           if (err1==0) {
00178             err2=rit3->interp(*sx,*sy,nn,x0,ret);
00179           }             
00180           rit3->free();
00181         }
00182       } else {
00183         O2SCL_ERR("Interpolation failed in interp().",gsl_efailed);
00184       }
00185       
00186     }
00187     
00188     return ret;
00189   }                   
00190   
00191   /// Give the value of the derivative \f$ y^{prime}(x=x_0) \f$ .
00192   virtual double deriv(const double x0, size_t n, const vec_t &x, 
00193                        const vec_t &y) {
00194     
00195     bool increasing=true, to_subset=false;
00196     double ret=0.0;
00197     int err0, err1, err2;
00198       
00199     if (x[0]==x[n-1]) {
00200       to_subset=true;
00201     }
00202 
00203     if (n<rit1->min_size) {
00204         O2SCL_ERR("Vector size too small in deriv().",gsl_edom);
00205         return 0.0;
00206       }
00207       err0=rit1->allocate(n);
00208       if (err0==0) {
00209         err1=rit1->init(x,y,n);
00210         if (err1==0) {
00211           err2=rit1->deriv(x,y,n,x0,ret);
00212           if (err2!=0) to_subset=true;
00213         } else {
00214           to_subset=true;
00215         }
00216         rit1->free();
00217       }
00218           
00219     if (!gsl_finite(ret)) to_subset=true;
00220       
00221     if (to_subset) {
00222         
00223       size_t nn=0;
00224       int retfs=find_subset(x0,x0,n,x,y,nn);
00225         
00226       if (retfs!=0 || nn<=1) {
00227         O2SCL_ERR("Interpolation failed in deriv().",gsl_efailed);
00228         return 0;
00229       }
00230 
00231       if (nn>=rit3->min_size) {
00232         err0=rit3->allocate(nn);
00233         if (err0==0) {
00234           err1=rit3->init(*sx,*sy,nn);
00235           if (err1==0) {
00236             err2=rit3->deriv(*sx,*sy,nn,x0,ret);
00237           }             
00238           rit3->free();
00239         }
00240       } else {
00241         O2SCL_ERR("Interpolation failed in deriv().",gsl_efailed);
00242       }
00243       
00244     }
00245     
00246     return ret;
00247   }                   
00248 
00249   /** \brief Give the value of the second derivative  
00250       \f$ y^{prime \prime}(x=x_0) \f$ .
00251   */
00252   virtual double deriv2(const double x0, size_t n, const vec_t &x, 
00253                         const vec_t &y) {
00254       
00255     bool increasing=true, to_subset=false;
00256     double ret=0.0;
00257     int err0, err1, err2;
00258       
00259     if (x[0]==x[n-1]) {
00260       to_subset=true;
00261     }
00262 
00263     if (n<rit1->min_size) {
00264         O2SCL_ERR("Vector size too small in deriv2().",gsl_edom);
00265         return 0.0;
00266       }
00267       err0=rit1->allocate(n);
00268       if (err0==0) {
00269         err1=rit1->init(x,y,n);
00270         if (err1==0) {
00271           err2=rit1->deriv2(x,y,n,x0,ret);
00272           if (err2!=0) to_subset=true;
00273         } else {
00274           to_subset=true;
00275         }
00276         rit1->free();
00277       }
00278           
00279     if (!gsl_finite(ret)) to_subset=true;
00280       
00281     if (to_subset) {
00282         
00283       size_t nn=0;
00284       int retfs=find_subset(x0,x0,n,x,y,nn);
00285         
00286       if (retfs!=0 || nn<=1) {
00287         O2SCL_ERR("Interpolation failed in deriv2().",gsl_efailed);
00288         return 0;
00289       }
00290 
00291       if (nn>=rit3->min_size) {
00292         err0=rit3->allocate(nn);
00293         if (err0==0) {
00294           err1=rit3->init(*sx,*sy,nn);
00295           if (err1==0) {
00296             err2=rit3->deriv2(*sx,*sy,nn,x0,ret);
00297           }             
00298           rit3->free();
00299         }
00300       } else {
00301         O2SCL_ERR("Interpolation failed in deriv2().",gsl_efailed);
00302       }
00303       
00304     }
00305     
00306     return ret;
00307   }                   
00308 
00309   /// Give the value of the integral \f$ \int_a^{b}y(x)~dx \f$ .
00310   virtual double integ(const double a, const double b, 
00311                        size_t n, const vec_t &x, const vec_t &y) {
00312                            
00313     bool increasing=true, to_subset=false;
00314     double ret=0.0;
00315     int err0, err1, err2;
00316       
00317     if (x[0]==x[n-1]) {
00318       to_subset=true;
00319     }
00320 
00321     if (n<rit1->min_size) {
00322         O2SCL_ERR("Vector size too small in integ().",gsl_edom);
00323         return 0.0;
00324       }
00325       err0=rit1->allocate(n);
00326       if (err0==0) {
00327         err1=rit1->init(x,y,n);
00328         if (err1==0) {
00329           err2=rit1->integ(x,y,n,a,b,ret);
00330           if (err2!=0) to_subset=true;
00331         } else {
00332           to_subset=true;
00333         }
00334         rit1->free();
00335       }
00336           
00337     if (!gsl_finite(ret)) to_subset=true;
00338       
00339     if (to_subset) {
00340         
00341       size_t nn=0;
00342       int retfs=find_subset(a,b,n,x,y,nn);
00343         
00344       if (retfs!=0 || nn<=1) {
00345         O2SCL_ERR("Interpolation failed in integ().",gsl_efailed);
00346         return 0;
00347       }
00348 
00349 
00350       if (nn>=rit3->min_size) {
00351         err0=rit3->allocate(nn);
00352         if (err0==0) {
00353           err1=rit3->init(*sx,*sy,nn);
00354           if (err1==0) {
00355             err2=rit3->integ(*sx,*sy,nn,a,b,ret);
00356           }             
00357           rit3->free();
00358         }
00359       } else {
00360         O2SCL_ERR("Interpolation failed in integ().",gsl_efailed);
00361       }
00362       
00363     }
00364     
00365     return ret;
00366   }                   
00367 
00368   /// \name Default interpolation managers
00369   //@{
00370   def_interp_mgr<vec_t,cspline_interp> dim1;
00371   def_interp_mgr<svec_t,cspline_interp> dim3;
00372   //@}
00373 
00374 #ifndef DOXGYEN_INTERNAL
00375 
00376   protected:
00377   
00378   /** \brief A lookup function for generic vectors
00379    */
00380   size_t local_lookup(size_t n, const vec_t &x, double x0) {
00381     size_t row=0, i=0;
00382     while(!gsl_finite(x[i]) && i<n-1) i++;
00383     if (i==n-1) {
00384       return 0;
00385     }
00386     double best=x[i], bdiff=fabs(x[i]-x0);
00387     for(;i<n;i++) {
00388       if (gsl_finite(x[i]) && fabs(x[i]-x0)<bdiff) {
00389         row=i;
00390         best=x[i];
00391         bdiff=fabs(x[i]-x0);
00392       }
00393     }
00394     return row;
00395   }
00396 
00397   /** \brief Try to find the largest monotonic and finite region
00398       around the desired location
00399 
00400       This function tries to find the largest monotonic region
00401       enclosing both \c a and \c b in the vector \c x. If it succeeds,
00402       it returns \ref gsl_success, and if it fails, it returns \ref
00403       gsl_efailed. It does not call the error handler.
00404 
00405       \todo The error handling is a bit off here, as it can return
00406       a non-zero value even with there is no real "error". We should
00407       just make a new bool reference paramter. 
00408   */
00409   int find_subset(const double a, const double b, size_t sz, const vec_t &x, 
00410                   const vec_t &y, size_t &nsz) 
00411   {
00412       
00413     size_t left, right;
00414 
00415     bool increasing=true;
00416     if (x[0]>x[sz-1]) increasing=false;
00417       
00418     // Lookup the point
00419     size_t row=local_lookup(sz,x,a);
00420     if (!gsl_finite(x[row]) || !gsl_finite(y[row])) {
00421       return gsl_efailed;
00422     }
00423     size_t row2=local_lookup(sz,x,b);
00424     if (!gsl_finite(x[row2]) || !gsl_finite(y[row2])) {
00425       return gsl_efailed;
00426     }
00427   
00428     // Get a neighboring point if necessary
00429     if (row2==row) {
00430       row2=row++;
00431       if (row2>=sz) row2=row-1;
00432     }
00433 
00434     // Arrange
00435     if (row<row2) {
00436       left=row;
00437       right=row2;
00438     } else {
00439       left=row2;
00440       right=row;
00441     }
00442       
00443     // Establish whether we're increasing or decreasing
00444     increasing=true;
00445     if (row2<row && x[row]<x[row2]) increasing=false;
00446     if (row2>row && x[row2]<x[row]) increasing=false;
00447 
00448     // Check region between row and row2 
00449 
00450     if (increasing) {
00451       size_t lo, hi;
00452       if (row2<row) {
00453         lo=row2;
00454         hi=row;
00455       } else {
00456         lo=row;
00457         hi=row2;
00458       }
00459       for(size_t i=lo;i<hi-1;i++) {
00460         if (x[i]>x[i+1]) return gsl_efailed;
00461       }
00462     } else {
00463       size_t lo, hi;
00464       if (row2<row) {
00465         lo=row2;
00466         hi=row;
00467       } else {
00468         lo=row;
00469         hi=row2;
00470       }
00471       for(size_t i=lo;i<hi-1;i++) {
00472         if (x[i]<x[i+1]) return gsl_efailed;
00473       }
00474     }
00475 
00476     // Increasing case
00477     
00478     if (increasing) {
00479       
00480       while(left>0 && x[left-1]<x[left] && 
00481             gsl_finite(x[left-1]) && gsl_finite(y[left-1])) left--;
00482       while(right<sz-1 && x[right]<x[right+1] &&
00483             gsl_finite(x[right+1]) && gsl_finite(y[right+1])) right++;
00484         
00485       nsz=right-left+1;
00486 
00487       if (sxalloc) {
00488         delete sx;
00489         delete sy;
00490       }
00491       sx=new svec_t(x,left,nsz);
00492       sy=new svec_t(y,left,nsz);
00493       sxalloc=true;
00494         
00495     } else {
00496 
00497       while(left>0 && x[left-1]>x[left] && 
00498             gsl_finite(x[left-1]) && gsl_finite(y[left-1])) left--;
00499       while(right<sz-1 && x[right]>x[right+1] &&
00500             gsl_finite(x[right+1]) && gsl_finite(y[right+1])) right++;
00501         
00502       nsz=right-left+1;
00503         
00504       if (sxalloc==true) {
00505         delete sx;
00506         delete sy;
00507       }
00508       sx=new svec_t(x,left,nsz);
00509       sy=new svec_t(y,left,nsz);
00510       sxalloc=true;
00511 
00512     }
00513       
00514     return 0;
00515   }
00516 
00517 #endif
00518 
00519   };
00520 
00521   /** \brief Smart interpolation class with pre-specified vectors
00522       
00523       This class can semi-intelligently handle arrays which are
00524       not-well formed outside the interpolation region. In particular,
00525       if an initial interpolation or derivative calculation fails, the
00526       arrays are searched for the largest neighborhood around the
00527       point \c x for which an interpolation or differentiation will
00528       likely produce a finite result.
00529 
00530       \future Properly implement handling of non-monotonic regions in
00531       the derivative functions as well as the interpolation function.
00532   */
00533   template<class vec_t, class svec_t, class alloc_vec_t, class alloc_t>
00534     class smart_interp_vec {
00535 
00536 #ifndef DOXYGEN_INTERNAL
00537     
00538   protected:
00539 
00540     /// If true, then \ref sx and \ref sy have been allocated
00541     bool sxalloc;
00542     /// Storage for internally created subvector
00543     svec_t *sx;
00544     /// Storage for internally created subvector
00545     svec_t *sy;
00546 
00547     /// Pointer to base interpolation object
00548     base_interp<vec_t> *rit1;
00549     /// Pointer to base interpolation object
00550     base_interp<svec_t> *rit2;
00551 
00552     /// Pointer to base interpolation manager
00553     base_interp_mgr<vec_t> *bim1;
00554 
00555     /// Pointer to base interpolation manager
00556     base_interp_mgr<svec_t> *bim2;
00557     
00558     /// Memory allocator for objects of type \c alloc_vec_t
00559     alloc_t ao;
00560 
00561     /// True if the user-specified x vector is increasing
00562     bool inc;
00563 
00564     /// Pointer to user-specified vector
00565     const vec_t *lx;
00566     /// Pointer to user-specified vector
00567     const vec_t *ly;
00568 
00569     /// Size of user-specifed vector
00570     size_t ln;
00571     
00572 #endif
00573 
00574   public:
00575 
00576     /// Create with base interpolation objects \c it and \c rit
00577     smart_interp_vec(size_t n, const vec_t &x, const vec_t &y) {
00578       sx=0;
00579       sy=0;
00580       sxalloc=false;
00581 
00582       bim1=&dim1;
00583       bim2=&dim2;
00584 
00585       rit1=bim1->new_interp();
00586       rit2=bim2->new_interp();
00587       ln=0;
00588       
00589       if (n<rit1->min_size || n<rit2->min_size) {
00590         O2SCL_ERR("Vector size too small in o2scl_interp_vec().",gsl_edom);
00591       } else {
00592 
00593           int r1=rit1->allocate(n);
00594           if (r1==0) {
00595             rit1->init(x,y,n);
00596             ln=n;
00597             lx=&x;
00598             ly=&y;
00599             inc=true;
00600         }
00601 
00602       } 
00603 
00604     }
00605 
00606     /// Create with base interpolation objects \c it and \c rit
00607     smart_interp_vec(base_interp_mgr<vec_t> &it1, 
00608                      base_interp_mgr<svec_t> &it2,
00609                      size_t n, const vec_t &x, const vec_t &y) {
00610       sx=0;
00611       sy=0;
00612       sxalloc=false;
00613 
00614       bim1=&it1;
00615       bim2=&it2;
00616 
00617       rit1=bim1->new_interp();
00618       rit2=bim2->new_interp();
00619       ln=0;
00620         
00621       if (n<rit1->min_size || n<rit2->min_size) {
00622         O2SCL_ERR("Vector size too small in o2scl_interp_vec().",gsl_edom);
00623       } else {
00624 
00625           int r1=rit1->allocate(n);
00626           if (r1==0) {
00627             rit1->init(x,y,n);
00628             ln=n;
00629             lx=&x;
00630             ly=&y;
00631             inc=true;
00632           }
00633 
00634       } 
00635         
00636     }
00637 
00638     virtual ~smart_interp_vec() {
00639       if (sxalloc) {
00640         delete sx;
00641         delete sy;
00642       }
00643       
00644       if (ln>0) {
00645         rit1->free();
00646       }
00647       
00648       /*
00649         We don't want to use "bim1->free_interp(rit1)" here instead
00650         of "delete rit1" because the pointer "bim1" may refer to 
00651         a user-defined interpolation manager, and it may have gone
00652         out of scope earlier.
00653       */
00654       delete rit1;
00655       delete rit2;
00656     }
00657 
00658     /// Give the value of the function \f$ y(x=x_0) \f$ .
00659     virtual double operator()(const double x0) {
00660       return interp(x0);
00661     }
00662 
00663     /// Give the value of the function \f$ y(x=x_0) \f$ .
00664     virtual double interp(const double x0) {
00665       
00666       double ret=0.0;
00667       int err;
00668       if (ln>0) {
00669         
00670         err=rit1->interp(*lx,*ly,ln,x0,ret);
00671         if (err!=gsl_success) {
00672           size_t nn=0;
00673           int retfs=find_inc_subset(x0,ln,*lx,*ly,nn);
00674           
00675           if (retfs==0 && nn>1 && nn>=rit2->min_size) {
00676             rit2->allocate(nn);
00677             rit2->init(*sx,*sy,nn);
00678             err=rit2->interp(*sx,*sy,nn,x0,ret);
00679             rit2->free();
00680           } else {
00681             O2SCL_ERR2("Interpolation failed in ",
00682                        "smart_interp_vec::interp().",gsl_efailed);
00683             return 0.0;
00684           }
00685           
00686         }
00687         
00688       }
00689       
00690       return ret;
00691     }
00692     
00693     /// Give the value of the derivative \f$ y^{prime}(x=x_0) \f$ .
00694     virtual double deriv(const double x0) {
00695       double ret=0.0;
00696       if (ln>0) {
00697         rit1->deriv(*lx,*ly,ln,x0,ret);
00698       }
00699       return ret;
00700     }                 
00701     
00702     /** \brief Give the value of the second derivative  
00703         \f$ y^{prime \prime}(x=x_0) \f$ .
00704     */
00705     virtual double deriv2(const double x0) {
00706       double ret=0.0;
00707       if (ln>0) {
00708         rit1->deriv2(*lx,*ly,ln,x0,ret);
00709       }
00710       return ret;
00711     }                 
00712     
00713     /// Give the value of the integral \f$ \int_a^{b}y(x)~dx \f$ .
00714     virtual double integ(const double x1, const double x2) {
00715       double ret=0.0;
00716       if (ln>0) {
00717         rit1->integ(*lx,*ly,ln,x1,x2,ret);
00718       }
00719       return ret;
00720     }                 
00721 
00722     /// Default interpolation manager
00723     def_interp_mgr<vec_t,cspline_interp> dim1;
00724 
00725     /// Default interpolation manager
00726     def_interp_mgr<svec_t,cspline_interp> dim2;
00727       
00728 #ifndef DOXYGEN_INTERNAL
00729 
00730   protected:
00731 
00732     /// A lookup function for generic vectors
00733     size_t local_lookup(size_t n, const vec_t &x, double x0) {
00734       size_t row=0, i=0;
00735       while(!gsl_finite(x[i]) && i<n-1) i++;
00736       if (i==n-1) {
00737         return 0;
00738       }
00739       double best=x[i], bdiff=fabs(x[i]-x0);
00740       for(;i<n;i++) {
00741         if (gsl_finite(x[i]) && fabs(x[i]-x0)<bdiff) {
00742           row=i;
00743           best=x[i];
00744           bdiff=fabs(x[i]-x0);
00745         }
00746       }
00747       return row;
00748     }
00749 
00750     /** \brief Try to find the largest monotonically increasing and
00751         finite region around the desired location
00752 
00753         This function looks through the vector \c x near the element
00754         closest to \c x0 to find the largest possible monotonic
00755         region. If it succeeds, it returns \ref gsl_success, and if it
00756         fails, it returns \ref gsl_efailed. It does not call the error
00757         handler.
00758 
00759         \todo Variables \c row and \c row appear to be unused? (2/17/11)
00760     */
00761     int find_inc_subset(const double x0, size_t sz, const vec_t &x, 
00762                         const vec_t &y, size_t &nsz) {
00763 
00764       size_t row=local_lookup(sz,x,x0), row2=row++;
00765       size_t left=row, right=row;
00766       
00767       if (row2>sz) row2=row-1;
00768 
00769       if (!gsl_finite(x[row]) || !gsl_finite(y[row])) {
00770         return gsl_efailed;
00771       }
00772   
00773       // Increasing case
00774       
00775       while(left>0 && x[left-1]<x[left] && 
00776             gsl_finite(x[left-1]) && gsl_finite(y[left-1])) left--;
00777       while(right<sz-1 && x[right]<x[right+1] &&
00778             gsl_finite(x[right+1]) && gsl_finite(y[right+1])) right++;
00779       
00780       nsz=right-left+1;
00781       
00782       if (sxalloc) {
00783         delete sx;
00784         delete sy;
00785       } 
00786       sx=new svec_t(x,left,nsz);
00787       sy=new svec_t(y,left,nsz);
00788       sxalloc=true;
00789       
00790       return 0;
00791     }
00792 
00793 #endif
00794 
00795   };
00796 
00797   // sm_interp typedef 
00798   typedef smart_interp<ovector_const_view,
00799     ovector_const_subvector> sm_interp;
00800   
00801   // sm_interp_vec typedef
00802   typedef smart_interp_vec<ovector_const_view,ovector_const_subvector,ovector,
00803     ovector_alloc> sm_interp_vec;
00804   
00805   /** \brief A specialization of smart_interp for C-style double arrays
00806    */
00807   template<size_t n> class sma_interp :
00808   public smart_interp<double[n],array_const_subvector> {
00809     
00810   public:
00811     
00812     /** \brief Create an interpolation object with user-specified
00813         interpolation types
00814     */
00815   sma_interp(base_interp_mgr<double[n]> &it1, 
00816              base_interp_mgr<array_const_subvector> &it3) :
00817     smart_interp<double[n],array_const_subvector>(it1,it3) {
00818     }
00819     
00820     /// Create an interpolation object with the default interpolation types
00821   sma_interp() : smart_interp<double[n],array_const_subvector>() {
00822     }
00823 
00824   };
00825   
00826   /** \brief A specialization of smart_interp_vec for C-style double arrays
00827    */
00828   template<class arr_t> class sma_interp_vec : 
00829   public smart_interp_vec<arr_t,array_const_subvector,arr_t,
00830     array_alloc<arr_t> >
00831       {
00832         
00833       public:
00834     
00835     
00836     /** \brief Create an interpolation object with user-specified 
00837         interpolation types
00838     */
00839       sma_interp_vec(base_interp_mgr<arr_t> &it, 
00840                      base_interp_mgr<array_const_subvector> &it2,
00841                      size_t n, const arr_t &x, const arr_t &y) :
00842         smart_interp_vec<arr_t,array_const_subvector,arr_t,
00843           array_alloc<arr_t> >(it,it2,n,x,y) {
00844         }
00845         
00846     /// Create an interpolation object with the default interpolation types
00847       sma_interp_vec(size_t n, const arr_t &x, const arr_t &y) :    
00848         smart_interp_vec<arr_t,array_const_subvector,arr_t,
00849           array_alloc<arr_t> >(n,x,y) {
00850         }
00851         
00852       };
00853   
00854   /** \brief Perform inverse linear interpolation
00855 
00856       This function performs inverse linear interpolation of the data
00857       defined by \c x and \c y, finding all points in \c x which have
00858       the property \f$ \mathrm{level} = y(x) \f$. All points for which
00859       this relation holds are put into the vector \c locs. The
00860       previous information contained in vector \c locs before the
00861       function call is destroyed.
00862 
00863       This is the 1-dimensional analog of finding contour levels as
00864       the \ref contour class does for 2 dimensions.
00865   */
00866   template<class vec_t, class vec2_t> int vector_find_level
00867     (double level, size_t n, vec_t &x, vec2_t &y, ovector &locs) {
00868 
00869     if (n<=1) {
00870       O2SCL_ERR2_RET("Need at least two data points in ",
00871                      "vector_find_level().",gsl_einval);
00872     }
00873     
00874     // Ensure that the location vector is empty
00875     locs.free();
00876 
00877     // Find intersections
00878     for(size_t i=0;i<n-1;i++) {
00879 
00880       if ((y[i]<level && y[i+1]>=level) ||
00881           (y[i]>level && y[i+1]<=level)) {
00882         // For each intersection, add the location using linear 
00883         // interpolation
00884         double x0=x[i]+(x[i+1]-x[i])*(level-y[i])/(y[i+1]-y[i]);
00885         locs.push_back(x0);
00886       }
00887     }
00888 
00889     return 0;
00890   }
00891 
00892   /// Compute the integral over <tt>y(x)</tt> using linear interpolation
00893   template<class vec_t> double vector_integ_linear(size_t n, vec_t &x, 
00894                                                    vec_t &y) {
00895 
00896     // Linear interpolation managers
00897     def_interp_mgr<vec_t,linear_interp> lint1;
00898     
00899     // Interpolation object
00900     o2scl_interp<vec_t> si(lint1);
00901 
00902     // Compute full integral
00903     double total=si.integ(x[0],x[n-1],n,x,y);
00904 
00905     return total;
00906   }
00907 
00908   /** \brief Compute the endpoints which enclose the regions whose
00909       integral is equal to \c sum
00910 
00911       Defining a new function, \f$ g(y_0) \f$ which takes as input any
00912       y-value, \f$ y_0 \f$ from the function \f$ y(x) \f$ (specified
00913       with the parameters \c x and \c y) and outputs the integral of
00914       the function \f$ y(x) \f$ over all regions where \f$ y(x) > y_0
00915       \f$. This function inverts \f$ g(y) \f$, taking the value
00916       of an integral as input, and returns the corresponding y-value
00917       in the variable \c lev. 
00918 
00919       In order to make sure that the intepretation of the integral is
00920       unambiguous, this function requires that the first and last values
00921       of \c y are equal, i.e. <tt>y[0]==y[n-1]</tt>. 
00922 
00923       This function is particularly useful, for example, in computing 
00924       the region which defines 68\% around a peak of data, thus 
00925       providing approximate \f$ 1~\sigma \f$ limits. 
00926 
00927       Linear interpolation is used to describe the function \f$ g \f$,
00928       and the precision of this function is limited by this assumption.
00929       This function may also sometimes fail if \c sum is very close to
00930       the minimum or maximum value of the function \f$ g \f$. 
00931 
00932       \comment
00933       Note that the two vector types for x and y must be the
00934       same in order to use o2scl_interp.
00935       \endcomment
00936   */
00937   template<class vec_t> int vector_invert_enclosed_sum
00938     (double sum, size_t n, vec_t &x, vec_t &y, double &lev) {
00939     
00940     if (n<=1) {
00941       O2SCL_ERR2_RET("Need at least two data points in ",
00942                      "vector_invert_enclosed_sum().",gsl_einval);
00943     }
00944 
00945     if (y[0]!=y[n-1]) {
00946       O2SCL_ERR2_RET("The first and last y-values must be equal in ",
00947                      "vector_invert_enclosed_sum().",gsl_einval);
00948     }
00949 
00950     // Construct a sorted list of function values 
00951     ovector ysort(n);
00952     vector_copy(n,y,ysort);
00953     vector_sort<ovector,double>(ysort.size(),ysort);
00954 
00955     // Create list of y-values to perform y-value and integral
00956     // interpolation. We choose values in between the grid points to
00957     // ensure that we don't accidentally land precisely on a peak or
00958     // valley.
00959     ovector ylist;
00960     for(size_t i=0;i<ysort.size()-1;i++) {
00961       if (ysort[i]!=ysort[i+1]) {
00962         ylist.push_back((ysort[i+1]+3.0*ysort[i])/4.0);
00963         ylist.push_back((ysort[i+1]*3.0+ysort[i])/4.0);
00964       }
00965     }
00966     
00967     // Linear interpolation managers
00968     def_interp_mgr<vec_t,linear_interp> lint1;
00969     def_interp_mgr<ovector,linear_interp> mint1;
00970 
00971     // Interpolation objects. We need two, one for the
00972     // user-specified vector type, and one for ovectors
00973     o2scl_interp<vec_t> si(lint1);
00974     o2scl_interp<ovector> si2(mint1);
00975     
00976     // Construct vectors for interpolation
00977     ovector xi, yi;
00978     
00979     size_t nfail=0;
00980 
00981     for(size_t k=0;k<ylist.size();k++) {
00982       double lev_tmp=ylist[k];
00983       ovector locs;
00984       vector_find_level(lev_tmp,n,x,y,locs);
00985       if ((locs.size()%2)!=0) {
00986         nfail++;
00987       } else {
00988         double sum_temp=0.0;
00989         for(size_t i=0;i<locs.size()/2;i++) {
00990           double x0=locs[2*i];
00991           double x1=locs[2*i+1];
00992           sum_temp+=si.integ(x0,x1,n,x,y);
00993         }
00994         xi.push_back(sum_temp);
00995         yi.push_back(lev_tmp);
00996       }
00997     }
00998     if (nfail>10) {
00999       O2SCL_ERR2_RET("More than 10 failures in ",
01000                      "vector_invert_enclosed_sum().",gsl_einval);
01001     }
01002 
01003     lev=si2.interp(sum,xi.size(),xi,yi);
01004     
01005     return 0;
01006   }
01007 
01008 #ifndef DOXYGENP
01009 }
01010 #endif
01011 
01012 #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.