CLHEP VERSION Reference Documentation
   
CLHEP Home Page     CLHEP Documentation     CLHEP Bug Reports

DefiniteIntegral.cc

Go to the documentation of this file.
00001 // -*- C++ -*-
00002 // $Id: DefiniteIntegral.cc,v 1.6 2010/06/16 18:22:01 garren Exp $
00003 
00004 #include <cmath>
00005 #include <vector>
00006 #include <stdexcept>
00007 #include "CLHEP/GenericFunctions/DefiniteIntegral.hh"
00008 #include "CLHEP/GenericFunctions/AbsFunction.hh"
00009 
00010 
00011 namespace Genfun {
00012 
00013 
00014   class DefiniteIntegral::Clockwork {
00015     
00016     //
00017     // This class has limited visibility its functions, data,
00018     // and nested classes are all public:
00019     // 
00020     
00021   public:
00022     
00023     class QuadratureRule {
00024       
00025     public:
00026       
00027       // Constructorctor:
00028       QuadratureRule() {};
00029       
00030       // Destructor:
00031       virtual ~QuadratureRule() {};
00032       
00033       // Integrate at the j^th level of refinement:
00034       virtual double integrate(const AbsFunction & function, 
00035                                double a,
00036                                double b,
00037                                unsigned int j) const=0;
00038       
00039       // Return the step multiplier:
00040       virtual unsigned int stepMultiplier () const=0;
00041 
00042       // Return the number of function calls:
00043       virtual unsigned int numFunctionCalls() const =0;
00044 
00045     };
00046     
00047     class TrapezoidQuadratureRule:public QuadratureRule {
00048       
00049     public:
00050       
00051       // Constructor:
00052       TrapezoidQuadratureRule():retVal(0),nFunctionCalls(0) {};
00053       
00054       // Destructor:
00055       ~TrapezoidQuadratureRule() {};
00056       
00057       // Integrate at the j^th level of refinement:
00058       virtual double integrate(const AbsFunction & function, 
00059                                double a,
00060                                double b,
00061                                unsigned int j) const;
00062       
00063       // The step is doubled at each level of refinement:
00064       virtual unsigned int stepMultiplier () const {return 2;}
00065 
00066       // Returns number of function calls:
00067       virtual unsigned int numFunctionCalls() const {return nFunctionCalls;};
00068       
00069     private:
00070 
00071       mutable double retVal;
00072       mutable unsigned int nFunctionCalls;
00073 
00074     };
00075     
00076     class XtMidpointQuadratureRule:public QuadratureRule {
00077       
00078     public:
00079       
00080       // Constructor:
00081       XtMidpointQuadratureRule():retVal(0),nFunctionCalls(0) {};
00082       
00083       // Destructorctor:
00084       ~XtMidpointQuadratureRule() {};
00085       
00086       // Integrate at the j^th level of refinement:
00087       virtual double integrate(const AbsFunction & function, 
00088                                double a,
00089                                double b,
00090                                unsigned int j) const;
00091       
00092       // The step is tripled at each level of refinement:
00093       virtual unsigned int stepMultiplier () const {return 3;}
00094 
00095       // Returns number of function calls:
00096       virtual unsigned int numFunctionCalls() const {return nFunctionCalls;};
00097       
00098     private:
00099 
00100       mutable double retVal;
00101       mutable unsigned int nFunctionCalls;
00102     };
00103     
00104     double                              a;              // lower limit of integration
00105     double                              b;              // upper limit of integration
00106     DefiniteIntegral::Type              type;           // open or closed
00107     mutable unsigned int                nFunctionCalls; // bookkeeping
00108     unsigned int                        MAXITER;        // Max no of step doubling, tripling, etc.
00109     double                              EPS;            // Target precision
00110     unsigned int                        K;              // Minimum order =2*5=10
00111 
00112     // Polynomial interpolation with Neville's method:
00113     void polint(std::vector<double>::iterator xArray, std::vector<double>::iterator yArray, double x, double & y, double & deltay) const;
00114     
00115   };
00116 
00117   
00118   DefiniteIntegral::DefiniteIntegral(double a, double b, Type type):
00119     c(new Clockwork()) {
00120     c->a              = a;
00121     c->b              = b;
00122     c->type           = type;
00123     c->nFunctionCalls = 0;
00124     c->MAXITER        = type==OPEN ? 20 : 14; 
00125     c->EPS            = 1.0E-6;
00126     c->K              = 5;
00127   }
00128   
00129   DefiniteIntegral::~DefiniteIntegral() {
00130     delete c;
00131   }
00132 
00133   DefiniteIntegral::DefiniteIntegral(const DefiniteIntegral & right) 
00134   :AbsFunctional(right), c(new Clockwork(*right.c)) {
00135   }
00136 
00137   DefiniteIntegral & DefiniteIntegral::operator = (const DefiniteIntegral & right) {
00138     if (this!=&right) {
00139       delete c;
00140       c = new Clockwork(*right.c);
00141     }
00142     return *this;
00143   }
00144   
00145   void DefiniteIntegral::setEpsilon(double eps) {
00146     c->EPS=eps;
00147   }
00148 
00149   void DefiniteIntegral::setMaxIter(unsigned int maxIter) {
00150     c->MAXITER=maxIter;
00151   }
00152 
00153   void DefiniteIntegral::setMinOrder(unsigned int minOrder) {
00154     c->K=(minOrder+1)/2;
00155   }
00156 
00157   double DefiniteIntegral::operator [] (const AbsFunction & function) const {
00158 
00159     const Clockwork::QuadratureRule * rule = c->type==OPEN ? 
00160       (Clockwork::QuadratureRule *) new Clockwork::XtMidpointQuadratureRule() : 
00161       (Clockwork::QuadratureRule *) new Clockwork::TrapezoidQuadratureRule();
00162     double xMult=rule->stepMultiplier();
00163 
00164     c->nFunctionCalls=0;
00165     std::vector<double> s(c->MAXITER+2),h(c->MAXITER+2);
00166     h[1]=1.0;
00167     for (unsigned int j=1;j<=c->MAXITER;j++) {
00168       s[j]=rule->integrate(function, c->a, c->b, j);
00169       c->nFunctionCalls=rule->numFunctionCalls();
00170       if (j>=c->K) {
00171         double ss, dss;
00172         c->polint(h.begin()+j-c->K,s.begin()+j-c->K,0.0,ss, dss);
00173         if (fabs(dss) <= c->EPS*fabs(ss)) {
00174           delete rule;
00175           return ss;
00176         }
00177       }
00178       s[j+1]=s[j];
00179       h[j+1]=h[j]/xMult/xMult;
00180     }
00181     delete rule;
00182     throw std::runtime_error("DefiniteIntegral:  too many steps.  No convergence");
00183     return 0.0;                   // Never get here.
00184   }
00185   
00186   void DefiniteIntegral::Clockwork::polint(std::vector<double>::iterator xArray, std::vector<double>::iterator yArray, double x, double & y, double & deltay) const {
00187     double dif = fabs(x-xArray[1]),dift;
00188     std::vector<double> c(K+1),d(K+1);
00189     unsigned int ns=1;
00190     for (unsigned int i=1;i<=K;i++) {
00191       dift=fabs(x-xArray[i]);
00192       if (dift<dif) {
00193         ns=i;
00194         dif=dift;
00195       }
00196       c[i]=d[i]=yArray[i];
00197     }
00198     y = yArray[ns--];
00199     for (unsigned int m=1;m<K;m++) {
00200       for (unsigned int i=1;i<=K-m;i++) {
00201         double ho = xArray[i]-x;
00202         double hp=  xArray[i+m]-x;
00203         double w=c[i+1]-d[i];
00204         double den=ho-hp;
00205         if (den==0)
00206           std::cerr
00207             << "Error in polynomial extrapolation"
00208             << std::endl;
00209         den=w/den;
00210         d[i]=hp*den;
00211         c[i]=ho*den;
00212       }
00213       deltay = 2*ns < (K-m) ? c[ns+1]: d[ns--];
00214       y += deltay;
00215     }
00216   }
00217   
00218   unsigned int DefiniteIntegral::numFunctionCalls() const {
00219     return c->nFunctionCalls;
00220   }
00221 
00222   // Quadrature rules:
00223   double DefiniteIntegral::Clockwork::TrapezoidQuadratureRule::integrate(const AbsFunction & function, double a, double b, unsigned int n) const {
00224     unsigned int it, j;
00225     if (n==1) {
00226       retVal = 0.5*(b-a)*(function(a)+function(b));
00227       nFunctionCalls+=2;
00228     }
00229     else { 
00230       for (it=1,j=1;j<n-1;j++)  it <<=1;
00231       double tnm=it;
00232       double del = (b-a)/tnm;
00233       double x=a+0.5*del;
00234       double sum;
00235       for (sum=0.0,j=1;j<=it;j++,x+=del) {
00236         sum +=function(x);
00237         nFunctionCalls++;
00238       }
00239       retVal = 0.5*(retVal+(b-a)*sum/tnm);
00240     }
00241     return retVal;
00242   }
00243 
00244   // Quadrature rules:
00245   double DefiniteIntegral::Clockwork::XtMidpointQuadratureRule::integrate(const AbsFunction & function, double a, double b, unsigned int n) const {
00246     unsigned int it, j;
00247     if (n==1) {
00248       retVal = (b-a)*(function((a+b)/2.0));
00249       nFunctionCalls+=1;
00250     }
00251     else { 
00252       for (it=1,j=1;j<n-1;j++)  it *=3;
00253       double tnm=it;
00254       double del  = (b-a)/(3.0*tnm);
00255       double ddel = del+del;
00256       double x=a+0.5*del;
00257       double sum=0;
00258       for (j=1;j<=it;j++) {
00259         sum +=function(x);
00260         x+=ddel;
00261         sum +=function(x);
00262         x+=del;
00263         nFunctionCalls+=2;
00264       }
00265       retVal = (retVal+(b-a)*sum/tnm)/3.0;
00266     }
00267     return retVal;
00268   }
00269   
00270   
00271 
00272 } // namespace Genfun

Generated on 15 Nov 2012 for CLHEP by  doxygen 1.4.7