![]() |
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 #ifndef O2SCL_GSL_INTE_QAWF_H 00025 #define O2SCL_GSL_INTE_QAWF_H 00026 00027 #include <o2scl/inte.h> 00028 #include <o2scl/gsl_inte_qawo.h> 00029 #include <o2scl/gsl_inte_qagiu.h> 00030 00031 #ifndef DOXYGENP 00032 namespace o2scl { 00033 #endif 00034 00035 /** \brief Adaptive integration for oscillatory integrals (GSL) 00036 00037 The Fourier integral 00038 \f[ 00039 \int_a^{\infty} f(x) \sin(\omega x)~dx 00040 \f] 00041 is computed for some frequency parameter \f$ \omega \f$, 00042 stored in \ref gsl_inte_qawo_sin::omega . 00043 00044 The integral is computed using the same method as \ref 00045 gsl_inte_qawo_sin and \ref gsl_inte_qawo_cos over each of the 00046 subintervals, 00047 \f{eqnarray*}{ 00048 C_1 &=& [a, a+c] \\ 00049 C_2 &=& [a+c, a+2c] \\ 00050 &\vdots & \\ 00051 C_k &=& [a +(k-1)c,\, a+kc], 00052 \f} 00053 where \f$ c = (2\mathrm{floor}(|\omega|)+1)\pi/|\omega|\f$. This 00054 width is chosen to cover an odd number of periods so that the 00055 contributions from the intervals alternate in sign and are 00056 monotonically decreasing when \f$ f \f$ is positive and 00057 monotonically decreasing. The sum of this sequence of 00058 contributions is accelerated using the \f$ \varepsilon \f$ 00059 algorithm. 00060 00061 The algorithm uses zero for the relative tolerance \ref 00062 inte::tol_rel and attempts to compute the integral to an 00063 overall absolute tolerance set by \ref inte::tol_abs. The 00064 following strategy is used: on each interval \f$ C_k\f$, the 00065 algorithm tries to achieve the tolerance 00066 \f[ 00067 \mathrm{TOL}_k = u_k\cdot \epsilon_{\mathrm{abs}} 00068 \f] 00069 where \f$ u_k = (1-p)p^{k-1} \f$ and \f$ p = 0.9\f$. The sum of 00070 the geometric series of contributions from each interval gives 00071 an overall tolerance of \f$ \epsilon_{\mathrm{abs}}\f$. If the 00072 integration of a subinterval leads to difficulties then the accu 00073 racy requirement for subsequent intervals is relaxed, 00074 \f[ 00075 \mathrm{TOL}_k = 00076 u_k\cdot \max\{\epsilon_{\mathrm{abs}}, E_1, \ldots, E_{k-1} \} 00077 \f] 00078 where \f$ E_k\f$ is the estimated error on the interval \f$ C_k\f$. 00079 00080 See \ref gslinte_subsect in the User's guide for general 00081 information about the GSL integration classes. 00082 00083 When verbose output is enabled, this class outputs information 00084 from both the subintegrations performed by \ref 00085 gsl_inte_qawo_sin and the overall integration progress in this 00086 class. 00087 */ 00088 template<class func_t> class gsl_inte_qawf_sin : 00089 public gsl_inte_qawo_sin<func_t> { 00090 00091 public: 00092 00093 gsl_inte_qawf_sin() { 00094 } 00095 00096 virtual ~gsl_inte_qawf_sin() {} 00097 00098 /** \brief Integrate function \c func from \c a to \c b and place 00099 the result in \c res and the error in \c err 00100 */ 00101 virtual int integ_err(func_t &func, double a, double b, 00102 double &res, double &err) { 00103 00104 this->otable=gsl_integration_qawo_table_alloc 00105 (this->omega,1.0,GSL_INTEG_SINE,this->n_levels); 00106 this->cyclew=new gsl_inte_workspace; 00107 this->cyclew->allocate(this->w->limit); 00108 00109 int status=qawf(func,a,this->tol_abs,&res,&err); 00110 00111 gsl_integration_qawo_table_free(this->otable); 00112 this->cyclew->free(); 00113 delete this->cyclew; 00114 00115 return status; 00116 } 00117 00118 #ifndef DOXYGEN_INTERNAL 00119 00120 protected: 00121 00122 /// The integration workspace 00123 gsl_inte_workspace *cyclew; 00124 00125 /** \brief The full GSL integration routine called by integ_err() 00126 */ 00127 int qawf(func_t &func, const double a, 00128 const double epsabs, double *result, double *abserr) { 00129 00130 double area, errsum; 00131 double res_ext, err_ext; 00132 double correc, total_error = 0.0, truncation_error; 00133 00134 size_t ktmin = 0; 00135 size_t iteration = 0; 00136 00137 typename gsl_inte_singular<func_t>::extrap_table table; 00138 00139 double cycle; 00140 //double omega = this->otable->omega; 00141 00142 const double p = 0.9; 00143 double factor = 1; 00144 double initial_eps, eps; 00145 int error_type = 0; 00146 00147 /* Initialize results */ 00148 00149 this->w->initialise(a,a); 00150 00151 *result = 0; 00152 *abserr = 0; 00153 00154 size_t limit=this->w->limit; 00155 /* 00156 if (limit > this->w->limit) { 00157 std::string estr="Iteration limit exceeds workspace "; 00158 estr+="in gsl_inte_qawf::qawf()."; 00159 O2SCL_ERR_RET(estr.c_str(),gsl_einval); 00160 } 00161 */ 00162 00163 /* Test on accuracy */ 00164 00165 if (epsabs <= 0) { 00166 std::string estr="The absolute tolerance must be positive "; 00167 estr+="in gsl_inte_qawf::qawf()."; 00168 O2SCL_ERR_RET(estr.c_str(),gsl_ebadtol); 00169 } 00170 00171 if (this->omega == 0.0) { 00172 if (this->otable->sine == GSL_INTEG_SINE) { 00173 /* The function sin(w x) f(x) is always zero for w = 0 */ 00174 00175 *result = 0; 00176 *abserr = 0; 00177 00178 return GSL_SUCCESS; 00179 } else { 00180 /* The function cos(w x) f(x) is always f(x) for w = 0 */ 00181 00182 gsl_inte_qagiu<func_t> iu; 00183 00184 int status=iu.integ_err(func,a,0.0,*result,*abserr); 00185 00186 return status; 00187 } 00188 } 00189 00190 if (epsabs > GSL_DBL_MIN / (1 - p)) { 00191 eps = epsabs * (1 - p); 00192 } else { 00193 eps = epsabs; 00194 } 00195 00196 initial_eps = eps; 00197 00198 area = 0; 00199 errsum = 0; 00200 00201 res_ext = 0; 00202 err_ext = GSL_DBL_MAX; 00203 correc = 0; 00204 00205 cycle = (2 * floor (fabs (this->omega)) + 1) * 00206 M_PI / fabs (this->omega); 00207 00208 gsl_integration_qawo_table_set_length (this->otable, cycle); 00209 00210 initialise_table (&table); 00211 00212 for (iteration = 0; iteration < limit; iteration++) { 00213 double area1, error1, reseps, erreps; 00214 00215 double a1 = a + iteration * cycle; 00216 double b1 = a1 + cycle; 00217 00218 double epsabs1 = eps * factor; 00219 00220 int status=qawo(func,a1,epsabs1,0.0,cyclew,this->otable, 00221 &area1,&error1); 00222 00223 this->w->append_interval (a1, b1, area1, error1); 00224 00225 factor *= p; 00226 00227 area = area + area1; 00228 errsum = errsum + error1; 00229 00230 /* estimate the truncation error as 50 times the final term */ 00231 00232 truncation_error = 50 * fabs (area1); 00233 00234 total_error = errsum + truncation_error; 00235 00236 if (total_error < epsabs && iteration > 4) { 00237 goto compute_result; 00238 } 00239 00240 if (error1 > correc) { 00241 correc = error1; 00242 } 00243 00244 if (status) { 00245 eps = GSL_MAX_DBL (initial_eps, correc * (1.0 - p)); 00246 } 00247 00248 if (status && total_error < 10 * correc && iteration > 3) { 00249 goto compute_result; 00250 } 00251 00252 append_table (&table, area); 00253 00254 if (table.n < 2) { 00255 continue; 00256 } 00257 00258 qelg (&table, &reseps, &erreps); 00259 00260 ktmin++; 00261 00262 if (ktmin >= 15 && err_ext < 0.001 * total_error) { 00263 error_type = 4; 00264 } 00265 00266 if (erreps < err_ext) { 00267 ktmin = 0; 00268 err_ext = erreps; 00269 res_ext = reseps; 00270 00271 if (err_ext + 10 * correc <= epsabs) 00272 break; 00273 if (err_ext <= epsabs && 10 * correc >= epsabs) 00274 break; 00275 } 00276 00277 if (this->verbose>0) { 00278 std::cout << "gsl_inte_qawf Iter: " << iteration; 00279 std::cout.setf(std::ios::showpos); 00280 std::cout << " Res: " << area; 00281 std::cout.unsetf(std::ios::showpos); 00282 std::cout << " Err: " << total_error 00283 << " Tol: " << epsabs << std::endl; 00284 if (this->verbose>1) { 00285 char ch; 00286 std::cout << "Press a key and type enter to continue. " ; 00287 std::cin >> ch; 00288 } 00289 } 00290 00291 } 00292 00293 if (iteration == limit) error_type = 1; 00294 00295 if (err_ext == GSL_DBL_MAX) 00296 goto compute_result; 00297 00298 err_ext = err_ext + 10 * correc; 00299 00300 *result = res_ext; 00301 *abserr = err_ext; 00302 00303 if (error_type == 0) { 00304 return GSL_SUCCESS ; 00305 } 00306 00307 if (res_ext != 0.0 && area != 0.0) { 00308 if (err_ext / fabs (res_ext) > errsum / fabs (area)) 00309 goto compute_result; 00310 } else if (err_ext > errsum) { 00311 goto compute_result; 00312 } else if (area == 0.0) { 00313 goto return_error; 00314 } 00315 00316 if (error_type == 4) { 00317 err_ext = err_ext + truncation_error; 00318 } 00319 00320 goto return_error; 00321 00322 compute_result: 00323 00324 *result = area; 00325 *abserr = total_error; 00326 00327 return_error: 00328 00329 if (error_type > 2) 00330 error_type--; 00331 00332 if (error_type == 0) { 00333 return GSL_SUCCESS; 00334 } else if (error_type == 1) { 00335 std::string estr="Number of iterations was insufficient "; 00336 estr+=" in gsl_inte_qawf::qawf()."; 00337 O2SCL_ERR_RET(estr.c_str(),gsl_emaxiter); 00338 } else if (error_type == 2) { 00339 std::string estr="Roundoff error prevents tolerance "; 00340 estr+="from being achieved in gsl_inte_qawf::qawf()."; 00341 O2SCL_ERR_RET(estr.c_str(),gsl_eround); 00342 } else if (error_type == 3) { 00343 std::string estr="Bad integrand behavior "; 00344 estr+=" in gsl_inte_qawf::qawf()."; 00345 O2SCL_ERR_RET(estr.c_str(),gsl_esing); 00346 } else if (error_type == 4) { 00347 std::string estr="Roundoff error detected in extrapolation table "; 00348 estr+="in gsl_inte_qawf::qawf()."; 00349 O2SCL_ERR_RET(estr.c_str(),gsl_eround); 00350 } else if (error_type == 5) { 00351 std::string estr="Integral is divergent or slowly convergent "; 00352 estr+="in gsl_inte_qawf::qawf()."; 00353 O2SCL_ERR_RET(estr.c_str(),gsl_ediverge); 00354 } else { 00355 std::string estr="Could not integrate function in gsl_inte_qawf"; 00356 estr+="::qawf() (it may have returned a non-finite result)."; 00357 O2SCL_ERR_RET(estr.c_str(),gsl_efailed); 00358 } 00359 } 00360 00361 /// Add the oscillating part to the integrand 00362 virtual double transform(double t, func_t &func) { 00363 return func(t)*sin(this->omega*t); 00364 } 00365 00366 #endif 00367 00368 /// Return string denoting type ("gsl_inte_qawf_sin") 00369 const char *type() { return "gsl_inte_qawf_sin"; } 00370 00371 }; 00372 00373 /** \brief Adaptive integration a function with finite limits of 00374 integration (GSL) 00375 00376 The Fourier integral 00377 \f[ 00378 \int_a^{\infty} f(x) \cos(\omega x)~dx 00379 \f] 00380 is computed for some frequency parameter \f$ \omega \f$ . 00381 00382 This class is exactly analogous to \ref gsl_inte_qawf_sin . 00383 See that class documentation for more details. 00384 */ 00385 template<class func_t> class gsl_inte_qawf_cos : 00386 public gsl_inte_qawf_sin<func_t> { 00387 00388 public: 00389 00390 gsl_inte_qawf_cos() { 00391 } 00392 00393 virtual ~gsl_inte_qawf_cos() {} 00394 00395 /** \brief Integrate function \c func from \c a to \c b and place 00396 the result in \c res and the error in \c err 00397 */ 00398 virtual int integ_err(func_t &func, double a, double b, 00399 double &res, double &err) { 00400 00401 this->otable=gsl_integration_qawo_table_alloc 00402 (this->omega,b-a,GSL_INTEG_COSINE,this->n_levels); 00403 this->cyclew=new gsl_inte_workspace; 00404 this->cyclew->allocate(this->w->limit); 00405 00406 int status=qawf(func,a,this->tol_abs,&res,&err); 00407 00408 gsl_integration_qawo_table_free(this->otable); 00409 this->cyclew->free(); 00410 delete this->cyclew; 00411 00412 return status; 00413 00414 } 00415 00416 #ifndef DOXYGEN_INTERNAL 00417 00418 protected: 00419 00420 /// Add the oscillating part to the integrand 00421 virtual double transform(double t, func_t &func) { 00422 return func(t)*cos(this->omega*t); 00423 } 00424 00425 #endif 00426 00427 /// Return string denoting type ("gsl_inte_qawf_cos") 00428 const char *type() { return "gsl_inte_qawf_cos"; } 00429 00430 }; 00431 00432 #ifndef DOXYGENP 00433 } 00434 #endif 00435 00436 #endif
Documentation generated with Doxygen. Provided under the GNU Free Documentation License (see License Information).