Object-oriented Scientific Computing Library: Version 0.910
cern_gauss.h
00001 /*
00002   -------------------------------------------------------------------
00003   
00004   Copyright (C) 2006-2012, 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_CERN_GAUSS_H
00024 #define O2SCL_CERN_GAUSS_H
00025 
00026 #include <o2scl/inte.h>
00027  
00028 #ifndef DOXYGENP
00029 namespace o2scl {
00030 #endif
00031 
00032   /** \brief Gaussian quadrature (CERNLIB)
00033  
00034       For any interval \f$ (a,b) \f$, we define \f$ g_8(a,b) \f$ and
00035       \f$ g_{16}(a,b) \f$ to be the 8- and 16-point Gaussian
00036       quadrature approximations to
00037       \f[
00038       I=\int_a^b f(x)~dx
00039       \f]
00040       and define
00041       \f[
00042       r(a,b)=\frac{|g_{16}(a,b)-g_{8}(a,b)|}{1+g_{16}(a,b)}
00043       \f]
00044       The function integ() returns \f$ G \f$ given by
00045       \f[
00046       G=\sum_{i=1}^{k} g_{16}(x_{i-1},x_i)
00047       \f]
00048       where \f$ x_0=a \f$ and \f$ x_k=b \f$ and the subdivision
00049       points \f$ x_i \f$ are given by
00050       \f[
00051       x_i=x_{i-1}+\lambda(B-x_{i-1})
00052       \f]
00053       where \f$ \lambda \f$ is the first number in the sequence \f$
00054       1,\frac{1}{2},\frac{1}{4},... \f$ for which
00055       \f[
00056       r(x_{i-1},x_i)<\mathrm{eps}.
00057       \f]
00058       If, at any stage, the ratio
00059       \f[
00060       q=\left| \frac{x_i-x_{i-1}}{b-a} \right|
00061       \f]
00062       is so small so that \f$ 1+0.005 q \f$ is indistinguishable from
00063       unity, then the accuracy is required is not reachable and 
00064       the error handler is called.
00065 
00066       Unless there is severe cancellation, inte::tol_rel may be
00067       considered as specifying a bound on the relative error of the
00068       integral in the case that \f$ |I|>1 \f$ and an absolute error if
00069       \f$ |I|<1 \f$. More precisely, if \f$ k \f$ is the number of
00070       subintervals from above, and if
00071       \f[
00072       I_{abs} = \int_a^b |f(x)|~dx
00073       \f]
00074       then
00075       \f[
00076       \frac{|G-I|}{I_{abs}+k}<\mathrm{tol_rel}
00077       \f]
00078       will nearly always be true when no error is returned.  For
00079       functions with no singualarities in the interval, the accuracy
00080       will usually be higher than this.
00081 
00082       If the desired accuracy is not achieved, the integration
00083       functions will call the error handler and return the best guess,
00084       unless \ref inte::err_nonconv is false, in which case the error
00085       handler is not called. 
00086     
00087       This function is based on the CERNLIB routines GAUSS and
00088       DGAUSS which are documented at
00089       http://wwwasdoc.web.cern.ch/wwwasdoc/shortwrupsdir/d103/top.html
00090 
00091       \future Allow user to change \c cst?
00092   */
00093   template<class func_t=funct> class cern_gauss : public inte<func_t> {
00094 
00095     public:
00096   
00097     cern_gauss() {
00098       x[0]=0.96028985649753623;
00099       x[1]=0.79666647741362674;
00100       x[2]=0.52553240991632899;
00101       x[3]=0.18343464249564980;
00102       x[4]=0.98940093499164993;
00103       x[5]=0.94457502307323258;
00104       x[6]=0.86563120238783175;
00105       x[7]=0.75540440835500303;
00106       x[8]=0.61787624440264375;
00107       x[9]=0.45801677765722739;
00108       x[10]=0.28160355077925891;
00109       x[11]=0.95012509837637440e-1;
00110       
00111       w[0]=0.10122853629037626;
00112       w[1]=0.22238103445337447;
00113       w[2]=0.31370664587788729;
00114       w[3]=0.36268378337836198;
00115       w[4]=0.27152459411754095e-1;
00116       w[5]=0.62253523938647893e-1;
00117       w[6]=0.95158511682492785e-1;
00118       w[7]=0.12462897125553387;
00119       w[8]=0.14959598881657673;
00120       w[9]=0.16915651939500254;
00121       w[10]=0.18260341504492359;
00122       w[11]=0.18945061045506850;
00123     }
00124 
00125     /** \brief Integrate function \c func from \c a to \c b
00126         giving result \c res and error \c err
00127     */
00128     virtual int integ_err(func_t &func, double a, double b, 
00129                           double &res, double &err) {
00130       res=integ(func,a,b);
00131       err=0.0;
00132       if (this->err_nonconv) return this->last_conv;
00133       return gsl_success;
00134     }
00135 
00136     /** \brief Integrate function \c func from \c a to \c b.
00137     */
00138     virtual double integ(func_t &func, double a, double b) {
00139 
00140       double y1, y2;
00141 
00142       this->last_conv=0;
00143       size_t itx=0;
00144 
00145       int i;
00146       bool loop=true, loop2=false;
00147       static const double cst=0.005;
00148       double h=0.0;
00149       if (b==a) return 0.0;
00150       double cnst=cst/(b-a);
00151       double aa=0.0, bb=a;
00152       while (loop==true || loop2==true) {
00153         itx++;
00154         if (loop==true) {
00155           aa=bb;
00156           bb=b;
00157         }
00158         double c1=(bb+aa)/2.0;
00159         double c2=(bb-aa)/2.0;
00160         double s8=0.0;
00161         for(i=0;i<4;i++) {
00162           double u=c2*x[i];
00163           y1=func(c1+u);
00164           y2=func(c1-u);
00165           s8+=w[i]*(y1+y2);
00166         }
00167         double s16=0.0;
00168         for(i=4;i<12;i++) {
00169           double u=c2*x[i];
00170           y1=func(c1+u);
00171           y2=func(c1-u);
00172           s16+=w[i]*(y1+y2);
00173         }
00174         s16*=c2;
00175  
00176         loop=false;
00177         loop2=false;
00178         if (fabs(s16-c2*s8)<this->tol_rel*(1.0+fabs(s16))) {
00179           h+=s16;
00180           if (bb!=b) loop=true;
00181         } else {
00182           bb=c1;
00183           if (1.0+cnst*fabs(c2)!=1.0) {
00184             loop2=true;
00185           } else {
00186             this->last_conv=gsl_efailed;
00187             this->last_iter=itx;
00188             O2SCL_CONV2("Failed to reach required accuracy in cern_",
00189                         "gauss::integ().",gsl_efailed,this->err_nonconv);
00190             return h;
00191           }
00192         }
00193       }
00194       this->last_iter=itx;
00195       return h;
00196     }
00197 
00198     protected:
00199 
00200 #ifndef DOXYGEN_INTERNAL
00201 
00202     /** \name Integration constants (Set in the constructor)
00203     */
00204     //@{
00205     double x[12], w[12];
00206     //@}
00207 
00208 #endif
00209 
00210   };
00211 
00212 #ifndef DOXYGENP
00213 }
00214 #endif
00215 
00216 #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.