cern_cauchy.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_CERN_CAUCHY_H
00024 #define O2SCL_CERN_CAUCHY_H
00025 
00026 #include <o2scl/inte.h>
00027 #include <o2scl/cern_gauss.h>
00028  
00029 #ifndef DOXYGENP
00030 namespace o2scl {
00031 #endif
00032  
00033   /** 
00034       \brief Cauchy principal value integration (CERNLIB)
00035  
00036       The location of the singularity must be specified before-hand in
00037       cern_cauchy::s, and the singularity must not be at one of the
00038       endpoints. Note that when integrating a function of the form
00039       \f$ \frac{f(x)}{(x-s)} \f$, the denominator \f$ (x-s) \f$ must be
00040       specified in the argument \c func to integ(). This is
00041       different from how the \ref gsl_inte_qawc operates.
00042  
00043       The method from \ref Longman58 is used for the decomposition of
00044       the integral, and the resulting integrals are computed using
00045       cern_gauss.
00046     
00047       The uncertainty in the integral is not calculated, and is always
00048       given as zero. The default base integration object is of type
00049       \ref cern_gauss.  This is the CERNLIB default, but can be
00050       modified by calling set_inte(). If the singularity is outside
00051       the region of integration, then the result from the base
00052       integration object is returned without calling the error
00053       handler.
00054     
00055       Possible errors for integ() and integ_err():
00056       - gsl_einval - Singularity is on an endpoint
00057       - gsl_efailed - Couldn't reach requested accuracy
00058   */
00059   template<class param_t, class func_t> class cern_cauchy : 
00060     public inte<param_t,func_t> {
00061 
00062     public:
00063   
00064     cern_cauchy() {
00065       x[0]=0.96028985649753623;
00066       x[1]=0.79666647741362674;
00067       x[2]=0.52553240991632899;
00068       x[3]=0.18343464249564980;
00069       x[4]=0.98940093499164993;
00070       x[5]=0.94457502307323258;
00071       x[6]=0.86563120238783175;
00072       x[7]=0.75540440835500303;
00073       x[8]=0.61787624440264375;
00074       x[9]=0.45801677765722739;
00075       x[10]=0.28160355077925891;
00076       x[11]=0.95012509837637440e-1;
00077       
00078       w[0]=0.10122853629037626;
00079       w[1]=0.22238103445337447;
00080       w[2]=0.31370664587788729;
00081       w[3]=0.36268378337836198;
00082       w[4]=0.27152459411754095e-1;
00083       w[5]=0.62253523938647893e-1;
00084       w[6]=0.95158511682492785e-1;
00085       w[7]=0.12462897125553387;
00086       w[8]=0.14959598881657673;
00087       w[9]=0.16915651939500254;
00088       w[10]=0.18260341504492359;
00089       w[11]=0.18945061045506850;
00090 
00091       it=&def_inte;
00092     }
00093 
00094     /// The singularity (must be set before calling integ() or integ_err())
00095     double s;
00096 
00097     /// Set the base integration object to use
00098     int set_inte(inte<param_t,func_t> &i) {
00099       it=&i;
00100       return 0;
00101     }
00102 
00103     /** \brief Integrate function \c func from \c a to \c b
00104         giving result \c res and error \c err
00105     */
00106     virtual int integ_err(func_t &func, double a, double b, param_t &pa,
00107                   double &res, double &err) {
00108       res=integ(func,a,b,pa);
00109       err=0.0;
00110       return 0;
00111     }
00112 
00113     /** 
00114         
00115     \brief Integrate function \c func from \c a to \c b
00116     */
00117     virtual double integ(func_t &func, double a, double b, param_t &pa) {    
00118       double y1, y2, y3, y4;
00119       size_t itx=0;
00120     
00121       if (s==a || s==b) {
00122         set_err("Singularity on boundary in cern_cauchy::integ().",
00123                 gsl_einval);
00124         return 0.0;
00125       } else if ((s<a && s<b) || (s>a && s>b)) {
00126         return it->integ(func,a,b,pa);
00127       }
00128       double h, b0;
00129       if (2.0*s<a+b) {
00130         h=it->integ(func,2.0*s-a,b,pa);
00131         b0=s-a;
00132       } else {
00133         h=it->integ(func,a,2.0*s-b,pa);
00134         b0=b-s;
00135       }
00136       double c=0.005/b0;
00137       double bb=0.0;
00138       bool loop1=true;
00139       while(loop1==true) {
00140         itx++;
00141         double s8, s16;
00142         double aa=bb;
00143         bb=b0;
00144         bool loop2=true;
00145         while(loop2==true) {
00146           double c1=(bb+aa)/2.0;
00147           double c2=(bb-aa)/2.0;
00148           double c3=s+c1;
00149           double c4=s-c1;
00150           s8=0.0;
00151           s16=0.0;
00152           for(int i=0;i<4;i++) {
00153             double u=c2*x[i];
00154             func(c3+u,y1,pa);
00155             func(c4-u,y2,pa);
00156             func(c3-u,y3,pa);
00157             func(c4+u,y4,pa);
00158             s8+=w[i]*((y1+y2)+(y3+y4));
00159           }
00160           s8*=c2;
00161           for(int i=4;i<12;i++) {
00162             double u=c2*x[i];
00163             func(c3+u,y1,pa);
00164             func(c4-u,y2,pa);
00165             func(c3-u,y3,pa);
00166             func(c4+u,y4,pa);
00167             s16+=w[i]*((y1+y2)+(y3+y4));
00168           }
00169           s16*=c2;
00170 
00171           if (fabs(s16-s8)<=this->tolf*(1.0+fabs(s16))) {
00172             loop2=false;
00173           } else {
00174             bb=c1;
00175             if ((1.0+fabs(c*c2))==1.0) {
00176               loop2=false;
00177             } else {
00178               this->last_iter=itx;
00179               set_err
00180                 ("Couldn't reach required accuracy in cern_cauchy::integ()",
00181                  gsl_efailed);
00182               return 0.0;
00183             }
00184           }
00185         }
00186         h+=s16;
00187         if (bb==b0) loop1=false;
00188       }
00189       this->last_iter=itx;
00190       return h;
00191     }
00192 
00193     /// Default integration object
00194     cern_gauss<param_t, func_t> def_inte;
00195 
00196     protected:
00197 
00198 #ifndef DOXYGEN_INTERNAL
00199 
00200     /** \name Integration constants
00201     */
00202     //@{
00203     double x[12], w[12];
00204     //@}
00205 
00206     /// The base integration object
00207     inte<param_t, func_t> *it;
00208 
00209 #endif
00210 
00211   };
00212 
00213 #ifndef DOXYGENP
00214 }
00215 #endif
00216 
00217 #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