![]() |
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_QUADRATURE_H 00021 #define MECHSYS_QUADRATURE_H 00022 00023 // STL 00024 #include <cmath> 00025 #include <cfloat> // for DBL_EPSILON 00026 00027 // GSL 00028 #include <gsl/gsl_integration.h> 00029 00030 namespace Numerical 00031 { 00032 00034 enum QMethod 00035 { 00036 QNG_T, 00037 QAGS_T 00038 }; 00039 00044 template<typename Instance> 00045 class Quadrature 00046 { 00047 public: 00048 // Constants 00049 static int WORKSPACE_SIZE; 00050 00051 // Typedefs 00052 typedef double (Instance::*pFun) (double x) const; 00053 00055 Quadrature (Instance const * p2Inst, pFun p2Fun, QMethod method=QAGS_T,double EPSREL=100.0*DBL_EPSILON); // p2Fun == &F(x) 00056 00058 ~Quadrature (); 00059 00060 // Methods 00061 double Integrate (double a, double b); 00062 double CallFun (double x) { return (_p2inst->*_p2fun)(x); } 00063 double LastError () const { return _last_error; } 00064 00065 private: 00066 Instance const * _p2inst; 00067 pFun _p2fun; 00068 QMethod _method; 00069 gsl_integration_workspace * _workspace; 00070 double _epsabs; 00071 double _epsrel; 00072 double _last_error; 00073 size_t _last_neval; 00074 00075 }; // class Quadrature 00076 00077 template<typename Instance> 00078 int Quadrature<Instance>::WORKSPACE_SIZE = 10000; 00079 00084 template<typename Instance> 00085 double __quadrature_call_fun__(double x, void *not_used_for_params) 00086 { 00087 Quadrature<Instance> * p2inst = static_cast<Quadrature<Instance>*>(not_used_for_params); 00088 return p2inst->CallFun(x); 00089 00090 } 00091 00092 00094 00095 00096 template<typename Instance> 00097 inline Quadrature<Instance>::Quadrature(Instance const * p2Inst, pFun p2Fun, QMethod method, double EPSREL) 00098 : _p2inst (p2Inst), 00099 _p2fun (p2Fun), 00100 _method (method), 00101 _epsabs (EPSREL), 00102 _epsrel (EPSREL), 00103 _last_error (-1), 00104 _last_neval (-1) 00105 { 00106 /* Each algorithm computes an approximation to a definite integral of the form, 00107 * 00108 * I = \int_a^b f(x) w(x) dx 00109 * 00110 * where w(x) is a weight function (for general integrands w(x)=1). 00111 * 00112 * The algorithms are built on pairs of quadrature rules, a higher order 00113 * rule and a lower order rule. The higher order rule is used to compute 00114 * the best approximation to an integral over a small range. The 00115 * difference between the results of the higher order rule and the lower 00116 * order rule gives an estimate of the error in the approximation. 00117 * 00118 * The user provides absolute and relative error bounds (epsabs, epsrel) which 00119 * specify the following accuracy requirement 00120 * 00121 * |RESULT - I| <= max(epsabs, epsrel |I|) 00122 * 00123 * where RESULT is the numerical approximation obtained by the algorithm. 00124 * 00125 * The algorithms attempt to estimate the absolute error 00126 * ABSERR = |RESULT - I| in such a way that the following inequality holds, 00127 * 00128 * |RESULT - I| <= ABSERR <= max(epsabs, epsrel |I|) 00129 * 00130 * The routines will fail to converge if the error bounds are too 00131 * stringent, but always return the best approximation obtained up to that 00132 * stage. 00133 * 00134 * The algorithms in QUADPACK use a naming convention based on the 00135 * following letters, 00136 * 00137 * `Q' - quadrature routine 00138 * 00139 * `N' - non-adaptive integrator 00140 * `A' - adaptive integrator 00141 * 00142 * `G' - general integrand (user-defined) 00143 * `W' - weight function with integrand 00144 * 00145 * `S' - singularities can be more readily integrated 00146 * `P' - points of special difficulty can be supplied 00147 * `I' - infinite range of integration 00148 * `O' - oscillatory weight function, cos or sin 00149 * `F' - Fourier integral 00150 * `C' - Cauchy principal value 00151 */ 00152 00153 _workspace = gsl_integration_workspace_alloc (WORKSPACE_SIZE); 00154 } 00155 00156 template<typename Instance> 00157 inline Quadrature<Instance>::~Quadrature() 00158 { 00159 if (_workspace!=NULL) gsl_integration_workspace_free (_workspace); 00160 } 00161 00162 template<typename Instance> 00163 inline double Quadrature<Instance>::Integrate(double a, double b) 00164 { 00165 // Function 00166 gsl_function f; 00167 f.function = &__quadrature_call_fun__<Instance>; 00168 f.params = this; 00169 00170 // Solve 00171 double result; 00172 switch (_method) 00173 { 00174 case QNG_T: 00175 { 00176 /* QNG non-adaptive Gauss-Kronrod integration 00177 * 00178 * The QNG algorithm is a non-adaptive procedure which uses fixed Gauss-Kronrod abscissae to sample the integrand at a 00179 * maximum of 87 points. It is provided for fast integration of smooth functions. 00180 * 00181 * Function: int gsl_integration_qng (const gsl_function * F, double A, double B, double EPSABS, double EPSREL, 00182 * double * RESULT, double * ABSERR, size_t * NEVAL) 00183 * 00184 * This function applies the Gauss-Kronrod 10-point, 21-point, 43-point and 87-point integration rules in succession 00185 * until an estimate of the integral of f over (a,b) is achieved within the desired absolute and relative error limits, 00186 * EPSABS and EPSREL. The function returns the final approximation, RESULT, an estimate of the absolute error, ABSERR 00187 * and the number of function evaluations used, NEVAL. The Gauss-Kronrod rules are designed in such a way that each 00188 * rule uses all the results of its predecessors, in order to minimize the total number of function evaluations. 00189 */ 00190 00191 gsl_integration_qng (&f, a, b, _epsabs, _epsrel, &result, &_last_error, &_last_neval); 00192 00193 break; 00194 } 00195 case QAGS_T: 00196 { 00197 /* QAGS adaptive integration with singularities 00198 * 00199 * The presence of an integrable singularity in the integration region causes an adaptive routine to concentrate new 00200 * subintervals around the singularity. As the subintervals decrease in size the successive approximations to the integral 00201 * converge in a limiting fashion. This approach to the limit can be accelerated using an extrapolation procedure. The 00202 * QAGS algorithm combines adaptive bisection with the Wynn epsilon-algorithm to speed up the integration of many types of 00203 * integrable singularities. 00204 * 00205 * Function: int gsl_integration_qags (const gsl_function * f, double a, double b, double epsabs, double epsrel, size_t 00206 * limit, gsl_integration_workspace * workspace, double * result, double * abserr) 00207 * 00208 * This function applies the Gauss-Kronrod 21-point integration rule adaptively until an estimate of the integral of f 00209 * over (a,b) is achieved within the desired absolute and relative error limits, epsabs and epsrel. The results are 00210 * extrapolated using the epsilon-algorithm, which accelerates the convergence of the integral in the presence of 00211 * discontinuities and integrable singularities. The function returns the final approximation from the extrapolation, 00212 * result, and an estimate of the absolute error, abserr. The subintervals and their results are stored in the memory 00213 * provided by workspace. The maximum number of subintervals is given by limit, which may not exceed the allocated size of 00214 * the workspace. 00215 */ 00216 00217 gsl_integration_qags (&f, a, b, _epsabs, _epsrel, WORKSPACE_SIZE, _workspace, &result, &_last_error); 00218 00219 break; 00220 } 00221 }; 00222 00223 // Results 00224 return result; 00225 } 00226 00227 }; // namespace Numerical 00228 00229 #endif // MECHSYS_QUADRATURE_H