Object-oriented Scientific Computing Library: Version 0.910
gsl_inte_qawf.h
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
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Documentation generated with Doxygen. Provided under the GNU Free Documentation License (see License Information).

Get Object-oriented Scientific Computing
Lib at SourceForge.net. Fast, secure and Free Open Source software
downloads.