gsl_inte_qag.h

00001 /*
00002   -------------------------------------------------------------------
00003   
00004   Copyright (C) 2006, 2007, Andrew W. Steiner
00005   
00006   This file is part of O2scl.
00007   
00008   O2scl is free software; you can redistribute it and/or modify
00009   it under the terms of the GNU General Public License as published by
00010   the Free Software Foundation; either version 3 of the License, or
00011   (at your option) any later version.
00012   
00013   O2scl is distributed in the hope that it will be useful,
00014   but WITHOUT ANY WARRANTY; without even the implied warranty of
00015   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016   GNU General Public License for more details.
00017   
00018   You should have received a copy of the GNU General Public License
00019   along with O2scl. If not, see <http://www.gnu.org/licenses/>.
00020 
00021   -------------------------------------------------------------------
00022 */
00023 #ifndef O2SCL_GSL_INTE_QAG_H
00024 #define O2SCL_GSL_INTE_QAG_H
00025 
00026 #include <o2scl/inte.h>
00027 #include <o2scl/gsl_inte_qag_b.h>
00028 
00029 #ifndef DOXYGENP
00030 namespace o2scl {
00031 #endif
00032 
00033   /** \brief Adaptive integration a function with finite limits of 
00034       integration (GSL)
00035 
00036       \todo Verbose output has been setup for this class, but this
00037       needs to be done for the other GSL-like integrators
00038   */
00039   template<class param_t, class func_t> class gsl_inte_qag : 
00040   public gsl_inte_kronrod<param_t,func_t> {
00041     
00042 #ifndef DOXYGEN_INTERNAL
00043 
00044   protected:
00045 
00046     /// Select the number of integration points
00047     int lkey;
00048 
00049 #endif
00050 
00051   public:
00052 
00053     gsl_inte_qag() {
00054       lkey=1;
00055     }
00056 
00057     virtual ~gsl_inte_qag() {}
00058       
00059     /** 
00060         \brief Set the number of integration points
00061  
00062         The possible values for \c key  are:
00063         - 1: GSL_INTEG_GAUSS15 (default)
00064         - 2: GSL_INTEG_GAUSS21
00065         - 3: GSL_INTEG_GAUSS31
00066         - 4: GSL_INTEG_GAUSS41
00067         - 5: GSL_INTEG_GAUSS51
00068         - 6: GSL_INTEG_GAUSS61
00069  
00070         If an integer other than 1-6 is given, the default
00071         (GSL_INTEG_GAUSS15) is assumed, and the error handler is called.
00072     */
00073     int set_key(int key) {
00074       if (key>=1 && key<=6){
00075         lkey=key;
00076         return 0;
00077       }
00078       lkey=1;
00079       set_err_ret("Invalid key in gsl_inte_qag::set_key().",gsl_einval);
00080     }
00081      
00082     /** \brief Return the key used (1-6)
00083      */
00084     int get_key() { return lkey; }
00085   
00086     /** \brief Integrate function \c func from \c a to \c b.
00087      */
00088     virtual double integ(func_t &func, double a, double b, param_t &pa) {
00089       double res, err;
00090       integ_err(func,a,b,pa,res,err);
00091       this->interror=err;
00092       return res;
00093     }
00094     
00095     /** \brief Integrate function \c func from \c a to \c b and place
00096         the result in \c res and the error in \c err
00097     */
00098     virtual int integ_err(func_t &func, double a, double b, 
00099                   param_t &pa, double &res, double &err2) {
00100 
00101       int status;
00102       gsl_integration_rule * integration_rule = gsl_integration_qk15;
00103 
00104       if (lkey < GSL_INTEG_GAUSS15) {
00105         lkey = GSL_INTEG_GAUSS15;
00106       } else if (lkey > GSL_INTEG_GAUSS61) {
00107         lkey = GSL_INTEG_GAUSS61;
00108       }
00109 
00110       switch (lkey) {
00111       case GSL_INTEG_GAUSS15:
00112         {
00113           double fv1[8], fv2[8];
00114           status=qag(func,8,o2scl_inte_qag_coeffs::qk15_xgk,
00115                      o2scl_inte_qag_coeffs::qk15_wg,
00116                      o2scl_inte_qag_coeffs::qk15_wgk,
00117                      fv1,fv2,a,b,this->tolx,this->tolf,this->wkspace,
00118                      &res,&err2,pa);
00119         }
00120         break;
00121       case GSL_INTEG_GAUSS21:
00122         {
00123           double fv1[11], fv2[11];
00124           status=qag(func,11,o2scl_inte_qag_coeffs::qk21_xgk,
00125                      o2scl_inte_qag_coeffs::qk21_wg,
00126                      o2scl_inte_qag_coeffs::qk21_wgk,
00127                      fv1,fv2,a,b,this->tolx,this->tolf,this->wkspace,
00128                      &res,&err2,pa);
00129         }
00130         break;
00131       case GSL_INTEG_GAUSS31:
00132         {
00133           double fv1[16], fv2[16];
00134           status=qag(func,16,o2scl_inte_qag_coeffs::qk31_xgk,
00135                      o2scl_inte_qag_coeffs::qk31_wg,
00136                      o2scl_inte_qag_coeffs::qk31_wgk,
00137                      fv1,fv2,a,b,this->tolx,this->tolf,this->wkspace,
00138                      &res,&err2,pa);
00139         }
00140         break;
00141       case GSL_INTEG_GAUSS41:
00142         {
00143           double fv1[21], fv2[21];
00144           status=qag(func,21,o2scl_inte_qag_coeffs::qk41_xgk,
00145                      o2scl_inte_qag_coeffs::qk41_wg,
00146                      o2scl_inte_qag_coeffs::qk41_wgk,
00147                      fv1,fv2,a,b,this->tolx,this->tolf,this->wkspace,
00148                      &res,&err2,pa);
00149         }
00150         break;
00151       case GSL_INTEG_GAUSS51:
00152         {
00153           double fv1[26], fv2[26];
00154           status=qag(func,26,o2scl_inte_qag_coeffs::qk51_xgk,
00155                      o2scl_inte_qag_coeffs::qk51_wg,
00156                      o2scl_inte_qag_coeffs::qk51_wgk,
00157                      fv1,fv2,a,b,this->tolx,this->tolf,this->wkspace,
00158                      &res,&err2,pa);
00159         }
00160         break;
00161       case GSL_INTEG_GAUSS61:
00162         {
00163           double fv1[31], fv2[31];
00164           status=qag(func,31,o2scl_inte_qag_coeffs::qk61_xgk,
00165                      o2scl_inte_qag_coeffs::qk61_wg,
00166                      o2scl_inte_qag_coeffs::qk61_wgk,
00167                      fv1,fv2,a,b,this->tolx,this->tolf,this->wkspace,
00168                      &res,&err2,pa);
00169         }
00170         break;
00171       default:
00172         GSL_ERROR("value of key does specify a known integration rule",
00173                   GSL_EINVAL);
00174       }
00175 
00176       return status;
00177     
00178     }
00179 
00180 #ifndef DOXYGEN_INTERNAL
00181 
00182   protected:
00183 
00184     /** 
00185         \brief Perform an adaptive integration given the coefficients,
00186         and returning \c result
00187     */
00188     int qag(func_t &func, const int qn, const double xgk[], 
00189             const double wg[], const double wgk[], double fv1[], 
00190             double fv2[], const double a, const double b, 
00191             const double l_epsabs, const double l_epsrel, const size_t limit, 
00192             double *result, double *abserr, param_t &pa)
00193     {
00194       double area, errsum;
00195       double result0, abserr0, resabs0, resasc0;
00196       double tolerance;
00197       size_t iteration = 0;
00198       int roundoff_type1 = 0, roundoff_type2 = 0, error_type = 0;
00199       
00200       double round_off;
00201       
00202       /* Initialize results */
00203       
00204       initialise (this->w, a, b);
00205       
00206       *result = 0;
00207       *abserr = 0;
00208       
00209       if (limit > this->w->limit) {
00210         GSL_ERROR("iteration limit exceeds available workspace", 
00211                   GSL_EINVAL);
00212       }
00213       
00214       if (l_epsabs <= 0 && 
00215           (l_epsrel < 50 * GSL_DBL_EPSILON || l_epsrel < 0.5e-28)) {
00216         GSL_ERROR("tolerance can't be acheived with given tolx & tolf",
00217                   GSL_EBADTOL);
00218       }
00219         
00220       /* perform the first integration */
00221         
00222       gsl_integration_qk_o2scl(func,qn,xgk,wg,wgk,fv1,fv2,a,b,
00223                              &result0,&abserr0,&resabs0,&resasc0,pa);
00224       
00225       set_initial_result(this->w,result0,abserr0);
00226       
00227       /* Test on accuracy */
00228       
00229       tolerance = GSL_MAX_DBL(l_epsabs, l_epsrel * fabs (result0));
00230       
00231       /* need IEEE rounding here to match original quadpack behavior */
00232           
00233       round_off=gsl_coerce_double(50 * GSL_DBL_EPSILON * resabs0);
00234           
00235       if (abserr0 <= round_off && abserr0 > tolerance) {
00236         *result = result0;
00237         *abserr = abserr0;
00238           
00239         GSL_ERROR ("cannot reach tolerance because of roundoff error "
00240                    "on first attempt", GSL_EROUND);
00241       } else if ((abserr0 <= tolerance && 
00242                   abserr0 != resasc0) || abserr0 == 0.0) {
00243         *result = result0;
00244         *abserr = abserr0;
00245           
00246         return gsl_success;
00247       } else if (limit == 1) {
00248         *result = result0;
00249         *abserr = abserr0;
00250         
00251         GSL_ERROR("a maximum of one iteration was insufficient", 
00252                   GSL_EMAXITER);
00253       }
00254       
00255       area = result0;
00256       errsum = abserr0;
00257       
00258       iteration = 1;
00259       do {
00260         double a1, b1, a2, b2;
00261         double a_i, b_i, r_i, e_i;
00262         double area1 = 0, area2 = 0, area12 = 0;
00263         double error1 = 0, error2 = 0, error12 = 0;
00264         double resasc1, resasc2;
00265         double resabs1, resabs2;
00266           
00267         /* Bisect the subinterval with the largest error estimate */
00268           
00269         retrieve (this->w, &a_i, &b_i, &r_i, &e_i);
00270           
00271         a1 = a_i;
00272         b1 = 0.5 * (a_i + b_i);
00273         a2 = b1;
00274         b2 = b_i;
00275           
00276         gsl_integration_qk_o2scl(func,qn,xgk,wg,wgk,fv1,fv2,a1,b1,
00277                                &area1,&error1,&resabs1,&resasc1,pa);
00278         gsl_integration_qk_o2scl(func,qn,xgk,wg,wgk,fv1,fv2,a2,b2,
00279                                &area2,&error2,&resabs2,&resasc2,pa);
00280           
00281         area12 = area1 + area2;
00282         error12 = error1 + error2;
00283           
00284         errsum += (error12 - e_i);
00285         area += area12 - r_i;
00286           
00287         if (resasc1 != error1 && resasc2 != error2)
00288           {
00289             double delta = r_i - area12;
00290               
00291             if (fabs (delta) <= 1.0e-5 * fabs (area12) && 
00292                 error12 >= 0.99 * e_i)
00293               {
00294                 roundoff_type1++;
00295               }
00296             if (iteration >= 10 && error12 > e_i)
00297               {
00298                 roundoff_type2++;
00299               }
00300           }
00301           
00302         tolerance = GSL_MAX_DBL (l_epsabs, l_epsrel * fabs (area));
00303           
00304         if (errsum > tolerance)
00305           {
00306             if (roundoff_type1 >= 6 || roundoff_type2 >= 20)
00307               {
00308                 error_type = 2;   /* round off error */
00309               }
00310             /* set error flag in the case of bad integrand behaviour at
00311                a point of the integration range */
00312               
00313             if (this->subinterval_too_small (a1, a2, b2))
00314               {
00315                 error_type = 3;
00316               }
00317           }
00318           
00319         update (this->w, a1, b1, area1, error1, a2, b2, area2, error2);
00320           
00321         retrieve (this->w, &a_i, &b_i, &r_i, &e_i);
00322           
00323         if (this->verbose>0) {
00324           std::cout << "gsl_inte_qag Iter: " << iteration;
00325           std::cout.setf(std::ios::showpos);
00326           std::cout << " Res: " << area;
00327           std::cout.unsetf(std::ios::showpos);
00328           std::cout << " Err: " << errsum
00329                     << " Tol: " << tolerance << std::endl;
00330           if (this->verbose>1) {
00331             char ch;
00332             std::cout << "Press a key and type enter to continue. " ;
00333             std::cin >> ch;
00334           }
00335         }
00336           
00337         iteration++;
00338         
00339       } while (iteration < limit && !error_type && 
00340                errsum > tolerance);
00341           
00342       *result = sum_results (this->w);
00343       *abserr = errsum;
00344       
00345       if (errsum <= tolerance) {
00346         return gsl_success;
00347       } else if (error_type == 2) {
00348         GSL_ERROR("roundoff error prevents tolerance from being achieved",
00349                   GSL_EROUND);
00350       } else if (error_type == 3) {
00351         GSL_ERROR("bad integrand behavior found in integration interval",
00352                   GSL_ESING);
00353       } else if (iteration == limit) {
00354         GSL_ERROR("maximum number of subdivisions reached",GSL_EMAXITER);
00355       } else {
00356         GSL_ERROR("could not integrate function",GSL_EFAILED);
00357       }
00358     }
00359     
00360 #endif
00361   
00362     /// Return string denoting type ("gsl_inte_qag")
00363     const char *type() { return "gsl_inte_qag"; }
00364   
00365   };
00366 
00367 #ifndef DOXYGENP
00368 }
00369 #endif
00370 
00371 #endif

Documentation generated with Doxygen and provided under the GNU Free Documentation License. See License Information for details.