deriv.h

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_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   */
00054   template<class param_t, class func_t> class deriv {
00055 
00056 #ifndef DOXYGEN_INTERNAL
00057     
00058   protected:
00059     
00060     /// A structure for passing the function to second and third derivatives
00061     typedef struct {
00062       public:
00063       /// The pointer to the function
00064       func_t *func;
00065       /// The pointer to the user-specified parameters
00066       param_t *up;
00067     } dpars;
00068     
00069     /// Avoids infinite loops in case the user calls the base class version
00070     bool from_calc;
00071 
00072 #endif
00073 
00074   public:
00075 
00076     deriv() {
00077       verbose=0;
00078       from_calc=false;
00079     }
00080 
00081     virtual ~deriv() {}
00082 
00083     /** 
00084         \brief Calculate the first derivative of \c func w.r.t. x
00085         
00086         After calling calc(), the error may be obtained from 
00087         \ref get_err().
00088     */
00089     virtual double calc(double x, param_t &pa, func_t &func) {
00090       double dx;
00091       from_calc=true;
00092       calc_err(x,pa,func,dx,derr);
00093       from_calc=false;
00094       return dx;
00095     }
00096 
00097     /** \brief Calculate the second derivative of \c func w.r.t. x
00098      */
00099     virtual double calc2(double x, param_t &pa, func_t &func) {
00100       double val;
00101       dpars dp={&func,&pa};
00102       funct_mfptr_noerr<deriv,dpars> mf(this,&deriv::derivfun);
00103       val=calc_int(x,dp,mf);
00104       return val;
00105     }
00106   
00107     /** \brief Calculate the third derivative of \c func w.r.t. x
00108      */
00109     virtual double calc3(double x, param_t &pa, func_t &func) {
00110       double val;
00111       dpars dp={&func,&pa};
00112       funct_mfptr_noerr<deriv,dpars> mf(this,&deriv::derivfun2);
00113       val=calc_int(x,dp,mf);
00114       return val;
00115     }
00116 
00117     /** \brief Get uncertainty of last calculation
00118      */
00119     virtual double get_err() {
00120       return derr;
00121     }
00122 
00123     /** \brief Output control
00124      */
00125     int verbose;
00126     
00127     /** \brief Calculate the first derivative of \c func w.r.t. x and the
00128         uncertainty
00129     */
00130     virtual int calc_err(double x, param_t &pa, func_t &func, double &dfdx, 
00131                          double &err) {
00132       if (from_calc==true) {
00133         set_err_ret("No method specified in calc_err().",gsl_nobase);
00134       }
00135       dfdx=calc(x,pa,func);
00136       err=0.0;
00137       return 0;
00138     }
00139 
00140     /** \brief Calculate the second derivative of \c func w.r.t. x and the
00141         uncertainty
00142     */
00143     virtual int calc2_err(double x, param_t &pa, func_t &func, 
00144                           double &d2fdx2, double &err) {
00145       int ret;
00146       dpars dp={&func,&pa};
00147       funct_mfptr_noerr<deriv,dpars> mf(this,&deriv::derivfun);
00148       ret=calc_err_int(x,dp,mf,d2fdx2,err);
00149       return 0;
00150     }
00151     
00152     /** \brief Calculate the third derivative of \c func w.r.t. x and the
00153         uncertainty
00154     */
00155     virtual int calc3_err(double x, param_t &pa, func_t &func, 
00156                           double &d3fdx3, double &err) {
00157       int ret;
00158       dpars dp={&func,&pa};
00159       funct_mfptr_noerr<deriv,dpars> mf(this,&deriv::derivfun2);
00160       ret=calc_err_int(x,dp,mf,d3fdx3,err);
00161       return 0;
00162     }
00163     
00164     /// Return string denoting type ("deriv")
00165     virtual const char *type() { return "deriv"; }
00166     
00167   protected:
00168 
00169 #ifndef DOXYGEN_INTERNAL
00170 
00171     /** 
00172         \brief Calculate the first derivative of \c func w.r.t. x
00173 
00174         This is an internal version of calc() which is used in
00175         computing second and third derivatives
00176      */
00177     virtual double calc_int(double x, dpars &pa, o2scl::funct<dpars> &func) {
00178       double dx;
00179       from_calc=true;
00180       calc_err_int(x,pa,func,dx,derr);
00181       from_calc=false;
00182       return dx;
00183     }
00184 
00185     /** \brief Calculate the first derivative of \c func w.r.t. x and the
00186         uncertainty
00187 
00188         This is an internal version of calc_err() which is used in
00189         computing second and third derivatives
00190     */
00191     virtual int calc_err_int(double x, dpars &pa, o2scl::funct<dpars> &func, 
00192                              double &dfdx, double &err) {
00193       if (from_calc==true) {
00194         set_err_ret("No method specified in calc_err_int().",gsl_nobase);
00195       }
00196       dfdx=calc_int(x,pa,func);
00197       err=0.0;
00198       return 0;
00199     }
00200     
00201     /// The uncertainity in the most recent derivative computation
00202     double derr;
00203 
00204     /// The function for the second derivative
00205     double derivfun(double x, dpars &dp) {
00206       return calc(x,*(dp.up),*(dp.func));
00207     }
00208 
00209     /// The function for the third derivative
00210     double derivfun2(double x, dpars &dp) {
00211       funct_mfptr_noerr<deriv,dpars> mf(this,&deriv::derivfun);
00212       double val=calc_int(x,dp,mf);
00213       return val;
00214     }
00215     
00216 #endif
00217 
00218   };
00219   
00220 #ifndef DOXYGENP
00221 }
00222 #endif
00223 
00224 #endif

Documentation generated with Doxygen and provided under the GNU Free Documentation License. See License Information for details.

Project hosting provided by SourceForge.net Logo, O2scl Sourceforge Project Page