![]() |
MechSys
1.0
Computing library for simulations in continuum and discrete mechanics
|
00001 /************************************************************************ 00002 * MechSys - Open Library for Mechanical Systems * 00003 * Copyright (C) 2005 Dorival M. Pedroso, Raul Durand * 00004 * Copyright (C) 2009 Sergio Galindo * 00005 * * 00006 * This program is free software: you can redistribute it and/or modify * 00007 * it under the terms of the GNU General Public License as published by * 00008 * the Free Software Foundation, either version 3 of the License, or * 00009 * any later version. * 00010 * * 00011 * This program is distributed in the hope that it will be useful, * 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 00014 * GNU General Public License for more details. * 00015 * * 00016 * You should have received a copy of the GNU General Public License * 00017 * along with this program. If not, see <http://www.gnu.org/licenses/> * 00018 ************************************************************************/ 00019 00020 #ifndef MECHSYS_NUMDIFF_H 00021 #define MECHSYS_NUMDIFF_H 00022 00023 // STL 00024 #include <cmath> 00025 #include <cfloat> // for DBL_EPSILON 00026 00027 // GSL 00028 #include <gsl/gsl_math.h> 00029 #include <gsl/gsl_deriv.h> 00030 00031 // MechSys 00032 #include <mechsys/util/string.h> 00033 #include <mechsys/util/fatal.h> 00034 00035 namespace Numerical 00036 { 00037 00038 template<typename Instance> 00039 class Diff // numerical differentiation 00040 { 00041 public: 00042 // Typedefs 00043 typedef double (Instance::*pFun) (double x); 00044 00045 // Constructor 00046 Diff (Instance * p2Inst); 00047 00048 // Methods 00049 double DyDx (pFun p2Fun, double AtX, double StepSize=1.0e-8); 00050 00051 // Internal methods 00052 double CallFun (double x) const { return (_p2inst->*_p2fun)(x); } 00053 00054 // Data 00055 int Method; 00056 double LastAbsErr; 00057 00058 private: 00059 Instance * _p2inst; 00060 pFun _p2fun; 00061 }; 00062 00065 template<typename Instance> 00066 double __numdiff_call_fun__ (double x, void * not_used_for_params) 00067 { 00068 Diff<Instance> * p2inst = static_cast<Diff<Instance>*>(not_used_for_params); 00069 return p2inst->CallFun (x); 00070 } 00071 00072 00074 00075 00076 template<typename Instance> 00077 inline Diff<Instance>::Diff (Instance * p2Inst) 00078 : Method (0), 00079 LastAbsErr (0.), 00080 _p2inst (p2Inst) 00081 {} 00082 00083 template<typename Instance> 00084 inline double Diff<Instance>::DyDx (pFun p2Fun, double AtX, double h) 00085 { 00086 // set pointer to function 00087 _p2fun = p2Fun; 00088 00089 // set GSL function 00090 gsl_function f; 00091 f.function = &__numdiff_call_fun__<Instance>; 00092 f.params = this; 00093 00094 // calculate derivative 00095 double result; 00096 if (Method==-1) gsl_deriv_backward (&f, AtX, h, &result, &LastAbsErr); 00097 else if (Method==0) gsl_deriv_central (&f, AtX, h, &result, &LastAbsErr); 00098 else if (Method==1) gsl_deriv_forward (&f, AtX, h, &result, &LastAbsErr); 00099 else throw new Fatal("Numerical::Diff: Method==%d is invalid. Valid ones are -1=backward, 0=central, 1=forward",Method); 00100 return result; 00101 } 00102 00103 }; // namespace Numerical 00104 00105 #endif // MECHSYS_NUMDIFF_H