Object-oriented Scientific Computing Library: Version 0.910
vector_derint.h
Go to the documentation of this file.
00001 /*
00002   -------------------------------------------------------------------
00003   
00004   Copyright (C) 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_VECTOR_DERINT_H
00024 #define O2SCL_VECTOR_DERINT_H
00025 
00026 /** \file vector_derint.h
00027     \brief Derivatives of integrals of functions stored in vectors
00028     with implicit fixed-size grid
00029 
00030     Integrate a function over a fixed-size grid specified in a vector.
00031     The integrals are always specified without the factor defining the
00032     grid size (i.e. \f$ \Delta x \f$), so the user must always
00033     multiply the result by the grid size afterwards to get the
00034     true integral.
00035 
00036     These integration rules often expect a minimum number of points,
00037     so for smaller vectors they fall back onto rules which use fewer
00038     points. For empty vectors they return zero, for vectors of length
00039     1, they always return the sole element of the vector, and for
00040     vectors of length 2, they always return the average of the two
00041     elements.
00042 
00043     More points does not always mean higher accuracy. 
00044 */
00045 #include <o2scl/ovector_tlate.h>
00046 #include <o2scl/interp.h>
00047 
00048 #ifndef DOXYGENP
00049 namespace o2scl {
00050 #endif
00051 
00052   /** \brief Derivative of a vector with a three-point formula
00053    */
00054   template<class vec_t, class vec2_t> 
00055     void vector_deriv_threept(size_t n, vec_t &v, vec2_t &v2) {
00056     if (n<=1) {
00057       O2SCL_ERR2("Requested derivative of zero or one-element vector ",
00058                  "in vector_deriv_threept().",gsl_einval);
00059     }
00060     if (n==2) {
00061       double d=v[1]-v[0];
00062       v2[0]=d;
00063       v2[1]=d;
00064       return;
00065     }
00066     v2[0]=-1.5*v[0]+2.0*v[1]-0.5*v[2];
00067     v2[n-1]=1.5*v[n-1]-2.0*v[n-2]+0.5*v[n-3];
00068     for(size_t i=1;i<n-1;i++) {
00069       v2[i]=(v[i+1]-v[i-1])/2.0;
00070     }
00071     return;
00072   }
00073 
00074   /** \brief Derivative of a vector with a three-point formula
00075       using two-point at the edges
00076   */
00077   template<class vec_t, class vec2_t> 
00078     void vector_deriv_threept_tap(size_t n, vec_t &v, vec2_t &v2) {
00079     if (n<=1) {
00080       O2SCL_ERR2("Requested derivative of zero or one-element vector ",
00081                  "in vector_deriv_threept().",gsl_einval);
00082     }
00083     if (n==2) {
00084       double d=v[1]-v[0];
00085       v2[0]=d;
00086       v2[1]=d;
00087       return;
00088     }
00089     // 2-point
00090     v2[0]=v[1]-v[0];
00091     v2[n-1]=v[n-1]-v[n-2];
00092     // 3-point
00093     for(size_t i=1;i<n-1;i++) {
00094       v2[i]=(v[i+1]-v[i-1])/2.0;
00095     }
00096     return;
00097   }
00098 
00099   /** \brief Derivative of a vector with a five-point formula
00100    */
00101   template<class vec_t, class vec2_t> 
00102     void vector_deriv_fivept(size_t n, vec_t &v, vec2_t &v2) {
00103     if (n<=1) {
00104       O2SCL_ERR2("Requested derivative of zero or one-element vector ",
00105                  "in vector_deriv_fivept().",gsl_einval);
00106     }
00107     if (n==2) {
00108       double d=v[1]-v[0];
00109       v2[0]=d;
00110       v2[1]=d;
00111       return;
00112     }
00113     v2[0]=-25.0/12.0*v[0]+4.0*v[1]-3.0*v[2]+4.0/3.0*v[3]-0.25*v[4];
00114     v2[1]=-0.25*v[0]-5.0/6.0*v[1]+1.5*v[2]-0.5*v[3]+v[4]/12.0;
00115     v2[n-2]=-v[n-5]/12.0+0.5*v[n-4]-1.5*v[n-3]+5.0/6.0*v[n-2]+0.25*v[n-1];
00116     v2[n-1]=0.25*v[n-5]-4.0*v[n-4]/3.0+3.0*v[n-3]-4.0*v[n-2]+25.0*v[n-1]/12.0;
00117     for(size_t i=2;i<n-2;i++) {
00118       v2[i]=1.0/12.0*(v[i-2]-v[i+2])+2.0/3.0*(v[i+1]-v[i-1]);
00119     }
00120     return;
00121   }
00122 
00123   /** \brief Derivative of a vector with a five-point formula with 
00124       four- and three-point formulas used at the edges
00125   */
00126   template<class vec_t, class vec2_t> 
00127     void vector_deriv_fivept_tap(size_t n, vec_t &v, vec2_t &v2) {
00128     if (n<=1) {
00129       O2SCL_ERR2("Requested derivative of zero or one-element vector ",
00130                  "in vector_deriv_fivept().",gsl_einval);
00131     }
00132     if (n==2) {
00133       double d=v[1]-v[0];
00134       v2[0]=d;
00135       v2[1]=d;
00136       return;
00137     }
00138     // 3-point
00139     v2[0]=-1.5*v[0]+2.0*v[1]-0.5*v[2];
00140     v2[n-1]=1.5*v[n-1]-2.0*v[n-2]+0.5*v[n-3];
00141     // 4-point
00142     v2[1]=-v[0]/3.0-v[1]/2.0+v[2]-v[3]/6.0;
00143     v2[n-2]=v[n-4]/6.0-v[n-3]+v[n-2]/2.0+v[n-1]/3.0;
00144     // 5-point
00145     for(size_t i=2;i<n-2;i++) {
00146       v2[i]=1.0/12.0*(v[i-2]-v[i+2])+2.0/3.0*(v[i+1]-v[i-1]);
00147     }
00148     return;
00149   }
00150   
00151   /** \brief Derivative from interpolation object
00152    */
00153   template<class ovec_t>
00154   void vector_deriv_interp(size_t n, ovec_t &v, ovec_t &v2, 
00155                            o2scl::base_interp_mgr<ovec_t> &bim) {
00156     ovec_t grid(n);
00157     for(size_t i=0;i<n;i++) grid[i]=((double)i);
00158     o2scl::o2scl_interp_vec<ovec_t> oi(bim,n,grid,v);
00159     for(size_t i=0;i<n;i++) v2[i]=oi.deriv(((double)i));
00160     return;
00161   }
00162 
00163   /** \brief Integrate with an extended trapezoidal rule. 
00164    */
00165   template<class vec_t> double vector_integ_trap(size_t n, vec_t &v) {
00166     if (n==0) {
00167       O2SCL_ERR2_RET("Tried to integrate zero-length vector in ",
00168                      "vector_integ_trap",gsl_einval);
00169     } else if (n==1) {
00170       return v[0];
00171     }
00172     double res=(v[0]+v[n-1])/2.0;
00173     for(size_t i=1;i<n-1;i++) res+=v[i];
00174     return res;
00175   }
00176 
00177   /** \brief Integrate with an extended 3-point rule (extended Simpson's rule)
00178 
00179       \note This uses an untested hack I wrote for even n. 
00180   */
00181   template<class vec_t> double vector_integ_threept(size_t n, vec_t &v) {
00182     if (n==0) {
00183       O2SCL_ERR2_RET("Tried to integrate zero-length vector in ",
00184                      "vector_integ_threept",gsl_einval);
00185     } else if (n==1) {
00186       return v[0];
00187     } else if (n==2) {
00188       return (v[0]+v[1])/2.0;
00189     }
00190     double res=v[0]+v[n-1];
00191     // If true, next terms have a prefactor of 4, otherwise
00192     // the next terms have a prefactor of 2
00193     bool four=true;
00194     for(size_t i=1;i<n/2;i++) {
00195       // Correct if n is even
00196       if (i==n-i-2) {
00197         if (four) res+=(v[i]+v[n-i-1])*3.5;
00198         else res+=(v[i]+v[n-i-1])*2.5;
00199       } else {
00200         if (four) res+=(v[i]+v[n-i-1])*4.0;
00201         else res+=(v[i]+v[n-i-1])*2.0;
00202       }
00203       four=!four;
00204     }
00205     return res/3.0;
00206   }
00207 
00208   /** \brief Integrate with an extended rule for 4 or more points. 
00209 
00210       This function falls back to the equivalent of
00211       vector_integ_threept() for 3 points.
00212   */
00213   template<class vec_t> double vector_integ_extended4(size_t n, vec_t &v) {
00214     if (n==0) {
00215       O2SCL_ERR2_RET("Tried to integrate zero-length vector in ",
00216                      "vector_integ_extended4",gsl_einval);
00217     } else if (n==1) {
00218       return v[0];
00219     } else if (n==2) {
00220       return (v[0]+v[1])/2.0;
00221     } else if (n==3) {
00222       return (v[0]+4.0*v[1]+v[2])/3.0;
00223     }
00224     double res=(v[0]*5.0+v[1]*13.0+v[n-1]*5.0+v[n-2]*13.0)/12.0;
00225     for(size_t i=2;i<n-2;i++) {
00226       res+=v[i];
00227     }
00228     return res;
00229   }
00230 
00231   /** \brief Integrate with Durand's rule for 4 or more points. 
00232 
00233       This function falls back to the equivalent of
00234       vector_integ_threept() for 3 points.
00235   */
00236   template<class vec_t> double vector_integ_durand(size_t n, vec_t &v) {
00237     if (n==0) {
00238       O2SCL_ERR2_RET("Tried to integrate zero-length vector in ",
00239                      "vector_integ_durand",gsl_einval);
00240     } else if (n==1) {
00241       return v[0];
00242     } else if (n==2) {
00243       return (v[0]+v[1])/2.0;
00244     } else if (n==3) {
00245       return (v[0]+4.0*v[1]+v[2])/3.0;
00246     }
00247     double res=(v[0]*4.0+v[1]*11.0+v[n-1]*4.0+v[n-2]*11.0)/10.0;
00248     for(size_t i=2;i<n-2;i++) {
00249       res+=v[i];
00250     }
00251     return res;
00252   }
00253 
00254   /** \brief Integrate with an extended rule for 8 or more points. 
00255 
00256       This function falls back to vector_integ_extended4() 
00257       for less than 8 points.
00258   */
00259   template<class vec_t> double vector_integ_extended8(size_t n, vec_t &v) {
00260     if (n<8) return vector_integ_extended4(n,v);
00261     double res=((v[0]+v[n-1])*17.0+(v[1]+v[n-2])*59.0+(v[2]+v[n-3])*43.0+
00262                 (v[3]+v[n-4])*49.0)/48.0;
00263     for(size_t i=4;i<n-4;i++) {
00264       res+=v[i];
00265     }
00266     return res;
00267   }
00268 
00269   /** \brief Integral from interpolation object
00270    */
00271   template<class ovec_t>
00272     double vector_integ_interp(size_t n, ovec_t &v, 
00273                                base_interp_mgr<ovec_t> &bim) {
00274     ovec_t grid(n);
00275     for(size_t i=0;i<n;i++) grid[i]=((double)i);
00276     o2scl_interp_vec<ovec_t> oi(bim,n,grid,v);
00277     return oi.integ(0.0,((double)(n-1)));
00278   }
00279 
00280 #ifndef DOXYGENP
00281 }
00282 #endif
00283 
00284 #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.