cern_gauss.h

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

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