00001 /* 00002 ------------------------------------------------------------------- 00003 00004 Copyright (C) 2006, 2007, 2008, 2009, 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_CERN_DERIV_H 00024 #define O2SCL_CERN_DERIV_H 00025 00026 #include <o2scl/deriv.h> 00027 #include <o2scl/funct.h> 00028 00029 #ifndef DOXYGENP 00030 namespace o2scl { 00031 #endif 00032 00033 /** 00034 \brief Numerical differentiation routine (CERNLIB) 00035 00036 This uses Romberg extrapolation to compute the 00037 derivative with the finite-differencing formula 00038 \f[ 00039 f^{\prime}(x) = [f(x+h)-f(x-h)]/(2h) 00040 \f] 00041 00042 If \ref root::verbose is greater than zero, then each iteration 00043 prints out the extrapolation table, and if \ref root::verbose 00044 is greater than 1, then a keypress is required at the 00045 end of each iteration. 00046 00047 For sufficiently difficult functions, the derivative computation 00048 can fail, and will call the error handler and return zero with 00049 zero error. 00050 00051 Based on the CERNLIB routine DERIV, which was 00052 based on \ref Rutishauser63 and is documented at 00053 http://wwwasdoc.web.cern.ch/wwwasdoc/shortwrupsdir/d401/top.html 00054 00055 An example demonstrating the usage of this class is 00056 given in <tt>examples/ex_deriv.cpp</tt> and the \ref ex_deriv_sect . 00057 00058 \note Second and third derivatives are computed by naive nested 00059 applications of the formula for the first derivative and the 00060 uncertainty for these will likely be underestimated. 00061 00062 \comment 00063 - Maybe we should consider moving the table size to a template 00064 parameter? (1/29/07 - Probably not, as we'd have to re-derive 00065 the coefficients for sizes other than 10) 00066 \endcomment 00067 */ 00068 template<class param_t, class func_t=funct<param_t> > 00069 class cern_deriv : public deriv<param_t,func_t> { 00070 00071 public: 00072 00073 /// A scaling factor (default 1.0) 00074 double delta; 00075 00076 /// Extrapolation tolerance (default is \f$ 5 \times 10^{14} \f$) 00077 double eps; 00078 00079 cern_deriv() { 00080 00081 dx[0]=0.0256; 00082 dx[1]=0.0192; 00083 dx[2]=0.0128; 00084 dx[3]=0.0096; 00085 dx[4]=0.0064; 00086 dx[5]=0.0048; 00087 dx[6]=0.0032; 00088 dx[7]=0.0024; 00089 dx[8]=0.0016; 00090 dx[9]=0.0012; 00091 00092 w[1][1]=1.3333333333333333; 00093 w[3][1]=1.0666666666666667; 00094 w[5][1]=1.0158730158730159; 00095 w[7][1]=1.0039215686274510; 00096 00097 w[2][1]=3.3333333333333333e-1; 00098 w[4][1]=6.6666666666666667e-2; 00099 w[6][1]=1.5873015873015873e-2; 00100 w[8][1]=3.9215686274509804e-3; 00101 00102 w[0][2]=2.2857142857142857; 00103 w[2][2]=1.1636363636363636; 00104 w[4][2]=1.0364372469635628; 00105 w[6][2]=1.0088669950738916; 00106 w[8][2]=1.0022021042329337; 00107 00108 w[1][2]=1.2857142857142857; 00109 w[3][2]=1.6363636363636364e-1; 00110 w[5][2]=3.6437246963562753e-2; 00111 w[7][2]=8.8669950738916256e-3; 00112 w[9][2]=2.2021042329336922e-3; 00113 00114 w[0][3]=1.8000000000000000; 00115 w[2][3]=1.1250000000000000; 00116 w[4][3]=1.0285714285714286; 00117 w[6][3]=1.0069930069930070; 00118 w[8][3]=1.0017391304347826; 00119 00120 w[1][3]=8.0000000000000000e-1; 00121 w[3][3]=1.2500000000000000e-1; 00122 w[5][3]=2.8571428571428571e-2; 00123 w[7][3]=6.9930069930069930e-3; 00124 w[9][3]=1.7391304347826087e-3; 00125 00126 delta=1.0; 00127 eps=5.0e-14; 00128 } 00129 00130 /** \brief Calculate the first derivative of \c func w.r.t. x and the 00131 uncertainty 00132 */ 00133 virtual int calc_err(double x, param_t &pa, func_t &func, 00134 double &dfdx, double &err) { 00135 00136 double t[10][10], a[10], del, hh; 00137 bool lev[10]={1,0,1,0,1,0,1,0,1,0}, lmt; 00138 int is, k, m; 00139 00140 del=10.0*fabs(delta); 00141 is=10; 00142 00143 do { 00144 is--; 00145 del=del/10.0; 00146 00147 if (is==0 || x+del*dx[9]==x) { 00148 delta=del; 00149 dfdx=0.0; 00150 err=0.0; 00151 O2SCL_ERR_RET 00152 ("Calculation of derivative failed in cern_deriv::calc().", 00153 gsl_efailed); 00154 } 00155 00156 for(k=0;k<=9;k++) { 00157 hh=del*dx[k]; 00158 t[k][0]=(func(x+hh,pa)-func(x-hh,pa))/(hh+hh); 00159 a[k]=t[k][0]; 00160 } 00161 00162 if (a[0]>=a[9]) { 00163 for(k=0;k<=9;k++) a[k]=-a[k]; 00164 } 00165 00166 lmt=true; 00167 for(k=1;k<=9;k++) { 00168 hh=a[k-1]-a[k]; 00169 lmt=(lmt && (hh<=0.0 || fabs(hh)<=eps*fabs(a[k]))); 00170 } 00171 00172 if (this->verbose>0) { 00173 std::cout << "cern_deriv, iteration: " << 10-is << std::endl; 00174 std::cout << "(hh, a[k], derivative) list: " 00175 << std::endl; 00176 for(k=1;k<=9;k++) { 00177 std::cout << a[k-1]-a[k] << " " << eps*fabs(a[k]) << " " 00178 << t[k][0] << std::endl; 00179 } 00180 std::cout << "Converged: " << lmt << std::endl; 00181 if (this->verbose>1) { 00182 char ch; 00183 std::cin >> ch; 00184 } 00185 } 00186 00187 } while (lmt==false); 00188 00189 for(m=1;m<=9;m++) { 00190 for(k=0;k<=9-m;k++) { 00191 if (lev[m]) { 00192 t[k][m]=w[m-1][1]*t[k+1][m-1]-w[m][1]*t[k][m-1]; 00193 } else if (lev[k]) { 00194 t[k][m]=w[m-1][2]*t[k+1][m-1]-w[m][2]*t[k][m-1]; 00195 } else { 00196 t[k][m]=w[m-1][3]*t[k+1][m-1]-w[m][3]*t[k][m-1]; 00197 } 00198 } 00199 } 00200 dfdx=t[0][9]; 00201 if (dfdx!=0.0) err=(dfdx-t[0][8])/dfdx; 00202 else err=0.0; 00203 delta=del; 00204 00205 return 0; 00206 } 00207 00208 /// Return string denoting type ("cern_deriv") 00209 virtual const char *type() { return "cern_deriv"; } 00210 00211 protected: 00212 00213 #ifndef DOXYGEN_INTERNAL 00214 00215 /** 00216 \brief Calculate the first derivative of \c func w.r.t. x 00217 00218 This is an internal version of calc() which is used in 00219 computing second and third derivatives 00220 */ 00221 virtual int calc_err_int 00222 (double x, typename deriv<param_t,func_t>::dpars &pa, 00223 funct<typename deriv<param_t,func_t>::dpars> &func, 00224 double &dfdx, double &err) { 00225 00226 double t[10][10], a[10], del, hh; 00227 bool lev[10]={1,0,1,0,1,0,1,0,1,0}, lmt; 00228 int is, k, m; 00229 00230 del=10.0*fabs(delta); 00231 is=10; 00232 00233 do { 00234 is--; 00235 del=del/10.0; 00236 if (is==0 || x+del*dx[9]==x) { 00237 delta=del; 00238 O2SCL_ERR("Calculation of derivative failed in cern_deriv::calc().", 00239 gsl_efailed); 00240 dfdx=0.0; 00241 err=0.0; 00242 return 1; 00243 } 00244 00245 for(k=0;k<=9;k++) { 00246 hh=del*dx[k]; 00247 t[k][0]=(func(x+hh,pa)-func(x-hh,pa))/(hh+hh); 00248 a[k]=t[k][0]; 00249 } 00250 00251 if (a[0]>=a[9]) { 00252 for(k=0;k<=9;k++) a[k]=-a[k]; 00253 } 00254 00255 lmt=true; 00256 for(k=1;k<=9;k++) { 00257 hh=a[k-1]-a[k]; 00258 lmt=(lmt && (hh<=0.0 || fabs(hh)<=eps*fabs(a[k]))); 00259 } 00260 00261 } while (lmt==false); 00262 00263 for(m=1;m<=9;m++) { 00264 for(k=0;k<=9-m;k++) { 00265 if (lev[m]) { 00266 t[k][m]=w[m-1][1]*t[k+1][m-1]-w[m][1]*t[k][m-1]; 00267 } else if (lev[k]) { 00268 t[k][m]=w[m-1][2]*t[k+1][m-1]-w[m][2]*t[k][m-1]; 00269 } else { 00270 t[k][m]=w[m-1][3]*t[k+1][m-1]-w[m][3]*t[k][m-1]; 00271 } 00272 } 00273 } 00274 dfdx=t[0][9]; 00275 if (dfdx!=0.0) err=(dfdx-t[0][8])/dfdx; 00276 else err=0.0; 00277 delta=del; 00278 00279 return 0; 00280 } 00281 00282 /// \name Storage for the fixed coefficients 00283 //@{ 00284 double dx[10]; 00285 double w[10][4]; 00286 //@} 00287 00288 #endif 00289 00290 }; 00291 00292 #ifndef DOXYGENP 00293 } 00294 #endif 00295 00296 #endif 00297 00298
Documentation generated with Doxygen and provided under the GNU Free Documentation License. See License Information for details.
Project hosting provided by
,
O2scl Sourceforge Project Page