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 #ifndef O2SCL_GSL_INTE_QNG_H 00024 #define O2SCL_GSL_INTE_QNG_H 00025 00026 #include <o2scl/inte.h> 00027 #include <o2scl/gsl_inte.h> 00028 00029 /** \brief A namespace for the quadrature coefficients for 00030 non-adaptive integration 00031 00032 <b>Documentation from GSL</b>: \n 00033 Gauss-Kronrod-Patterson quadrature coefficients for use in 00034 quadpack routine qng. These coefficients were calculated with 00035 101 decimal digit arithmetic by L. W. Fullerton, Bell Labs, Nov 00036 1981. 00037 00038 */ 00039 namespace o2scl_inte_qng_coeffs { 00040 00041 /** Abscissae common to the 10-, 21-, 43- and 87-point rule */ 00042 static const double x1[5] = { 00043 0.973906528517171720077964012084452, 00044 0.865063366688984510732096688423493, 00045 0.679409568299024406234327365114874, 00046 0.433395394129247190799265943165784, 00047 0.148874338981631210884826001129720 00048 } ; 00049 00050 /** Weights of the 10-point formula */ 00051 static const double w10[5] = { 00052 0.066671344308688137593568809893332, 00053 0.149451349150580593145776339657697, 00054 0.219086362515982043995534934228163, 00055 0.269266719309996355091226921569469, 00056 0.295524224714752870173892994651338 00057 } ; 00058 00059 /** Abscissae common to the 21-, 43- and 87-point rule */ 00060 static const double x2[5] = { 00061 0.995657163025808080735527280689003, 00062 0.930157491355708226001207180059508, 00063 0.780817726586416897063717578345042, 00064 0.562757134668604683339000099272694, 00065 0.294392862701460198131126603103866 00066 } ; 00067 00068 /** Weights of the 21-point formula for abscissae x1 */ 00069 static const double w21a[5] = { 00070 0.032558162307964727478818972459390, 00071 0.075039674810919952767043140916190, 00072 0.109387158802297641899210590325805, 00073 0.134709217311473325928054001771707, 00074 0.147739104901338491374841515972068 00075 } ; 00076 00077 /** Weights of the 21-point formula for abscissae x2 */ 00078 static const double w21b[6] = { 00079 0.011694638867371874278064396062192, 00080 0.054755896574351996031381300244580, 00081 0.093125454583697605535065465083366, 00082 0.123491976262065851077958109831074, 00083 0.142775938577060080797094273138717, 00084 0.149445554002916905664936468389821 00085 } ; 00086 00087 /** Abscissae common to the 43- and 87-point rule */ 00088 static const double x3[11] = { 00089 0.999333360901932081394099323919911, 00090 0.987433402908088869795961478381209, 00091 0.954807934814266299257919200290473, 00092 0.900148695748328293625099494069092, 00093 0.825198314983114150847066732588520, 00094 0.732148388989304982612354848755461, 00095 0.622847970537725238641159120344323, 00096 0.499479574071056499952214885499755, 00097 0.364901661346580768043989548502644, 00098 0.222254919776601296498260928066212, 00099 0.074650617461383322043914435796506 00100 } ; 00101 00102 /** Weights of the 43-point formula for abscissae x1, x3 */ 00103 static const double w43a[10] = { 00104 0.016296734289666564924281974617663, 00105 0.037522876120869501461613795898115, 00106 0.054694902058255442147212685465005, 00107 0.067355414609478086075553166302174, 00108 0.073870199632393953432140695251367, 00109 0.005768556059769796184184327908655, 00110 0.027371890593248842081276069289151, 00111 0.046560826910428830743339154433824, 00112 0.061744995201442564496240336030883, 00113 0.071387267268693397768559114425516 00114 } ; 00115 00116 /** Weights of the 43-point formula for abscissae x3 */ 00117 static const double w43b[12] = { 00118 0.001844477640212414100389106552965, 00119 0.010798689585891651740465406741293, 00120 0.021895363867795428102523123075149, 00121 0.032597463975345689443882222526137, 00122 0.042163137935191811847627924327955, 00123 0.050741939600184577780189020092084, 00124 0.058379395542619248375475369330206, 00125 0.064746404951445885544689259517511, 00126 0.069566197912356484528633315038405, 00127 0.072824441471833208150939535192842, 00128 0.074507751014175118273571813842889, 00129 0.074722147517403005594425168280423 00130 } ; 00131 00132 /** Abscissae of the 87-point rule */ 00133 static const double x4[22] = { 00134 0.999902977262729234490529830591582, 00135 0.997989895986678745427496322365960, 00136 0.992175497860687222808523352251425, 00137 0.981358163572712773571916941623894, 00138 0.965057623858384619128284110607926, 00139 0.943167613133670596816416634507426, 00140 0.915806414685507209591826430720050, 00141 0.883221657771316501372117548744163, 00142 0.845710748462415666605902011504855, 00143 0.803557658035230982788739474980964, 00144 0.757005730685495558328942793432020, 00145 0.706273209787321819824094274740840, 00146 0.651589466501177922534422205016736, 00147 0.593223374057961088875273770349144, 00148 0.531493605970831932285268948562671, 00149 0.466763623042022844871966781659270, 00150 0.399424847859218804732101665817923, 00151 0.329874877106188288265053371824597, 00152 0.258503559202161551802280975429025, 00153 0.185695396568346652015917141167606, 00154 0.111842213179907468172398359241362, 00155 0.037352123394619870814998165437704 00156 } ; 00157 00158 /** Weights of the 87-point formula for abscissae x1, x2, x3 */ 00159 static const double w87a[21] = { 00160 0.008148377384149172900002878448190, 00161 0.018761438201562822243935059003794, 00162 0.027347451050052286161582829741283, 00163 0.033677707311637930046581056957588, 00164 0.036935099820427907614589586742499, 00165 0.002884872430211530501334156248695, 00166 0.013685946022712701888950035273128, 00167 0.023280413502888311123409291030404, 00168 0.030872497611713358675466394126442, 00169 0.035693633639418770719351355457044, 00170 0.000915283345202241360843392549948, 00171 0.005399280219300471367738743391053, 00172 0.010947679601118931134327826856808, 00173 0.016298731696787335262665703223280, 00174 0.021081568889203835112433060188190, 00175 0.025370969769253827243467999831710, 00176 0.029189697756475752501446154084920, 00177 0.032373202467202789685788194889595, 00178 0.034783098950365142750781997949596, 00179 0.036412220731351787562801163687577, 00180 0.037253875503047708539592001191226 00181 } ; 00182 00183 /** Weights of the 87-point formula for abscissae x4 */ 00184 static const double w87b[23] = { 00185 0.000274145563762072350016527092881, 00186 0.001807124155057942948341311753254, 00187 0.004096869282759164864458070683480, 00188 0.006758290051847378699816577897424, 00189 0.009549957672201646536053581325377, 00190 0.012329447652244853694626639963780, 00191 0.015010447346388952376697286041943, 00192 0.017548967986243191099665352925900, 00193 0.019938037786440888202278192730714, 00194 0.022194935961012286796332102959499, 00195 0.024339147126000805470360647041454, 00196 0.026374505414839207241503786552615, 00197 0.028286910788771200659968002987960, 00198 0.030052581128092695322521110347341, 00199 0.031646751371439929404586051078883, 00200 0.033050413419978503290785944862689, 00201 0.034255099704226061787082821046821, 00202 0.035262412660156681033782717998428, 00203 0.036076989622888701185500318003895, 00204 0.036698604498456094498018047441094, 00205 0.037120549269832576114119958413599, 00206 0.037334228751935040321235449094698, 00207 0.037361073762679023410321241766599 00208 } ; 00209 00210 } 00211 00212 #ifndef DOXYGENP 00213 namespace o2scl { 00214 #endif 00215 00216 /** 00217 \brief Non-adaptive integration from a to b (GSL) 00218 00219 The function \ref integ() uses 10-point, 21-point, 43-point, and 00220 87-point Gauss-Kronrod integration successively until the 00221 integral is returned within the accuracy specified by 00222 \ref inte::tolx and \ref inte::tolf . 00223 00224 The error handler is called if the 87-point integration fails 00225 to produce the desired accuracy. If \ref inte::err_nonconv is 00226 false (the default is true), then the error handler is never 00227 called and when the desired accuracy is not obtained the 00228 result of the 87-point integration is returned along with 00229 the associated error. 00230 00231 The return value of the function to be integrated is ignored. 00232 00233 \todo Shouldn't feval be last_iter ? 00234 00235 \future Compare directly with GSL as is done in gsl_inte_qag_ts. 00236 */ 00237 template<class param_t, class func_t> class gsl_inte_qng : 00238 public inte<param_t,func_t>, public gsl_inte { 00239 00240 public: 00241 00242 /** 00243 \brief The number of function evalutions for the last integration 00244 00245 Set to either 0, 21, 43, or 87, depending on the number of 00246 function evaluations that were used. This variable is zero if 00247 an error occurs before any function evaluations were performed 00248 and is never equal 10, since in the 10-point method, the 00249 21-point result is used to estimate the error. If the function 00250 fails to achieve the desired precision, feval is set to 88. 00251 */ 00252 size_t feval; 00253 00254 /** \brief Integrate function \c func from \c a to \c b. 00255 */ 00256 virtual double integ(func_t &func, double a, double b, param_t &pa) { 00257 double res; 00258 integ_err(func,a,b,pa,res,this->interror); 00259 return res; 00260 } 00261 00262 /** \brief Integrate function \c func from \c a to \c b 00263 giving result \c res and error \c err 00264 00265 \future Allow user to change 0.5e28 00266 */ 00267 virtual int integ_err(func_t &func, double a, double b, 00268 param_t &pa, double &res, double &err2) { 00269 00270 this->last_conv=0; 00271 00272 double fv1[5], fv2[5], fv3[5], fv4[5]; 00273 00274 /* array of function values which have been computed */ 00275 double savfun[21]; 00276 00277 /* 10, 21, 43 and 87 point results */ 00278 double res10, res21, res43, res87; 00279 00280 double result_kronrod, err; 00281 00282 /* approximation to the integral of abs(f) */ 00283 double resabs; 00284 00285 /* approximation to the integral of abs(f-i/(b-a)) */ 00286 double resasc; 00287 00288 const double half_length = 0.5 * (b - a); 00289 const double abs_half_length = fabs (half_length); 00290 const double center = 0.5 * (b + a); 00291 00292 double f_center; 00293 func(center,f_center,pa); 00294 00295 int k; 00296 00297 if (this->tolx <= 0 && (this->tolf < 50 * GSL_DBL_EPSILON || 00298 this->tolf < 0.5e-28)) { 00299 res = 0; 00300 err2 = 0; 00301 feval = 0; 00302 00303 std::string estr="Tolerance cannot be achieved with given "; 00304 estr+="value of 'tolx' and 'tolf' in gsl_inte_qng::integ_err()."; 00305 O2SCL_ERR_RET(estr.c_str(),gsl_ebadtol); 00306 }; 00307 00308 /* Compute the integral using the 10- and 21-point formula. */ 00309 00310 res10 = 0; 00311 res21 = o2scl_inte_qng_coeffs::w21b[5] * f_center; 00312 resabs = o2scl_inte_qng_coeffs::w21b[5] * fabs (f_center); 00313 00314 00315 for (k = 0; k < 5; k++) { 00316 const double abscissa = half_length * o2scl_inte_qng_coeffs::x1[k]; 00317 double fval1, fval2; 00318 func(center+abscissa,fval1,pa); 00319 func(center-abscissa,fval2,pa); 00320 const double fval = fval1 + fval2; 00321 res10 += o2scl_inte_qng_coeffs::w10[k] * fval; 00322 res21 += o2scl_inte_qng_coeffs::w21a[k] * fval; 00323 resabs += o2scl_inte_qng_coeffs::w21a[k] * 00324 (fabs (fval1) + fabs (fval2)); 00325 savfun[k] = fval; 00326 fv1[k] = fval1; 00327 fv2[k] = fval2; 00328 } 00329 00330 for (k = 0; k < 5; k++) { 00331 const double abscissa = half_length * o2scl_inte_qng_coeffs::x2[k]; 00332 double fval1, fval2; 00333 func(center+abscissa,fval1,pa); 00334 func(center-abscissa,fval2,pa); 00335 const double fval = fval1 + fval2; 00336 res21 += o2scl_inte_qng_coeffs::w21b[k] * fval; 00337 resabs += o2scl_inte_qng_coeffs::w21b[k] * 00338 (fabs (fval1) + fabs (fval2)); 00339 savfun[k + 5] = fval; 00340 fv3[k] = fval1; 00341 fv4[k] = fval2; 00342 } 00343 00344 resabs *= abs_half_length ; 00345 00346 { 00347 const double mean = 0.5 * res21; 00348 00349 resasc = o2scl_inte_qng_coeffs::w21b[5] * fabs (f_center - mean); 00350 00351 for (k = 0; k < 5; k++) { 00352 resasc += 00353 (o2scl_inte_qng_coeffs::w21a[k] * (fabs (fv1[k] - mean) + 00354 fabs (fv2[k] - mean)) 00355 + o2scl_inte_qng_coeffs::w21b[k] * (fabs (fv3[k] - mean) + 00356 fabs (fv4[k] - mean))); 00357 } 00358 resasc *= abs_half_length ; 00359 } 00360 00361 result_kronrod = res21 * half_length; 00362 00363 err = rescale_error ((res21 - res10) * half_length, resabs, resasc) ; 00364 00365 /* test for convergence. */ 00366 00367 if (err < this->tolx || err < this->tolf * fabs (result_kronrod)) { 00368 res = result_kronrod ; 00369 err2 = err ; 00370 feval = 21; 00371 return gsl_success; 00372 } 00373 00374 /* compute the integral using the 43-point formula. */ 00375 00376 res43 = o2scl_inte_qng_coeffs::w43b[11] * f_center; 00377 00378 for (k = 0; k < 10; k++) { 00379 res43 += savfun[k] * o2scl_inte_qng_coeffs::w43a[k]; 00380 } 00381 00382 for (k = 0; k < 11; k++) { 00383 const double abscissa = half_length * o2scl_inte_qng_coeffs::x3[k]; 00384 double fval1, fval2; 00385 func(center+abscissa,fval1,pa); 00386 func(center-abscissa,fval2,pa); 00387 const double fval = fval1+fval2; 00388 res43 += fval * o2scl_inte_qng_coeffs::w43b[k]; 00389 savfun[k + 10] = fval; 00390 } 00391 00392 /* test for convergence */ 00393 result_kronrod = res43 * half_length; 00394 err = rescale_error ((res43 - res21) * half_length, resabs, resasc); 00395 00396 if (err < this->tolx || err < this->tolf * fabs (result_kronrod)) { 00397 res = result_kronrod ; 00398 err2 = err ; 00399 feval = 43; 00400 return gsl_success; 00401 } 00402 00403 /* compute the integral using the 87-point formula. */ 00404 00405 res87 = o2scl_inte_qng_coeffs::w87b[22] * f_center; 00406 00407 for (k = 0; k < 21; k++) { 00408 res87 += savfun[k] * o2scl_inte_qng_coeffs::w87a[k]; 00409 } 00410 00411 for (k = 0; k < 22; k++) { 00412 const double abscissa = half_length * o2scl_inte_qng_coeffs::x4[k]; 00413 double fval1, fval2; 00414 func(center+abscissa,fval1,pa); 00415 func(center-abscissa,fval2,pa); 00416 res87 += o2scl_inte_qng_coeffs::w87b[k] * (fval1+fval2); 00417 } 00418 00419 /* test for convergence */ 00420 00421 result_kronrod = res87 * half_length ; 00422 00423 err = rescale_error ((res87 - res43) * half_length, resabs, resasc); 00424 00425 if (err < this->tolx || err < this->tolf * fabs (result_kronrod)) { 00426 res = result_kronrod ; 00427 err2 = err ; 00428 feval = 87; 00429 return gsl_success; 00430 } 00431 00432 /* failed to converge */ 00433 res = result_kronrod ; 00434 err2 = err ; 00435 feval = 88; 00436 00437 std::string estr="Failed to reach tolerance "; 00438 estr+="in gsl_inte_qng::integ_err()."; 00439 this->last_conv=gsl_etol; 00440 O2SCL_CONV_RET(estr.c_str(),gsl_etol,this->err_nonconv); 00441 } 00442 00443 /// Return string denoting type ("gsl_inte_qng") 00444 const char *type() { return "gsl_inte_qng"; } 00445 00446 }; 00447 00448 #ifndef DOXYGENP 00449 } 00450 #endif 00451 00452 #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