![]() |
Object-oriented Scientific Computing Library: Version 0.910
|
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
Documentation generated with Doxygen. Provided under the GNU Free Documentation License (see License Information).