![]() |
Object-oriented Scientific Computing Library: Version 0.910
|
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
Documentation generated with Doxygen. Provided under the GNU Free Documentation License (see License Information).