MechSys  1.0
Computing library for simulations in continuum and discrete mechanics
/home/dorival/mechsys/lib/numerical/multipleroots.h
Go to the documentation of this file.
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
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines