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