Object-oriented Scientific Computing Library: Version 0.910
gsl_inte_qag.h
00001 /*
00002   -------------------------------------------------------------------
00003   
00004   Copyright (C) 2006-2012, Jerry Gagelman
00005   and Andrew W. Steiner
00006   
00007   This file is part of O2scl.
00008   
00009   O2scl is free software; you can redistribute it and/or modify
00010   it under the terms of the GNU General Public License as published by
00011   the Free Software Foundation; either version 3 of the License, or
00012   (at your option) any later version.
00013   
00014   O2scl is distributed in the hope that it will be useful,
00015   but WITHOUT ANY WARRANTY; without even the implied warranty of
00016   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017   GNU General Public License for more details.
00018   
00019   You should have received a copy of the GNU General Public License
00020   along with O2scl. If not, see <http://www.gnu.org/licenses/>.
00021 
00022   -------------------------------------------------------------------
00023 */
00024 /* 
00025  * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 Brian Gough
00026  * 
00027  * This program is free software; you can redistribute it and/or modify
00028  * it under the terms of the GNU General Public License as published by
00029  * the Free Software Foundation; either version 3 of the License, or (at
00030  * your option) any later version.
00031  * 
00032  * This program is distributed in the hope that it will be useful, but
00033  * WITHOUT ANY WARRANTY; without even the implied warranty of
00034  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00035  * General Public License for more details.
00036  * 
00037  * You should have received a copy of the GNU General Public License
00038  * along with this program; if not, write to the Free Software
00039  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 
00040  * 02110-1301, USA.
00041  */
00042 #ifndef O2SCL_GSL_INTE_QAG_H
00043 #define O2SCL_GSL_INTE_QAG_H
00044 
00045 #include <o2scl/inte.h>
00046 #include <o2scl/gsl_inte_kronrod.h>
00047 #include <o2scl/funct.h>
00048 #include <o2scl/string_conv.h>
00049 
00050 #ifndef DOXYGENP
00051 namespace o2scl {
00052 #endif
00053 
00054   /** \brief Adaptive numerical integration of a function (without 
00055       singularities) on a bounded interval (GSL)
00056       
00057       Adaptive integration of a univariate function requires two main
00058       procedures: approximating the integral on a bounded interval,
00059       and estimating the approximation error. The algorithm
00060       recursively refines the interval, computing the integral and its
00061       error estimate on each subinterval, until the total error
00062       estimate over \b all subintervals falls within the
00063       user-specified tolerance. The value returned is the sum of the
00064       (approximated) integrals over all subintervals.
00065          
00066       See \ref gslinte_subsect in the User's guide for general
00067       information about the GSL integration classes.
00068 
00069       \future There are a few fine-tuned parameters which should
00070       be re-expressed as data members in the convergence tests.
00071       \future Should QUADPACK parameters in round-off tests be subject 
00072       to adjustments by the end user?
00073       \future Add functions to examine the contents of the workspace
00074       to detect regions where the integrand may be problematic;
00075       possibly call these functions automatically depending on
00076       verbosity settings.
00077   */
00078   template<class func_t=funct> class gsl_inte_qag : 
00079   public gsl_inte_kronrod<func_t> {
00080     
00081   public:
00082 
00083   /// Create an integrator with the specified rule
00084   gsl_inte_qag() {
00085   }
00086   
00087   virtual ~gsl_inte_qag() {}
00088     
00089   /** \brief Integrate function \c func from \c a to \c b and place
00090       the result in \c res and the error in \c err
00091   */
00092   virtual int integ_err(func_t &func, double a, double b, 
00093                         double &res, double &err) {
00094     this->last_conv=0;
00095     return qag(func,a,b,this->tol_abs,this->tol_rel,&res,&err);
00096   }
00097 
00098 #ifndef DOXYGEN_INTERNAL
00099 
00100   protected:
00101 
00102   /** \brief Perform an adaptive integration given the coefficients,
00103       and returning \c result
00104 
00105       \future Just move this function to integ_err().
00106   */
00107   int qag(func_t &func, const double a, const double b, 
00108           const double l_epsabs, const double l_epsrel, 
00109           double *result, double *abserr) {
00110     
00111     double area, errsum;
00112     double result0, abserr0, resabs0, resasc0;
00113     double tolerance;
00114     size_t iteration = 0;
00115     int roundoff_type1 = 0, roundoff_type2 = 0, error_type = 0;
00116       
00117     double round_off;
00118       
00119     /* Initialize results */
00120     
00121     this->w->initialise(a,b);
00122     
00123     *result = 0;
00124     *abserr = 0;
00125       
00126     if (l_epsabs <= 0 && 
00127         (l_epsrel < 50 * GSL_DBL_EPSILON || l_epsrel < 0.5e-28)) {
00128       this->last_iter=0;
00129       std::string estr="Tolerance cannot be achieved with given ";
00130       estr+="value of tol_abs, "+dtos(l_epsabs)+", and tol_rel, "+
00131         dtos(l_epsrel)+", in gsl_inte_qag::qag().";
00132       O2SCL_ERR_RET(estr.c_str(),gsl_ebadtol);
00133     }
00134         
00135     /* perform the first integration */
00136     
00137     gauss_kronrod(func,a,b,&result0,&abserr0,&resabs0,&resasc0);
00138     
00139     this->w->set_initial_result(result0,abserr0);
00140       
00141     /* Test on accuracy */
00142       
00143     tolerance = GSL_MAX_DBL(l_epsabs, l_epsrel * fabs (result0));
00144       
00145     /* need IEEE rounding here to match original quadpack behavior */
00146           
00147     round_off=gsl_coerce_double(50 * GSL_DBL_EPSILON * resabs0);
00148           
00149     if (abserr0 <= round_off && abserr0 > tolerance) {
00150 
00151       *result = result0;
00152       *abserr = abserr0;
00153 
00154       // We start with 1 here, because an integration
00155       // was already performed above
00156       this->last_iter=1;
00157         
00158       this->last_conv=gsl_eround;
00159       std::string estr="Cannot reach tolerance because of roundoff ";
00160       estr+="error on first attempt in gsl_inte_qag::qag().";
00161       O2SCL_CONV_RET(estr.c_str(),gsl_eround,this->err_nonconv);
00162 
00163     } else if ((abserr0 <= tolerance && 
00164                 abserr0 != resasc0) || abserr0 == 0.0) {
00165       *result = result0;
00166       *abserr = abserr0;
00167           
00168       // We start with 1 here, because an integration
00169       // was already performed above
00170       this->last_iter=1;
00171 
00172       return gsl_success;
00173 
00174     } else if (this->w->limit == 1) {
00175 
00176       *result = result0;
00177       *abserr = abserr0;
00178         
00179       // We start with 1 here, because an integration
00180       // was already performed above
00181       this->last_iter=1;
00182 
00183       this->last_conv=gsl_emaxiter;
00184       O2SCL_CONV2_RET("A maximum of 1 iteration was insufficient ",
00185                       "in gsl_inte_qag::qag().",
00186                       gsl_emaxiter,this->err_nonconv);
00187     }
00188       
00189     area = result0;
00190     errsum = abserr0;
00191       
00192     iteration = 1;
00193     do {
00194       double a1, b1, a2, b2;
00195       double a_i, b_i, r_i, e_i;
00196       double area1 = 0, area2 = 0, area12 = 0;
00197       double error1 = 0, error2 = 0, error12 = 0;
00198       double resasc1, resasc2;
00199       double resabs1, resabs2;
00200           
00201       /* Bisect the subinterval with the largest error estimate */
00202           
00203       this->w->retrieve (&a_i, &b_i, &r_i, &e_i);
00204           
00205       a1 = a_i;
00206       b1 = 0.5 * (a_i + b_i);
00207       a2 = b1;
00208       b2 = b_i;
00209       
00210       gauss_kronrod(func,a1,b1,&area1,&error1,&resabs1,&resasc1);
00211       gauss_kronrod(func,a2,b2,&area2,&error2,&resabs2,&resasc2);
00212       
00213       area12 = area1 + area2;
00214       error12 = error1 + error2;
00215           
00216       errsum += (error12 - e_i);
00217       area += area12 - r_i;
00218           
00219       if (resasc1 != error1 && resasc2 != error2) {
00220         double delta = r_i - area12;
00221           
00222         if (fabs (delta) <= 1.0e-5 * fabs (area12) && 
00223             error12 >= 0.99 * e_i) {
00224           roundoff_type1++;
00225         }
00226         if (iteration >= 10 && error12 > e_i) {
00227           roundoff_type2++;
00228         }
00229       }
00230         
00231       tolerance = GSL_MAX_DBL (l_epsabs, l_epsrel * fabs (area));
00232           
00233       if (errsum > tolerance) {
00234         if (roundoff_type1 >= 6 || roundoff_type2 >= 20) {
00235           // round off error
00236           error_type = 2;
00237         }
00238         /* set error flag in the case of bad integrand behaviour at
00239            a point of the integration range */
00240           
00241         if (this->w->subinterval_too_small (a1, a2, b2)) {
00242           error_type = 3;
00243         }
00244       }
00245         
00246       this->w->update (a1, b1, area1, error1, a2, b2, area2, error2);
00247           
00248       this->w->retrieve (&a_i, &b_i, &r_i, &e_i);
00249           
00250       if (this->verbose>0) {
00251         std::cout << "gsl_inte_qag Iter: " << iteration;
00252         std::cout.setf(std::ios::showpos);
00253         std::cout << " Res: " << area;
00254         std::cout.unsetf(std::ios::showpos);
00255         std::cout << " Err: " << errsum
00256                   << " Tol: " << tolerance << std::endl;
00257         if (this->verbose>1) {
00258           char ch;
00259           std::cout << "Press a key and type enter to continue. " ;
00260           std::cin >> ch;
00261         }
00262       }
00263           
00264       iteration++;
00265         
00266     } while (iteration < this->w->limit && !error_type && 
00267              errsum > tolerance);
00268           
00269     *result = this->w->sum_results();
00270     *abserr = errsum;
00271       
00272     this->last_iter=iteration;
00273       
00274     if (errsum <= tolerance) {
00275       return gsl_success;
00276     } else if (error_type == 2) {
00277       this->last_conv=gsl_eround;
00278       std::string estr="Roundoff error prevents tolerance ";
00279       estr+="from being achieved in gsl_inte_qag::qag().";
00280       O2SCL_CONV_RET(estr.c_str(),gsl_eround,this->err_nonconv);
00281     } else if (error_type == 3) {
00282       this->last_conv=gsl_esing;
00283       std::string estr="Bad integrand behavior ";
00284       estr+=" in gsl_inte_qag::qag().";
00285       O2SCL_CONV_RET(estr.c_str(),gsl_esing,this->err_nonconv);
00286     } else if (iteration == this->w->limit) {
00287       this->last_conv=gsl_emaxiter;
00288       std::string estr="Maximum number of subdivisions ("+itos(iteration);
00289       estr+=") reached in gsl_inte_qag::qag().";
00290       O2SCL_CONV_RET(estr.c_str(),gsl_emaxiter,this->err_nonconv);
00291     } else {
00292       std::string estr="Could not integrate function in gsl_inte_qag::";
00293       estr+="qag() (it may have returned a non-finite result).";
00294       O2SCL_ERR_RET(estr.c_str(),gsl_efailed);
00295     }
00296       
00297     // No return statement needed since the above if statement
00298     // always forces a return
00299   }
00300     
00301 #endif
00302 
00303   public:
00304   
00305   /// Return string denoting type ("gsl_inte_qag")
00306   const char *type() { return "gsl_inte_qag"; }
00307   
00308   };
00309 
00310 #ifndef DOXYGENP
00311 }
00312 #endif
00313 
00314 #endif
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Documentation generated with Doxygen. Provided under the GNU Free Documentation License (see License Information).

Get Object-oriented Scientific Computing
Lib at SourceForge.net. Fast, secure and Free Open Source software
downloads.