00001 /* 00002 ------------------------------------------------------------------- 00003 00004 Copyright (C) 2006, 2007, 2008, 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 #include <o2scl/funct.h> 00029 00030 #ifndef DOXYGENP 00031 namespace o2scl { 00032 #endif 00033 00034 /** \brief Adaptive integration a function with finite limits of 00035 integration (GSL) 00036 00037 \todo Verbose output has been setup for this class, but this 00038 needs to be done for some of the other GSL-like integrators 00039 00040 \todo Document workspace size here somehow 00041 00042 \todo Document use of last_iter 00043 */ 00044 template<class param_t, class func_t=funct<param_t> > class gsl_inte_qag : 00045 public gsl_inte_kronrod<param_t,func_t> { 00046 00047 #ifndef DOXYGEN_INTERNAL 00048 00049 protected: 00050 00051 /// Select the number of integration points 00052 int lkey; 00053 00054 #endif 00055 00056 public: 00057 00058 /// Create an integrator with the specified key 00059 gsl_inte_qag(int key=1) { 00060 lkey=1; 00061 if (key>=1 && key<=6){ 00062 lkey=key; 00063 } 00064 } 00065 00066 virtual ~gsl_inte_qag() {} 00067 00068 /** 00069 \brief Set the number of integration points 00070 00071 The possible values for \c key are: 00072 - 1: GSL_INTEG_GAUSS15 (default) 00073 - 2: GSL_INTEG_GAUSS21 00074 - 3: GSL_INTEG_GAUSS31 00075 - 4: GSL_INTEG_GAUSS41 00076 - 5: GSL_INTEG_GAUSS51 00077 - 6: GSL_INTEG_GAUSS61 00078 00079 If an integer other than 1-6 is given, the default 00080 (GSL_INTEG_GAUSS15) is assumed, and the error handler is called. 00081 */ 00082 int set_key(int key) { 00083 if (key>=1 && key<=6){ 00084 lkey=key; 00085 return 0; 00086 } 00087 lkey=1; 00088 set_err_ret("Invalid key in gsl_inte_qag::set_key().",gsl_einval); 00089 } 00090 00091 /** \brief Return the key used (1-6) 00092 */ 00093 int get_key() { return lkey; } 00094 00095 /** \brief Integrate function \c func from \c a to \c b. 00096 */ 00097 virtual double integ(func_t &func, double a, double b, param_t &pa) { 00098 double res, err; 00099 integ_err(func,a,b,pa,res,err); 00100 this->interror=err; 00101 return res; 00102 } 00103 00104 /** \brief Integrate function \c func from \c a to \c b and place 00105 the result in \c res and the error in \c err 00106 */ 00107 virtual int integ_err(func_t &func, double a, double b, 00108 param_t &pa, double &res, double &err2) { 00109 00110 int status; 00111 gsl_integration_rule * integration_rule = gsl_integration_qk15; 00112 00113 if (lkey < GSL_INTEG_GAUSS15) { 00114 lkey = GSL_INTEG_GAUSS15; 00115 } else if (lkey > GSL_INTEG_GAUSS61) { 00116 lkey = GSL_INTEG_GAUSS61; 00117 } 00118 00119 switch (lkey) { 00120 case GSL_INTEG_GAUSS15: 00121 { 00122 double fv1[8], fv2[8]; 00123 status=qag(func,8,o2scl_inte_qag_coeffs::qk15_xgk, 00124 o2scl_inte_qag_coeffs::qk15_wg, 00125 o2scl_inte_qag_coeffs::qk15_wgk, 00126 fv1,fv2,a,b,this->tolx,this->tolf,this->wkspace, 00127 &res,&err2,pa); 00128 } 00129 break; 00130 case GSL_INTEG_GAUSS21: 00131 { 00132 double fv1[11], fv2[11]; 00133 status=qag(func,11,o2scl_inte_qag_coeffs::qk21_xgk, 00134 o2scl_inte_qag_coeffs::qk21_wg, 00135 o2scl_inte_qag_coeffs::qk21_wgk, 00136 fv1,fv2,a,b,this->tolx,this->tolf,this->wkspace, 00137 &res,&err2,pa); 00138 } 00139 break; 00140 case GSL_INTEG_GAUSS31: 00141 { 00142 double fv1[16], fv2[16]; 00143 status=qag(func,16,o2scl_inte_qag_coeffs::qk31_xgk, 00144 o2scl_inte_qag_coeffs::qk31_wg, 00145 o2scl_inte_qag_coeffs::qk31_wgk, 00146 fv1,fv2,a,b,this->tolx,this->tolf,this->wkspace, 00147 &res,&err2,pa); 00148 } 00149 break; 00150 case GSL_INTEG_GAUSS41: 00151 { 00152 double fv1[21], fv2[21]; 00153 status=qag(func,21,o2scl_inte_qag_coeffs::qk41_xgk, 00154 o2scl_inte_qag_coeffs::qk41_wg, 00155 o2scl_inte_qag_coeffs::qk41_wgk, 00156 fv1,fv2,a,b,this->tolx,this->tolf,this->wkspace, 00157 &res,&err2,pa); 00158 } 00159 break; 00160 case GSL_INTEG_GAUSS51: 00161 { 00162 double fv1[26], fv2[26]; 00163 status=qag(func,26,o2scl_inte_qag_coeffs::qk51_xgk, 00164 o2scl_inte_qag_coeffs::qk51_wg, 00165 o2scl_inte_qag_coeffs::qk51_wgk, 00166 fv1,fv2,a,b,this->tolx,this->tolf,this->wkspace, 00167 &res,&err2,pa); 00168 } 00169 break; 00170 case GSL_INTEG_GAUSS61: 00171 { 00172 double fv1[31], fv2[31]; 00173 status=qag(func,31,o2scl_inte_qag_coeffs::qk61_xgk, 00174 o2scl_inte_qag_coeffs::qk61_wg, 00175 o2scl_inte_qag_coeffs::qk61_wgk, 00176 fv1,fv2,a,b,this->tolx,this->tolf,this->wkspace, 00177 &res,&err2,pa); 00178 } 00179 break; 00180 default: 00181 std::string estr="Incorrect key in gsl_inte_qag::integ_err()."; 00182 set_err_ret(estr.c_str(),gsl_esanity); 00183 } 00184 00185 return status; 00186 00187 } 00188 00189 #ifndef DOXYGEN_INTERNAL 00190 00191 protected: 00192 00193 /** 00194 \brief Perform an adaptive integration given the coefficients, 00195 and returning \c result 00196 */ 00197 int qag(func_t &func, const int qn, const double xgk[], 00198 const double wg[], const double wgk[], double fv1[], 00199 double fv2[], const double a, const double b, 00200 const double l_epsabs, const double l_epsrel, const size_t limit, 00201 double *result, double *abserr, param_t &pa) 00202 { 00203 double area, errsum; 00204 double result0, abserr0, resabs0, resasc0; 00205 double tolerance; 00206 size_t iteration = 0; 00207 int roundoff_type1 = 0, roundoff_type2 = 0, error_type = 0; 00208 00209 double round_off; 00210 00211 /* Initialize results */ 00212 00213 initialise (this->w, a, b); 00214 00215 *result = 0; 00216 *abserr = 0; 00217 00218 if (limit > this->w->limit) { 00219 00220 this->last_iter=0; 00221 00222 std::string estr="Iteration limit exceeds workspace "; 00223 estr+="in gsl_inte_qag::qag()."; 00224 set_err_ret(estr.c_str(),gsl_einval); 00225 } 00226 00227 if (l_epsabs <= 0 && 00228 (l_epsrel < 50 * GSL_DBL_EPSILON || l_epsrel < 0.5e-28)) { 00229 00230 this->last_iter=0; 00231 00232 std::string estr="Tolerance cannot be achieved with given "; 00233 estr+="value of 'tolx' and 'tolf' in gsl_inte_qag::qag()."; 00234 set_err_ret(estr.c_str(),gsl_ebadtol); 00235 } 00236 00237 /* perform the first integration */ 00238 00239 gsl_integration_qk_o2scl(func,qn,xgk,wg,wgk,fv1,fv2,a,b, 00240 &result0,&abserr0,&resabs0,&resasc0,pa); 00241 00242 set_initial_result(this->w,result0,abserr0); 00243 00244 /* Test on accuracy */ 00245 00246 tolerance = GSL_MAX_DBL(l_epsabs, l_epsrel * fabs (result0)); 00247 00248 /* need IEEE rounding here to match original quadpack behavior */ 00249 00250 round_off=gsl_coerce_double(50 * GSL_DBL_EPSILON * resabs0); 00251 00252 if (abserr0 <= round_off && abserr0 > tolerance) { 00253 00254 *result = result0; 00255 *abserr = abserr0; 00256 00257 // We start with 1 here, because an integration 00258 // was already performed above 00259 this->last_iter=1; 00260 00261 std::string estr="Cannot reach tolerance because of roundoff error "; 00262 estr+="on first attempt in gsl_inte_qag::qag()."; 00263 set_err_ret(estr.c_str(),gsl_eround); 00264 00265 } else if ((abserr0 <= tolerance && 00266 abserr0 != resasc0) || abserr0 == 0.0) { 00267 *result = result0; 00268 *abserr = abserr0; 00269 00270 // We start with 1 here, because an integration 00271 // was already performed above 00272 this->last_iter=1; 00273 00274 return gsl_success; 00275 00276 } else if (limit == 1) { 00277 00278 *result = result0; 00279 *abserr = abserr0; 00280 00281 // We start with 1 here, because an integration 00282 // was already performed above 00283 this->last_iter=1; 00284 00285 std::string estr="A maximum of 1 iteration was insufficient "; 00286 estr+="in gsl_inte_qag::qag()."; 00287 set_err_ret(estr.c_str(),gsl_emaxiter); 00288 } 00289 00290 area = result0; 00291 errsum = abserr0; 00292 00293 iteration = 1; 00294 do { 00295 double a1, b1, a2, b2; 00296 double a_i, b_i, r_i, e_i; 00297 double area1 = 0, area2 = 0, area12 = 0; 00298 double error1 = 0, error2 = 0, error12 = 0; 00299 double resasc1, resasc2; 00300 double resabs1, resabs2; 00301 00302 /* Bisect the subinterval with the largest error estimate */ 00303 00304 retrieve (this->w, &a_i, &b_i, &r_i, &e_i); 00305 00306 a1 = a_i; 00307 b1 = 0.5 * (a_i + b_i); 00308 a2 = b1; 00309 b2 = b_i; 00310 00311 gsl_integration_qk_o2scl(func,qn,xgk,wg,wgk,fv1,fv2,a1,b1, 00312 &area1,&error1,&resabs1,&resasc1,pa); 00313 gsl_integration_qk_o2scl(func,qn,xgk,wg,wgk,fv1,fv2,a2,b2, 00314 &area2,&error2,&resabs2,&resasc2,pa); 00315 00316 area12 = area1 + area2; 00317 error12 = error1 + error2; 00318 00319 errsum += (error12 - e_i); 00320 area += area12 - r_i; 00321 00322 if (resasc1 != error1 && resasc2 != error2) { 00323 double delta = r_i - area12; 00324 00325 if (fabs (delta) <= 1.0e-5 * fabs (area12) && 00326 error12 >= 0.99 * e_i) { 00327 roundoff_type1++; 00328 } 00329 if (iteration >= 10 && error12 > e_i) { 00330 roundoff_type2++; 00331 } 00332 } 00333 00334 tolerance = GSL_MAX_DBL (l_epsabs, l_epsrel * fabs (area)); 00335 00336 if (errsum > tolerance) { 00337 if (roundoff_type1 >= 6 || roundoff_type2 >= 20) { 00338 error_type = 2; /* round off error */ 00339 } 00340 /* set error flag in the case of bad integrand behaviour at 00341 a point of the integration range */ 00342 00343 if (this->subinterval_too_small (a1, a2, b2)) { 00344 error_type = 3; 00345 } 00346 } 00347 00348 update (this->w, a1, b1, area1, error1, a2, b2, area2, error2); 00349 00350 retrieve (this->w, &a_i, &b_i, &r_i, &e_i); 00351 00352 if (this->verbose>0) { 00353 std::cout << "gsl_inte_qag Iter: " << iteration; 00354 std::cout.setf(std::ios::showpos); 00355 std::cout << " Res: " << area; 00356 std::cout.unsetf(std::ios::showpos); 00357 std::cout << " Err: " << errsum 00358 << " Tol: " << tolerance << std::endl; 00359 if (this->verbose>1) { 00360 char ch; 00361 std::cout << "Press a key and type enter to continue. " ; 00362 std::cin >> ch; 00363 } 00364 } 00365 00366 iteration++; 00367 00368 } while (iteration < limit && !error_type && 00369 errsum > tolerance); 00370 00371 *result = sum_results (this->w); 00372 *abserr = errsum; 00373 00374 this->last_iter=iteration; 00375 00376 if (errsum <= tolerance) { 00377 return gsl_success; 00378 } else if (error_type == 2) { 00379 std::string estr="Roundoff error prevents tolerance "; 00380 estr+="from being achieved in gsl_inte_qag::qag()."; 00381 set_err_ret(estr.c_str(),gsl_eround); 00382 } else if (error_type == 3) { 00383 std::string estr="Bad integrand behavior "; 00384 estr+=" in gsl_inte_qag::qag()."; 00385 set_err_ret(estr.c_str(),gsl_esing); 00386 } else if (iteration == limit) { 00387 std::string estr="Maximum number of subdivisions ("+itos(iteration); 00388 estr+=") reached in gsl_inte_qag::qag()."; 00389 set_err_ret(estr.c_str(),gsl_emaxiter); 00390 } else { 00391 std::string estr="Could not integrate function in gsl_inte_qag::"; 00392 estr+="qag() (it may have returned a non-finite result)."; 00393 set_err_ret(estr.c_str(),gsl_efailed); 00394 } 00395 00396 // No return statement needed since the above if statement 00397 // always forces a return 00398 } 00399 00400 #endif 00401 00402 public: 00403 00404 /// Return string denoting type ("gsl_inte_qag") 00405 const char *type() { return "gsl_inte_qag"; } 00406 00407 }; 00408 00409 #ifndef DOXYGENP 00410 } 00411 #endif 00412 00413 #endif
Documentation generated with Doxygen and provided under the GNU Free Documentation License. See License Information for details.
Project hosting provided by
,
O2scl Sourceforge Project Page