cern_cauchy.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_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().
00041  
00042       The method from \ref Longman58 is used for the decomposition of
00043       the integral, and the resulting integrals are computed using
00044       cern_gauss.
00045     
00046       The uncertainty in the integral is not calculated, and is always
00047       given as zero. The default base integration object is of type
00048       \ref cern_gauss.  This is the CERNLIB default, but can be
00049       modified by calling set_inte(). If the singularity is outside
00050       the region of integration, then the result from the base
00051       integration object is returned without calling the error
00052       handler.
00053     
00054       Possible errors for integ() and integ_err():
00055       - gsl_einval - Singularity is on an endpoint
00056       - gsl_efailed - Couldn't reach requested accuracy
00057     
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     
00120       if (s==a || s==b) {
00121         set_err("Singularity on boundary in cern_cauchy::integ().",
00122                 gsl_einval);
00123         return 0.0;
00124       } else if ((s<a && s<b) || (s>a && s>b)) {
00125         return it->integ(func,a,b,pa);
00126       }
00127       double h, b0;
00128       if (2.0*s<a+b) {
00129         h=it->integ(func,2.0*s-a,b,pa);
00130         b0=s-a;
00131       } else {
00132         h=it->integ(func,a,2.0*s-b,pa);
00133         b0=b-s;
00134       }
00135       double c=0.005/b0;
00136       double bb=0.0;
00137       bool loop1=true;
00138       while(loop1==true) {
00139         double s8, s16;
00140         double aa=bb;
00141         bb=b0;
00142         bool loop2=true;
00143         while(loop2==true) {
00144           double c1=(bb+aa)/2.0;
00145           double c2=(bb-aa)/2.0;
00146           double c3=s+c1;
00147           double c4=s-c1;
00148           s8=0.0;
00149           s16=0.0;
00150           for(int i=0;i<4;i++) {
00151             double u=c2*x[i];
00152             func(c3+u,y1,pa);
00153             func(c4-u,y2,pa);
00154             func(c3-u,y3,pa);
00155             func(c4+u,y4,pa);
00156             s8+=w[i]*((y1+y2)+(y3+y4));
00157           }
00158           s8*=c2;
00159           for(int i=4;i<12;i++) {
00160             double u=c2*x[i];
00161             func(c3+u,y1,pa);
00162             func(c4-u,y2,pa);
00163             func(c3-u,y3,pa);
00164             func(c4+u,y4,pa);
00165             s16+=w[i]*((y1+y2)+(y3+y4));
00166           }
00167           s16*=c2;
00168 
00169           if (fabs(s16-s8)<=this->tolf*(1.0+fabs(s16))) {
00170             loop2=false;
00171           } else {
00172             bb=c1;
00173             if ((1.0+fabs(c*c2))==1.0) {
00174               loop2=false;
00175             } else {
00176               set_err
00177                 ("Couldn't reach required accuracy in cern_cauchy::integ()",
00178                  gsl_efailed);
00179               return 0.0;
00180             }
00181           }
00182         }
00183         h+=s16;
00184         if (bb==b0) loop1=false;
00185       }
00186       return h;
00187     }
00188 
00189     /// Default integration object
00190     cern_gauss<param_t, func_t> def_inte;
00191 
00192     protected:
00193 
00194 #ifndef DOXYGEN_INTERNAL
00195 
00196     /** \name Integration constants
00197     */
00198     //@{
00199     double x[12], w[12];
00200     //@}
00201 
00202     /// The base integration object
00203     inte<param_t, func_t> *it;
00204 
00205 #endif
00206 
00207   };
00208 
00209 #ifndef DOXYGENP
00210 }
00211 #endif
00212 
00213 #endif

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