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