GaussLegendreIntegrator.cxx

Go to the documentation of this file.
00001 // @(#)root/mathcore:$Id: GaussLegendreIntegrator.cxx 36764 2010-11-19 10:02:00Z moneta $
00002 // Authors: David Gonzalez Maline    01/2008 
00003 
00004 /**********************************************************************
00005  *                                                                    *
00006  * Copyright (c) 2006 , LCG ROOT MathLib Team                         *
00007  *                                                                    *
00008  *                                                                    *
00009  **********************************************************************/
00010 
00011 #include "Math/GaussLegendreIntegrator.h"
00012 #include <cmath>
00013 #include <string.h>
00014 #include <algorithm>
00015 
00016 namespace ROOT {
00017 namespace Math {
00018 
00019 GaussLegendreIntegrator::GaussLegendreIntegrator(int num, double eps) : 
00020    GaussIntegrator(eps)
00021 {
00022    // Basic contructor
00023    fNum = num;
00024    fX = 0;
00025    fW = 0;
00026 
00027    CalcGaussLegendreSamplingPoints();
00028 }
00029 
00030 GaussLegendreIntegrator::~GaussLegendreIntegrator()
00031 {
00032    // Default Destructor 
00033 
00034 
00035    delete [] fX;
00036    delete [] fW;
00037 }
00038 
00039 void GaussLegendreIntegrator::SetNumberPoints(int num)
00040 {
00041    // Set the number of points used in the calculation of the integral
00042 
00043    fNum = num;
00044    CalcGaussLegendreSamplingPoints();
00045 }
00046 
00047 void GaussLegendreIntegrator::GetWeightVectors(double *x, double *w) const
00048 {
00049    // Returns the arrays x and w.
00050 
00051    std::copy(fX,fX+fNum, x);
00052    std::copy(fW,fW+fNum, w);
00053 }
00054 
00055 
00056 double GaussLegendreIntegrator::DoIntegral(double a, double b, const IGenFunction* function)
00057 {
00058    // Gauss-Legendre integral, see CalcGaussLegendreSamplingPoints.
00059 
00060    if (fNum<=0 || fX == 0 || fW == 0)
00061       return 0;
00062 
00063    fUsedOnce = true;
00064 
00065    const double a0 = (b + a)/2;
00066    const double b0 = (b - a)/2;
00067 
00068    double xx[1];
00069 
00070    double result = 0.0;
00071    for (int i=0; i<fNum; i++)
00072    {
00073       xx[0] = a0 + b0*fX[i];
00074       result += fW[i] * (*function)(xx);
00075    }
00076 
00077    fLastResult = result*b0;
00078    return fLastResult;
00079 }
00080    
00081 
00082 void GaussLegendreIntegrator::SetRelTolerance (double eps)
00083 {
00084    // Set the desired relative Error.
00085    fEpsilon = eps;
00086    CalcGaussLegendreSamplingPoints();
00087 }
00088 
00089 void GaussLegendreIntegrator::SetAbsTolerance (double)
00090 {   MATH_WARN_MSG("ROOT::Math::GaussLegendreIntegrator", "There is no Absolute Tolerance!");  }
00091 
00092 
00093 
00094 void GaussLegendreIntegrator::CalcGaussLegendreSamplingPoints()
00095 {
00096    // Given the number of sampling points this routine fills the
00097    // arrays x and w.
00098 
00099    if (fNum<=0 || fEpsilon<=0)
00100       return;
00101 
00102    if ( fX == 0 )
00103       delete [] fX;
00104 
00105    if ( fW == 0 )
00106       delete [] fW;
00107 
00108    fX = new double[fNum];
00109    fW = new double[fNum];
00110 
00111    // The roots of symmetric is the interval, so we only have to find half of them
00112    const unsigned int m = (fNum+1)/2;
00113 
00114    double z, pp, p1,p2, p3;
00115 
00116    // Loop over the desired roots
00117    for (unsigned int i=0; i<m; i++) {
00118       z = std::cos(3.14159265358979323846*(i+0.75)/(fNum+0.5));
00119 
00120       // Starting with the above approximation to the i-th root, we enter
00121       // the main loop of refinement by Newton's method
00122       do {
00123          p1=1.0;
00124          p2=0.0;
00125 
00126          // Loop up the recurrence relation to get the Legendre
00127          // polynomial evaluated at z
00128          for (int j=0; j<fNum; j++)
00129          {
00130             p3 = p2;
00131             p2 = p1;
00132             p1 = ((2.0*j+1.0)*z*p2-j*p3)/(j+1.0);
00133          }
00134          // p1 is now the desired Legendre polynomial. We next compute pp, its
00135          // derivative, by a standard relation involving also p2, the polynomial
00136          // of one lower order
00137          pp = fNum*(z*p1-p2)/(z*z-1.0);
00138          // Newton's method
00139          z -= p1/pp;
00140 
00141       } while (std::fabs(p1/pp) > fEpsilon);
00142 
00143       // Put root and its symmetric counterpart
00144       fX[i]       = -z;
00145       fX[fNum-i-1] =  z;
00146 
00147       // Compute the weight and put its symmetric counterpart
00148       fW[i]       = 2.0/((1.0-z*z)*pp*pp);
00149       fW[fNum-i-1] = fW[i];
00150    }
00151 }
00152 
00153 ROOT::Math::IntegratorOneDimOptions  GaussLegendreIntegrator::Options() const { 
00154    ROOT::Math::IntegratorOneDimOptions opt; 
00155    opt.SetAbsTolerance(fEpsilon); 
00156    opt.SetRelTolerance(fEpsilon); 
00157    opt.SetWKSize(0); 
00158    opt.SetNPoints(fNum); 
00159    opt.SetIntegrator("GaussLegendre");
00160    return opt; 
00161 }
00162 
00163 void GaussLegendreIntegrator::SetOptions(const ROOT::Math::IntegratorOneDimOptions & opt)
00164 {
00165    //   set integration options
00166 //    std::cout << "fEpsilon = " << fEpsilon << std::endl;
00167 //    std::cout << opt.RelTolerance() << " abs " << opt.AbsTolerance() << std::endl;
00168    //double tol = opt.RelTolerance(); fEpsilon = tol; 
00169    fEpsilon = opt.RelTolerance(); 
00170 //    std::cout << "fEpsilon = " << fEpsilon << std::endl;
00171    fNum = opt.NPoints(); 
00172    if (fNum <= 7)  MATH_WARN_MSGVAL("GaussLegendreIntegrator::SetOptions","setting a low number of points ",fNum);
00173    CalcGaussLegendreSamplingPoints();
00174 }
00175 
00176 } // end namespace Math  
00177 } // end namespace ROOT

Generated on Tue Jul 5 14:34:23 2011 for ROOT_528-00b_version by  doxygen 1.5.1