gsl_inte_qawf.h

00001 /*
00002   -------------------------------------------------------------------
00003   
00004   Copyright (C) 2006, 2007, 2008, 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_QAWF_H
00024 #define O2SCL_GSL_INTE_QAWF_H
00025 
00026 #include <o2scl/inte.h>
00027 #include <o2scl/gsl_inte_qawo.h>
00028 #include <o2scl/gsl_inte_qagiu.h>
00029 
00030 #ifndef DOXYGENP
00031 namespace o2scl {
00032 #endif
00033   
00034   /** 
00035       \brief Adaptive integration for oscillatory integrals (GSL)
00036       
00037       The number of subdivisions of the original interval which 
00038       this class is allowed to make is dictated by the workspace
00039       size for the integration class, which can be set using
00040       \ref gsl_inte_table::set_wkspace() . 
00041       
00042       \todo Improve documentation a little
00043   */
00044   template<class param_t, class func_t> class gsl_inte_qawf_sin : 
00045   public gsl_inte_qawo_sin<param_t,func_t> {
00046     
00047   public:
00048     
00049     gsl_inte_qawf_sin() {
00050     }
00051     
00052     virtual ~gsl_inte_qawf_sin() {}
00053     
00054     /** \brief Integrate function \c func from \c a to \c b.
00055      */
00056     virtual double integ(func_t &func, double a, double b, param_t &pa) {
00057       double res, err;
00058       integ_err(func,a,b,pa,res,err);
00059       this->interror=err;
00060       return res;
00061     }
00062 
00063     /** \brief Integrate function \c func from \c a to \c b and place
00064         the result in \c res and the error in \c err
00065     */
00066     virtual int integ_err(func_t &func, double a, double b, 
00067                           param_t &pa, double &res, double &err2) {
00068       
00069       this->otable=gsl_integration_qawo_table_alloc
00070         (this->omega,1.0,GSL_INTEG_SINE,this->tab_size);
00071       cyclew=gsl_integration_workspace_alloc(this->wkspace);
00072       
00073       int status=qawf(func,a,this->tolx,this->wkspace,&res,&err2,pa);
00074       
00075       gsl_integration_qawo_table_free(this->otable);
00076       gsl_integration_workspace_free(cyclew);
00077       
00078       return status;
00079       
00080     }
00081 
00082 #ifndef DOXYGEN_INTERNAL
00083 
00084   protected:
00085     
00086     /// The integration workspace
00087     gsl_integration_workspace *cyclew;
00088     
00089     /** 
00090         \brief The full GSL integration routine called by integ_err()
00091     */
00092     int qawf(func_t &func, const double a, 
00093              const double epsabs, const size_t limit, 
00094              double *result, double *abserr, param_t &pa) {
00095 
00096       double area, errsum;
00097       double res_ext, err_ext;
00098       double correc, total_error = 0.0, truncation_error;
00099 
00100       size_t ktmin = 0;
00101       size_t iteration = 0;
00102 
00103       struct extrapolation_table table;
00104 
00105       double cycle;
00106       //double omega = this->otable->omega;
00107 
00108       const double p = 0.9;
00109       double factor = 1;
00110       double initial_eps, eps;
00111       int error_type = 0;
00112 
00113       /* Initialize results */
00114 
00115       initialise (this->w, a, a);
00116 
00117       *result = 0;
00118       *abserr = 0;
00119 
00120       if (limit > this->w->limit) {
00121         std::string estr="Iteration limit exceeds workspace ";
00122         estr+="in gsl_inte_qawf::qawf().";
00123         O2SCL_ERR_RET(estr.c_str(),gsl_einval);
00124       }
00125 
00126       /* Test on accuracy */
00127 
00128       if (epsabs <= 0) {
00129         std::string estr="The absolute tolerance must be positive ";
00130         estr+="in gsl_inte_qawf::qawf().";
00131         O2SCL_ERR_RET(estr.c_str(),gsl_ebadtol);
00132       }
00133 
00134       if (this->omega == 0.0) {
00135         if (this->otable->sine == GSL_INTEG_SINE) {
00136           /* The function sin(w x) f(x) is always zero for w = 0 */
00137 
00138           *result = 0;
00139           *abserr = 0;
00140 
00141           return GSL_SUCCESS;
00142         } else {
00143           /* The function cos(w x) f(x) is always f(x) for w = 0 */
00144 
00145           gsl_inte_qagiu<param_t,func_t> iu;
00146               
00147           int status=iu.integ_err(func,a,0.0,pa,*result,*abserr);
00148 
00149           return status;
00150         }
00151       }
00152 
00153       if (epsabs > GSL_DBL_MIN / (1 - p)) {
00154         eps = epsabs * (1 - p);
00155       } else {
00156         eps = epsabs;
00157       }
00158 
00159       initial_eps = eps;
00160 
00161       area = 0;
00162       errsum = 0;
00163 
00164       res_ext = 0;
00165       err_ext = GSL_DBL_MAX;
00166       correc = 0;
00167       
00168       cycle = (2 * floor (fabs (this->omega)) + 1) * M_PI / fabs (this->omega);
00169 
00170       gsl_integration_qawo_table_set_length (this->otable, cycle);
00171 
00172       initialise_table (&table);
00173 
00174       for (iteration = 0; iteration < limit; iteration++) {
00175         double area1, error1, reseps, erreps;
00176 
00177         double a1 = a + iteration * cycle;
00178         double b1 = a1 + cycle;
00179 
00180         double epsabs1 = eps * factor;
00181 
00182         int status=qawo(func,a1,epsabs1,0.0,limit,cyclew,this->otable,
00183                         &area1,&error1,pa);
00184           
00185         this->append_interval (this->w, a1, b1, area1, error1);
00186           
00187         factor *= p;
00188 
00189         area = area + area1;
00190         errsum = errsum + error1;
00191 
00192         /* estimate the truncation error as 50 times the final term */
00193 
00194         truncation_error = 50 * fabs (area1);
00195 
00196         total_error = errsum + truncation_error;
00197 
00198         if (total_error < epsabs && iteration > 4) {
00199           goto compute_result;
00200         }
00201 
00202         if (error1 > correc) {
00203           correc = error1;
00204         }
00205 
00206         if (status) {
00207           eps = GSL_MAX_DBL (initial_eps, correc * (1.0 - p));
00208         }
00209 
00210         if (status && total_error < 10 * correc && iteration > 3) {
00211           goto compute_result;
00212         }
00213 
00214         append_table (&table, area);
00215 
00216         if (table.n < 2) {
00217           continue;
00218         }
00219 
00220         qelg (&table, &reseps, &erreps);
00221 
00222         ktmin++;
00223 
00224         if (ktmin >= 15 && err_ext < 0.001 * total_error) {
00225           error_type = 4;
00226         }
00227 
00228         if (erreps < err_ext) {
00229           ktmin = 0;
00230           err_ext = erreps;
00231           res_ext = reseps;
00232 
00233           if (err_ext + 10 * correc <= epsabs)
00234             break;
00235           if (err_ext <= epsabs && 10 * correc >= epsabs)
00236             break;
00237         }
00238 
00239       }
00240 
00241       if (iteration == limit) error_type = 1;
00242 
00243       if (err_ext == GSL_DBL_MAX)
00244         goto compute_result;
00245 
00246       err_ext = err_ext + 10 * correc;
00247 
00248       *result = res_ext;
00249       *abserr = err_ext;
00250 
00251       if (error_type == 0) {
00252         return GSL_SUCCESS ;
00253       }
00254 
00255       if (res_ext != 0.0 && area != 0.0) {
00256         if (err_ext / fabs (res_ext) > errsum / fabs (area))
00257           goto compute_result;
00258       } else if (err_ext > errsum) {
00259         goto compute_result;
00260       } else if (area == 0.0) {
00261         goto return_error;
00262       }
00263 
00264       if (error_type == 4) {
00265         err_ext = err_ext + truncation_error;
00266       }
00267 
00268       goto return_error;
00269 
00270     compute_result:
00271 
00272       *result = area;
00273       *abserr = total_error;
00274 
00275     return_error:
00276 
00277       if (error_type > 2)
00278         error_type--;
00279 
00280       if (error_type == 0) {
00281         return GSL_SUCCESS;
00282       } else if (error_type == 1) {
00283         std::string estr="Number of iterations was insufficient ";
00284         estr+=" in gsl_inte_qawf::qawf().";
00285         O2SCL_ERR_RET(estr.c_str(),gsl_emaxiter);
00286       } else if (error_type == 2) {
00287         std::string estr="Roundoff error prevents tolerance ";
00288         estr+="from being achieved in gsl_inte_qawf::qawf().";
00289         O2SCL_ERR_RET(estr.c_str(),gsl_eround);
00290       } else if (error_type == 3) {
00291         std::string estr="Bad integrand behavior ";
00292         estr+=" in gsl_inte_qawf::qawf().";
00293         O2SCL_ERR_RET(estr.c_str(),gsl_esing);
00294       } else if (error_type == 4) {
00295         std::string estr="Roundoff error detected in extrapolation table ";
00296         estr+="in gsl_inte_qawf::qawf().";
00297         O2SCL_ERR_RET(estr.c_str(),gsl_eround);
00298       } else if (error_type == 5) {
00299         std::string estr="Integral is divergent or slowly convergent ";
00300         estr+="in gsl_inte_qawf::qawf().";
00301         O2SCL_ERR_RET(estr.c_str(),gsl_ediverge);
00302       } else {
00303         std::string estr="Could not integrate function in gsl_inte_qawf";
00304         estr+="::qawf() (it may have returned a non-finite result).";
00305         O2SCL_ERR_RET(estr.c_str(),gsl_efailed);
00306       }
00307     }
00308     
00309 
00310     /// Add the oscillating part to the integrand
00311     virtual double transform(func_t &func, double x, param_t &pa) {
00312       double wx = this->omega * x;
00313       double sinwx = sin(wx) ;
00314       double y;
00315       func(x,y,pa);
00316       return y*sinwx;
00317     }
00318 
00319 #endif
00320   
00321     /// Return string denoting type ("gsl_inte_qawf_sin")
00322     const char *type() { return "gsl_inte_qawf_sin"; }
00323   
00324   };
00325 
00326   /** \brief Adaptive integration a function with finite limits of 
00327       integration (GSL)
00328 
00329       The number of subdivisions of the original interval which 
00330       this class is allowed to make is dictated by the workspace
00331       size for the integration class, which can be set using
00332       \ref gsl_inte_table::set_wkspace() . 
00333       
00334       \todo Verbose output has been setup for this class, but this
00335       needs to be done for the other GSL-like integrators
00336   */
00337   template<class param_t, class func_t> class gsl_inte_qawf_cos : 
00338   public gsl_inte_qawf_sin<param_t,func_t> {
00339     
00340   public:
00341 
00342     gsl_inte_qawf_cos() {
00343     }
00344 
00345     virtual ~gsl_inte_qawf_cos() {}
00346       
00347     /** \brief Integrate function \c func from \c a to \c b and place
00348         the result in \c res and the error in \c err
00349     */
00350     virtual int integ_err(func_t &func, double a, double b, 
00351                           param_t &pa, double &res, double &err2) {
00352 
00353       this->otable=gsl_integration_qawo_table_alloc
00354         (this->omega,b-a,GSL_INTEG_COSINE,this->tab_size);
00355       this->cyclew=gsl_integration_workspace_alloc(this->wkspace);
00356       
00357       int status=qawf(func,a,this->tolx,this->wkspace,&res,&err2,pa);
00358       
00359       gsl_integration_qawo_table_free(this->otable);
00360       gsl_integration_workspace_free(this->cyclew);
00361       
00362       return status;
00363       
00364     }
00365 
00366 #ifndef DOXYGEN_INTERNAL
00367 
00368   protected:
00369     
00370     /// Add the oscillating part to the integrand
00371     virtual double transform(func_t &func, double x, param_t &pa) {
00372       double wx = this->omega * x;
00373       double coswx = cos(wx) ;
00374       double y;
00375       func(x,y,pa);
00376       return y*coswx;
00377     }
00378 
00379 #endif
00380   
00381     /// Return string denoting type ("gsl_inte_qawf_cos")
00382     const char *type() { return "gsl_inte_qawf_cos"; }
00383   
00384   };
00385 
00386 #ifndef DOXYGENP
00387 }
00388 #endif
00389 
00390 #endif

Documentation generated with Doxygen and provided under the GNU Free Documentation License. See License Information for details.

Project hosting provided by SourceForge.net Logo, O2scl Sourceforge Project Page