![]() |
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_MULTIPLEROOTS_H 00021 #define MECHSYS_MULTIPLEROOTS_H 00022 00023 // STL 00024 #include <cmath> 00025 #include <cfloat> // for DBL_EPSILON 00026 00027 // MechSys 00028 #include <mechsys/numerical/brentroot.h> 00029 #include <mechsys/numerical/quadrature.h> 00030 #include <mechsys/util/fatal.h> 00031 #include <mechsys/util/array.h> 00032 #include <mechsys/util/util.h> 00033 00034 namespace Numerical 00035 { 00036 00041 template<typename Instance> 00042 class MultipleRoots 00043 { 00044 public: 00045 // Typedefs 00046 typedef double (Instance::*pFun) (double x) const; 00047 00049 MultipleRoots (Instance const * p2Inst, pFun F, pFun G, pFun H, double Tol=sqrt(DBL_EPSILON), double Gamma=0.001); 00050 00051 // Methods 00052 void Solve (double A, double B, Array<double> & R, bool Single=false) const; 00053 double NRoots (double a, double b) const; 00054 void SetTol (double Tol) { _tol = Tol; } 00055 void SetGam (double Gam) { _gam = Gam; } 00056 void SetQuadError(double Err) { _qerr= Err; } 00057 int Ncalls () const { return _N_calls; } 00058 int Mcalls () const { return _M_calls; } 00059 void ResetNcalls () { _N_calls = 0; } 00060 void ResetMcalls () { _M_calls = 0; } 00061 00062 private: 00063 Instance const * _p2inst; 00064 pFun _F; 00065 pFun _G; 00066 pFun _H; 00067 double _tol; 00068 double _gam; 00069 double _qerr; 00070 mutable int _N_calls; 00071 mutable int _M_calls; 00072 00073 // private functions 00074 double _M (double x) const; 00075 void _find_roots (double a, double b, Array<double> & R) const; 00076 00077 }; // class MultipleRoots 00078 00079 00081 00082 00083 /* public */ 00084 00085 template<typename Instance> 00086 inline MultipleRoots<Instance>::MultipleRoots(Instance const * p2Inst, pFun F, pFun G, pFun H, double Tol, double Gamma) 00087 : _p2inst (p2Inst), 00088 _F (F), 00089 _G (G), 00090 _H (H), 00091 _tol (Tol), 00092 _gam (Gamma), 00093 _qerr (1.0e-3), 00094 _N_calls (0), 00095 _M_calls (0) 00096 { 00097 } 00098 00099 template<typename Instance> 00100 inline void MultipleRoots<Instance>::Solve(double A, double B, Array<double> & R, bool Single) const 00101 { 00102 // No roots 00103 R.Resize(0); 00104 00105 // Single Root - using Newton's method 00106 if (Single) 00107 { 00108 double f0 = (_p2inst->*_F)(A); 00109 double f1 = (_p2inst->*_F)(B); 00110 if (f0*f1<0.0) 00111 { 00112 double ak = f0/(f0-f1); 00113 for (_N_calls=1; _N_calls<=30; ++_N_calls) 00114 { 00115 double fak = (_p2inst->*_F)(ak); 00116 if (fabs(fak)<_tol) { R.Push(ak); return; } 00117 ak += -fak/(_p2inst->*_G)(ak); 00118 } 00119 throw new Fatal(_("MultipleRoots::Solve: Did not converge for %d iterations"),30); 00120 } 00121 } 00122 else _find_roots(A,B,R); // Recursive method 00123 } 00124 00125 template<typename Instance> 00126 inline double MultipleRoots<Instance>::NRoots(double a, double b) const 00127 { 00128 double f0 = (_p2inst->*_F)(a); 00129 double f1 = (_p2inst->*_F)(b); 00130 double g0 = (_p2inst->*_G)(a); 00131 double g1 = (_p2inst->*_G)(b); 00132 00133 Quadrature<MultipleRoots> qu(this, &MultipleRoots::_M, /*method*/Numerical::QAGS_T, /*EPSREL*/0.001); 00134 double res1 = -_gam*qu.Integrate(a,b); 00135 double res2 = atan(_gam*(f0*g1-f1*g0)/(f0*f1+g0*g1*_gam*_gam+_tol)); 00136 00137 _N_calls++; 00138 00139 return (res1+res2)/Util::Pi(); 00140 } 00141 00142 00143 /* private */ 00144 00145 template<typename Instance> 00146 inline double MultipleRoots<Instance>::_M(double x) const 00147 { 00148 double f = (_p2inst->*_F)(x); 00149 double g = (_p2inst->*_G)(x); 00150 double h = (_p2inst->*_H)(x); 00151 00152 _M_calls++; 00153 00154 double res = (f*h-g*g)/(f*f+_gam*_gam*g*g+_tol); 00155 //std::cout << "f=" << f << ", g=" << g << ", h=" << h << ", res=" << res << std::endl; 00156 if (res!=res) throw new Fatal (_("MultipleRoots::_M: integrand function is NaN")); 00157 return res; 00158 } 00159 00160 template<typename Instance> 00161 inline void MultipleRoots<Instance>::_find_roots(double a, double b, Array<double> & R) const 00162 { 00163 double n = NRoots(a,b); 00164 long nr = lround(n); 00165 //std::cout << "a=" << a << ", b=" << b << ", nr=" << n << std::endl; 00166 if (nr==0) return; 00167 if (nr==1 && ((_p2inst->*_F)(a)*(_p2inst->*_F)(b)<0)) 00168 { 00169 BrentRoot<Instance> br(_p2inst, _F); 00170 R.Push(br.Solve(a,b)); 00171 } 00172 else 00173 { 00174 double mid = (a+b)/2.0; 00175 _find_roots (a , mid , R); 00176 _find_roots (mid+_tol , b , R); 00177 } 00178 } 00179 00180 00181 }; // namespace Numerical 00182 00183 #endif // MECHSYS_MULTIPLEROOTS_H