00001 /* 00002 ------------------------------------------------------------------- 00003 00004 Copyright (C) 2006, 2007, 2008, 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_DERIV_H 00024 #define O2SCL_DERIV_H 00025 00026 #include <iostream> 00027 #include <cmath> 00028 #include <o2scl/collection.h> 00029 #include <o2scl/funct.h> 00030 00031 #ifndef DOXYGENP 00032 namespace o2scl { 00033 #endif 00034 00035 /** 00036 \brief Numerical differentiation base 00037 00038 This base class does not perform any actual differentiation. 00039 Use one of the children cern_deriv, gsl_deriv, or eqi_deriv 00040 instead. 00041 00042 This base class contains some code to automatically apply 00043 the first derivative routines to compute second or third 00044 derivatives. The error estimates for these will likely 00045 be underestimated. 00046 00047 \note Because this class template aims to automatically provide 00048 second and third derivatives, one must overload either both 00049 calc() and calc_int() or both calc_err() and calc_err_int(). 00050 00051 \future Improve the methods for second and third derivatives 00052 00053 \future This does not have pure virtual functions, but I'd still 00054 like to prevent the user from directly instantiating a deriv 00055 object. 00056 */ 00057 template<class param_t, class func_t> class deriv { 00058 00059 #ifndef DOXYGEN_INTERNAL 00060 00061 protected: 00062 00063 /// A structure for passing the function to second and third derivatives 00064 typedef struct { 00065 public: 00066 /// The pointer to the function 00067 func_t *func; 00068 /// The pointer to the user-specified parameters 00069 param_t *up; 00070 } dpars; 00071 00072 /// Avoids infinite loops in case the user calls the base class version 00073 bool from_calc; 00074 00075 #endif 00076 00077 public: 00078 00079 deriv() { 00080 verbose=0; 00081 from_calc=false; 00082 } 00083 00084 virtual ~deriv() {} 00085 00086 /** 00087 \brief Calculate the first derivative of \c func w.r.t. x 00088 00089 After calling calc(), the error may be obtained from 00090 \ref get_err(). 00091 */ 00092 virtual double calc(double x, param_t &pa, func_t &func) { 00093 double dx; 00094 from_calc=true; 00095 calc_err(x,pa,func,dx,derr); 00096 from_calc=false; 00097 return dx; 00098 } 00099 00100 /** \brief Calculate the second derivative of \c func w.r.t. x 00101 */ 00102 virtual double calc2(double x, param_t &pa, func_t &func) { 00103 double val; 00104 dpars dp={&func,&pa}; 00105 funct_mfptr_noerr<deriv,dpars> mf(this,&deriv::derivfun); 00106 val=calc_int(x,dp,mf); 00107 return val; 00108 } 00109 00110 /** \brief Calculate the third derivative of \c func w.r.t. x 00111 */ 00112 virtual double calc3(double x, param_t &pa, func_t &func) { 00113 double val; 00114 dpars dp={&func,&pa}; 00115 funct_mfptr_noerr<deriv,dpars> mf(this,&deriv::derivfun2); 00116 val=calc_int(x,dp,mf); 00117 return val; 00118 } 00119 00120 /** \brief Get uncertainty of last calculation 00121 */ 00122 virtual double get_err() { 00123 return derr; 00124 } 00125 00126 /** \brief Output control 00127 */ 00128 int verbose; 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, double &dfdx, 00134 double &err) { 00135 if (from_calc==true) { 00136 set_err_ret("No method specified in calc_err().",gsl_nobase); 00137 } 00138 dfdx=calc(x,pa,func); 00139 err=0.0; 00140 return 0; 00141 } 00142 00143 /** \brief Calculate the second derivative of \c func w.r.t. x and the 00144 uncertainty 00145 */ 00146 virtual int calc2_err(double x, param_t &pa, func_t &func, 00147 double &d2fdx2, double &err) { 00148 int ret; 00149 dpars dp={&func,&pa}; 00150 funct_mfptr_noerr<deriv,dpars> mf(this,&deriv::derivfun); 00151 ret=calc_err_int(x,dp,mf,d2fdx2,err); 00152 return 0; 00153 } 00154 00155 /** \brief Calculate the third derivative of \c func w.r.t. x and the 00156 uncertainty 00157 */ 00158 virtual int calc3_err(double x, param_t &pa, func_t &func, 00159 double &d3fdx3, double &err) { 00160 int ret; 00161 dpars dp={&func,&pa}; 00162 funct_mfptr_noerr<deriv,dpars> mf(this,&deriv::derivfun2); 00163 ret=calc_err_int(x,dp,mf,d3fdx3,err); 00164 return 0; 00165 } 00166 00167 /// Return string denoting type ("deriv") 00168 virtual const char *type() { return "deriv"; } 00169 00170 protected: 00171 00172 #ifndef DOXYGEN_INTERNAL 00173 00174 /** 00175 \brief Calculate the first derivative of \c func w.r.t. x 00176 00177 This is an internal version of calc() which is used in 00178 computing second and third derivatives 00179 */ 00180 virtual double calc_int(double x, dpars &pa, o2scl::funct<dpars> &func) { 00181 double dx; 00182 from_calc=true; 00183 calc_err_int(x,pa,func,dx,derr); 00184 from_calc=false; 00185 return dx; 00186 } 00187 00188 /** \brief Calculate the first derivative of \c func w.r.t. x and the 00189 uncertainty 00190 00191 This is an internal version of calc_err() which is used in 00192 computing second and third derivatives 00193 */ 00194 virtual int calc_err_int(double x, dpars &pa, o2scl::funct<dpars> &func, 00195 double &dfdx, double &err) { 00196 if (from_calc==true) { 00197 set_err_ret("No method specified in calc_err_int().",gsl_nobase); 00198 } 00199 dfdx=calc_int(x,pa,func); 00200 err=0.0; 00201 return 0; 00202 } 00203 00204 /// The uncertainity in the most recent derivative computation 00205 double derr; 00206 00207 /// The function for the second derivative 00208 double derivfun(double x, dpars &dp) { 00209 return calc(x,*(dp.up),*(dp.func)); 00210 } 00211 00212 /// The function for the third derivative 00213 double derivfun2(double x, dpars &dp) { 00214 funct_mfptr_noerr<deriv,dpars> mf(this,&deriv::derivfun); 00215 double val=calc_int(x,dp,mf); 00216 return val; 00217 } 00218 00219 #endif 00220 00221 }; 00222 00223 #ifndef DOXYGENP 00224 } 00225 #endif 00226 00227 #endif
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