CMS 3D CMS Logo

/afs/cern.ch/work/a/aaltunda/public/www/CMSSW_5_3_14/src/PhysicsTools/Utilities/interface/NumericalIntegration.h

Go to the documentation of this file.
00001 #ifndef PhysicsTools_Utilities_NumericalIntegration_h
00002 #define PhysicsTools_Utilities_NumericalIntegration_h
00003 /* 
00004  * Numerical integration utilities
00005  *
00006  * \author: Luca Lista
00007  * Gauss Legendre and Gauss algorithms based on ROOT implementation
00008  *
00009  */
00010 #include "Math/Functor.h"
00011 #include "Math/Integrator.h"
00012 #include "Math/AllIntegrationTypes.h"
00013 #include <vector>
00014 #include <cmath>
00015 #include <memory>
00016 
00017 namespace funct {
00018 
00019   template<typename F>
00020   double trapezoid_integral(const F& f, double min, double max, unsigned int samples) { 
00021       const double l = max - min, delta = l / samples;
00022       double sum = 0;
00023       for(unsigned int i = 0; i < samples; ++i) {
00024         sum += f(min + (i + 0.5) * delta);
00025       }
00026       return sum * delta;
00027     }
00028   
00029   class TrapezoidIntegrator {
00030   public:
00031     TrapezoidIntegrator() : samples_(0) { }
00032     explicit TrapezoidIntegrator(unsigned int samples) : samples_(samples) { }
00033     template<typename F>
00034     double operator()(const F& f, double min, double max) const { 
00035       return trapezoid_integral(f, min, max, samples_);
00036     }
00037   private:
00038     unsigned int samples_;
00039   };
00040 
00041   class GaussLegendreIntegrator {
00042   public:
00043     GaussLegendreIntegrator() : samples_(0) { }
00044     GaussLegendreIntegrator(unsigned int samples, double epsilon);
00045     template<typename F>
00046     double operator()(const F& f, double min, double max) const {
00047       a0 = 0.5*(max + min);
00048       b0 = 0.5*(max - min);
00049       result = 0.0;
00050       for (i = 0; i < samples_; ++i) {
00051         result += w[i] * f(a0 + b0*x[i]);
00052       }
00053       
00054       return result * b0;      
00055     }
00056   private:
00057     unsigned int samples_;
00058     std::vector<double> x, w;
00059     mutable double a0, b0, result;
00060     mutable unsigned int i;
00061   };
00062 
00063   class GaussIntegrator {
00064   public:
00065     GaussIntegrator() { }
00066     GaussIntegrator(double epsilon) : epsilon_(epsilon) { }
00067     template<typename F>
00068     double operator()(const F& f, double a, double b) const {
00069       h = 0;
00070       if (b == a) return h;
00071       aconst = kCST/std::abs(b - a);
00072       bb = a;
00073     CASE1:
00074       aa = bb;
00075       bb = b;
00076     CASE2:
00077       c1 = kHF*(bb + aa);
00078       c2 = kHF*(bb - aa);
00079       s8 = 0;
00080       for(i = 0; i < 4; ++i) {
00081         u = c2*x[i];
00082         xx = c1 + u;
00083         f1 = f(xx);
00084         xx = c1-u;
00085         f2 = f(xx);
00086         s8 += w[i]*(f1 + f2);
00087       }
00088       s16 = 0;
00089       for(i = 4; i < 12; ++i) {
00090         u = c2*x[i];
00091         xx = c1+u;
00092         f1 = f(xx);
00093         xx = c1-u;
00094         f2 = f(xx);
00095         s16 += w[i]*(f1 + f2);
00096       }
00097       s16 = c2*s16;
00098       if (std::abs(s16 - c2*s8) <= epsilon_*(1. + std::abs(s16))) {
00099         h += s16;
00100         if(bb != b) goto CASE1;
00101       } else {
00102         bb = c1;
00103         if(1. + aconst*std::abs(c2) != 1) goto CASE2;
00104         h = s8;
00105       }
00106       
00107       error_ = std::abs(s16 - c2*s8);
00108       return h;   
00109     }    
00110     double error() const { return error_; }
00111   private:
00112     mutable double error_;
00113     double epsilon_;
00114     static const double x[12], w[12];
00115     static const double kHF;
00116     static const double kCST;
00117     mutable double h, aconst, bb, aa, c1, c2, u, s8, s16, f1, f2, xx;
00118     mutable unsigned int i;
00119   };
00120 
00121   struct RootIntegrator {
00122     RootIntegrator(ROOT::Math::IntegrationOneDim::Type type = ROOT::Math::IntegrationOneDim::kADAPTIVE, 
00123                    double absTol = 1e-9, double relTol = 1e-6, unsigned int size = 1000, unsigned int rule = 3) :
00124       type_(type), absTol_(absTol), relTol_(relTol), size_(size), rule_(rule),
00125       integrator_(new ROOT::Math::Integrator(type, absTol, relTol, size, rule)) { }
00126     RootIntegrator(const RootIntegrator & o) { 
00127       type_ = o.type_; 
00128       absTol_ = o.absTol_; relTol_ = o.relTol_;
00129       size_ = o.size_; rule_ = o.rule_;
00130       integrator_.reset(new ROOT::Math::Integrator(type_, absTol_, relTol_, size_, rule_));
00131     }
00132     RootIntegrator & operator=(const RootIntegrator & o) {
00133       type_ = o.type_; 
00134       absTol_ = o.absTol_; relTol_ = o.relTol_;
00135       size_ = o.size_; rule_ = o.rule_;
00136       integrator_.reset(new ROOT::Math::Integrator(type_, absTol_, relTol_, size_, rule_));
00137       return * this;
00138     }
00139     template<typename F>
00140     double operator()(const F& f, double a, double b) const {
00141       ROOT::Math::Functor1D wrapper(&f, &F::operator());
00142       integrator_->SetFunction(wrapper);
00143       return integrator_->Integral(a, b);
00144     }
00145   private:
00146     ROOT::Math::IntegrationOneDim::Type type_;
00147     double absTol_, relTol_;
00148     unsigned int size_, rule_;
00149     mutable std::auto_ptr<ROOT::Math::Integrator> integrator_;
00150   };    
00151 }
00152 
00153 #endif