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