RooIntegrator1D.cxx

Go to the documentation of this file.
00001 /*****************************************************************************
00002  * Project: RooFit                                                           *
00003  * Package: RooFitCore                                                       *
00004  * @(#)root/roofitcore:$Id: RooIntegrator1D.cxx 36210 2010-10-08 21:59:38Z wouter $
00005  * Authors:                                                                  *
00006  *   WV, Wouter Verkerke, UC Santa Barbara, verkerke@slac.stanford.edu       *
00007  *   DK, David Kirkby,    UC Irvine,         dkirkby@uci.edu                 *
00008  *                                                                           *
00009  * Copyright (c) 2000-2005, Regents of the University of California          *
00010  *                          and Stanford University. All rights reserved.    *
00011  *                                                                           *
00012  * Redistribution and use in source and binary forms,                        *
00013  * with or without modification, are permitted according to the terms        *
00014  * listed in LICENSE (http://roofit.sourceforge.net/license.txt)             *
00015  *****************************************************************************/
00016 
00017 //////////////////////////////////////////////////////////////////////////////
00018 //
00019 // BEGIN_HTML
00020 // RooIntegrator1D implements an adaptive one-dimensional 
00021 // numerical integration algorithm. 
00022 // END_HTML
00023 //
00024 
00025 
00026 #include "RooFit.h"
00027 #include "Riostream.h"
00028 
00029 #include "TClass.h"
00030 #include "RooIntegrator1D.h"
00031 #include "RooArgSet.h"
00032 #include "RooRealVar.h"
00033 #include "RooNumber.h"
00034 #include "RooIntegratorBinding.h"
00035 #include "RooNumIntConfig.h"
00036 #include "RooNumIntFactory.h"
00037 #include "RooMsgService.h"
00038 
00039 #include <assert.h>
00040 
00041 
00042 
00043 ClassImp(RooIntegrator1D)
00044 ;
00045 
00046 // Register this class with RooNumIntConfig
00047 
00048 //_____________________________________________________________________________
00049 void RooIntegrator1D::registerIntegrator(RooNumIntFactory& fact)
00050 {
00051   // Register RooIntegrator1D, is parameters and capabilities with RooNumIntFactory
00052 
00053   RooCategory sumRule("sumRule","Summation Rule") ;
00054   sumRule.defineType("Trapezoid",RooIntegrator1D::Trapezoid) ;
00055   sumRule.defineType("Midpoint",RooIntegrator1D::Midpoint) ;
00056   sumRule.setLabel("Trapezoid") ;
00057   RooCategory extrap("extrapolation","Extrapolation procedure") ;
00058   extrap.defineType("None",0) ;
00059   extrap.defineType("Wynn-Epsilon",1) ;
00060   extrap.setLabel("Wynn-Epsilon") ;
00061   RooRealVar maxSteps("maxSteps","Maximum number of steps",20) ;
00062   RooRealVar minSteps("minSteps","Minimum number of steps",999) ;
00063   RooRealVar fixSteps("fixSteps","Fixed number of steps",0) ;
00064 
00065   RooIntegrator1D* proto = new RooIntegrator1D() ;
00066   fact.storeProtoIntegrator(proto,RooArgSet(sumRule,extrap,maxSteps,minSteps,fixSteps)) ;
00067   RooNumIntConfig::defaultConfig().method1D().setLabel(proto->IsA()->GetName()) ;
00068 }
00069 
00070 
00071 
00072 //_____________________________________________________________________________
00073 RooIntegrator1D::RooIntegrator1D() :
00074   _h(0), _s(0), _c(0), _d(0), _x(0)
00075 {
00076   // Default constructor
00077 }
00078 
00079 
00080 //_____________________________________________________________________________
00081 RooIntegrator1D::RooIntegrator1D(const RooAbsFunc& function, SummationRule rule,
00082                                  Int_t maxSteps, Double_t eps) : 
00083   RooAbsIntegrator(function), _rule(rule), _maxSteps(maxSteps),  _minStepsZero(999), _fixSteps(0), _epsAbs(eps), _epsRel(eps), _doExtrap(kTRUE)
00084 {
00085   // Construct integrator on given function binding, using specified summation
00086   // rule, maximum number of steps and conversion tolerance. The integration
00087   // limits are taken from the function binding
00088 
00089   _useIntegrandLimits= kTRUE;
00090   _valid= initialize();
00091 } 
00092 
00093 
00094 //_____________________________________________________________________________
00095 RooIntegrator1D::RooIntegrator1D(const RooAbsFunc& function, Double_t xmin, Double_t xmax,
00096                                  SummationRule rule, Int_t maxSteps, Double_t eps) : 
00097   RooAbsIntegrator(function), 
00098   _rule(rule), 
00099   _maxSteps(maxSteps), 
00100   _minStepsZero(999), 
00101   _fixSteps(0),
00102   _epsAbs(eps), 
00103   _epsRel(eps),
00104   _doExtrap(kTRUE)
00105 {
00106   // Construct integrator on given function binding for given range,
00107   // using specified summation rule, maximum number of steps and
00108   // conversion tolerance. The integration limits are taken from the
00109   // function binding
00110 
00111   _useIntegrandLimits= kFALSE;
00112   _xmin= xmin;
00113   _xmax= xmax;
00114   _valid= initialize();
00115 } 
00116 
00117 
00118 //_____________________________________________________________________________
00119 RooIntegrator1D::RooIntegrator1D(const RooAbsFunc& function, const RooNumIntConfig& config) :
00120   RooAbsIntegrator(function,config.printEvalCounter()), 
00121   _epsAbs(config.epsAbs()),
00122   _epsRel(config.epsRel())
00123 {
00124   // Construct integrator on given function binding, using specified
00125   // configuration object. The integration limits are taken from the
00126   // function binding
00127 
00128   // Extract parameters from config object
00129   const RooArgSet& configSet = config.getConfigSection(IsA()->GetName()) ;  
00130   _rule = (SummationRule) configSet.getCatIndex("sumRule",Trapezoid) ;
00131   _maxSteps = (Int_t) configSet.getRealValue("maxSteps",20) ;
00132   _minStepsZero = (Int_t) configSet.getRealValue("minSteps",999) ;
00133   _fixSteps = (Int_t) configSet.getRealValue("fixSteps",0) ;
00134   _doExtrap = (Bool_t) configSet.getCatIndex("extrapolation",1) ;
00135 
00136   if (_fixSteps>_maxSteps) {
00137     oocoutE((TObject*)0,Integration) << "RooIntegrator1D::ctor() ERROR: fixSteps>maxSteps, fixSteps set to maxSteps" << endl ;
00138     _fixSteps = _maxSteps ;
00139   }
00140 
00141   _useIntegrandLimits= kTRUE;
00142   _valid= initialize();
00143 } 
00144 
00145 
00146 
00147 //_____________________________________________________________________________
00148 RooIntegrator1D::RooIntegrator1D(const RooAbsFunc& function, Double_t xmin, Double_t xmax,
00149                                 const RooNumIntConfig& config) :
00150   RooAbsIntegrator(function,config.printEvalCounter()), 
00151   _epsAbs(config.epsAbs()),
00152   _epsRel(config.epsRel())
00153 {
00154   // Construct integrator on given function binding, using specified
00155   // configuration object and integration range
00156 
00157   // Extract parameters from config object
00158   const RooArgSet& configSet = config.getConfigSection(IsA()->GetName()) ;  
00159   _rule = (SummationRule) configSet.getCatIndex("sumRule",Trapezoid) ;
00160   _maxSteps = (Int_t) configSet.getRealValue("maxSteps",20) ;
00161   _minStepsZero = (Int_t) configSet.getRealValue("minSteps",999) ;
00162   _fixSteps = (Int_t) configSet.getRealValue("fixSteps",0) ;  
00163   _doExtrap = (Bool_t) configSet.getCatIndex("extrapolation",1) ;
00164 
00165   _useIntegrandLimits= kFALSE;
00166   _xmin= xmin;
00167   _xmax= xmax;
00168   _valid= initialize();
00169 } 
00170 
00171 
00172 
00173 //_____________________________________________________________________________
00174 RooAbsIntegrator* RooIntegrator1D::clone(const RooAbsFunc& function, const RooNumIntConfig& config) const
00175 {
00176   // Clone integrator with new function binding and configuration. Needed by RooNumIntFactory
00177   return new RooIntegrator1D(function,config) ;
00178 }
00179 
00180 
00181 
00182 //_____________________________________________________________________________
00183 Bool_t RooIntegrator1D::initialize()
00184 {
00185   // Initialize the integrator
00186 
00187   // apply defaults if necessary
00188   if(_maxSteps <= 0) {
00189     _maxSteps= (_rule == Trapezoid) ? 20 : 14;
00190   }
00191 
00192   if(_epsRel <= 0) _epsRel= 1e-6;
00193   if(_epsAbs <= 0) _epsAbs= 1e-6;
00194 
00195   // check that the integrand is a valid function
00196   if(!isValid()) {
00197     oocoutE((TObject*)0,Integration) << "RooIntegrator1D::initialize: cannot integrate invalid function" << endl;
00198     return kFALSE;
00199   }
00200 
00201   // Allocate coordinate buffer size after number of function dimensions
00202   _x = new Double_t[_function->getDimension()] ;
00203 
00204 
00205   // Allocate workspace for numerical integration engine
00206   _h= new Double_t[_maxSteps + 2];
00207   _s= new Double_t[_maxSteps + 2];
00208   _c= new Double_t[_nPoints + 1];
00209   _d= new Double_t[_nPoints + 1];
00210 
00211   return checkLimits();
00212 }
00213 
00214 
00215 //_____________________________________________________________________________
00216 RooIntegrator1D::~RooIntegrator1D()
00217 {
00218   // Destructor
00219 
00220   // Release integrator workspace
00221   if(_h) delete[] _h;
00222   if(_s) delete[] _s;
00223   if(_c) delete[] _c;
00224   if(_d) delete[] _d;
00225   if(_x) delete[] _x;
00226 }
00227 
00228 
00229 //_____________________________________________________________________________
00230 Bool_t RooIntegrator1D::setLimits(Double_t *xmin, Double_t *xmax) 
00231 {
00232   // Change our integration limits. Return kTRUE if the new limits are
00233   // ok, or otherwise kFALSE. Always returns kFALSE and does nothing
00234   // if this object was constructed to always use our integrand's limits.
00235 
00236   if(_useIntegrandLimits) {
00237     oocoutE((TObject*)0,Integration) << "RooIntegrator1D::setLimits: cannot override integrand's limits" << endl;
00238     return kFALSE;
00239   }
00240   _xmin= *xmin;
00241   _xmax= *xmax;
00242   return checkLimits();
00243 }
00244 
00245 
00246 //_____________________________________________________________________________
00247 Bool_t RooIntegrator1D::checkLimits() const 
00248 {
00249   // Check that our integration range is finite and otherwise return kFALSE.
00250   // Update the limits from the integrand if requested.
00251 
00252   if(_useIntegrandLimits) {
00253     assert(0 != integrand() && integrand()->isValid());
00254     _xmin= integrand()->getMinLimit(0);
00255     _xmax= integrand()->getMaxLimit(0);
00256   }
00257   _range= _xmax - _xmin;
00258   if(_range < 0) {
00259     oocoutE((TObject*)0,Integration) << "RooIntegrator1D::checkLimits: bad range with min >= max (_xmin = " << _xmin << " _xmax = " << _xmax << ")" << endl;
00260     return kFALSE;
00261   }
00262   return (RooNumber::isInfinite(_xmin) || RooNumber::isInfinite(_xmax)) ? kFALSE : kTRUE;
00263 }
00264 
00265 
00266 //_____________________________________________________________________________
00267 Double_t RooIntegrator1D::integral(const Double_t *yvec) 
00268 {
00269   // Calculate numeric integral at given set of function binding parameters
00270   
00271   assert(isValid());
00272 
00273   // Copy yvec to xvec if provided
00274   if (yvec) {
00275     UInt_t i ; for (i=0 ; i<_function->getDimension()-1 ; i++) {
00276       _x[i+1] = yvec[i] ;
00277     }
00278   }
00279 
00280   Int_t j;
00281   _h[1]=1.0;
00282   Double_t zeroThresh = _epsAbs/_range ;
00283   for(j= 1; j<=_maxSteps; j++) {
00284     // refine our estimate using the appropriate summation rule
00285     _s[j]= (_rule == Trapezoid) ? addTrapezoids(j) : addMidpoints(j);
00286 
00287     if (j >= _minStepsZero) {
00288       Bool_t allZero(kTRUE) ;
00289       Int_t jj ; for (jj=0 ; jj<=j ; jj++) {    
00290         if (_s[j]>=zeroThresh) {
00291           allZero=kFALSE ;
00292         }
00293       }
00294       if (allZero) {
00295         //cout << "Roo1DIntegrator(" << this << "): zero convergence at step " << j << ", value = " << 0 << endl ;
00296         return 0;
00297       }
00298     }
00299     
00300     if (_fixSteps>0) {
00301       
00302       // Fixed step mode, return result after fixed number of steps
00303       if (j==_fixSteps) {
00304         //cout << "returning result at fixed step " << j << endl ;
00305         return _s[j];
00306       }
00307 
00308     } else  if(j >= _nPoints) {
00309 
00310       // extrapolate the results of recent refinements and check for a stable result
00311       if (_doExtrap) {
00312         extrapolate(j);
00313       } else {
00314         _extrapValue = _s[j] ;
00315         _extrapError = _s[j]-_s[j-1] ;
00316       }
00317 
00318       if(fabs(_extrapError) <= _epsRel*fabs(_extrapValue)) {
00319         return _extrapValue;
00320       }
00321       if(fabs(_extrapError) <= _epsAbs) {
00322         return _extrapValue ;
00323       }
00324 
00325     }
00326     // update the step size for the next refinement of the summation
00327     _h[j+1]= (_rule == Trapezoid) ? _h[j]/4. : _h[j]/9.;
00328   }
00329 
00330   oocoutW((TObject*)0,Integration) << "RooIntegrator1D::integral: integral of " << _function->getName() << " over range (" << _xmin << "," << _xmax << ") did not converge after " 
00331                                    << _maxSteps << " steps" << endl;
00332   for(j= 1; j <= _maxSteps; j++) {
00333     ooccoutW((TObject*)0,Integration) << "   [" << j << "] h = " << _h[j] << " , s = " << _s[j] << endl;
00334   }
00335   return _s[_maxSteps] ;
00336 }
00337 
00338 
00339 //_____________________________________________________________________________
00340 Double_t RooIntegrator1D::addMidpoints(Int_t n)
00341 {
00342   // Calculate the n-th stage of refinement of the Second Euler-Maclaurin
00343   // summation rule which has the useful property of not evaluating the
00344   // integrand at either of its endpoints but requires more function
00345   // evaluations than the trapezoidal rule. This rule can be used with
00346   // a suitable change of variables to estimate improper integrals.
00347 
00348   Double_t x,tnm,sum,del,ddel;
00349   Int_t it,j;
00350 
00351   if(n == 1) {
00352     Double_t xmid= 0.5*(_xmin + _xmax);
00353     return (_savedResult= _range*integrand(xvec(xmid)));
00354   }
00355   else {
00356     for(it=1, j=1; j < n-1; j++) it*= 3;
00357     tnm= it;
00358     del= _range/(3.*tnm);
00359     ddel= del+del;
00360     x= _xmin + 0.5*del;
00361     for(sum= 0, j= 1; j <= it; j++) {
00362       sum+= integrand(xvec(x));
00363       x+= ddel;
00364       sum+= integrand(xvec(x));
00365       x+= del;
00366     }      
00367     return (_savedResult= (_savedResult + _range*sum/tnm)/3.);
00368   }
00369 }
00370 
00371 
00372 //_____________________________________________________________________________
00373 Double_t RooIntegrator1D::addTrapezoids(Int_t n)
00374 {
00375   // Calculate the n-th stage of refinement of the extended trapezoidal
00376   // summation rule. This is the most efficient rule for a well behaved
00377   // integrand that can be evaluated over its entire range, including the
00378   // endpoints.
00379 
00380   Double_t x,tnm,sum,del;
00381   Int_t it,j;
00382 
00383   if (n == 1) {
00384     // use a single trapezoid to cover the full range
00385     return (_savedResult= 0.5*_range*(integrand(xvec(_xmin)) + integrand(xvec(_xmax))));
00386   }
00387   else {
00388     // break the range down into several trapezoids using 2**(n-2)
00389     // equally-spaced interior points
00390     for(it=1, j=1; j < n-1; j++) it <<= 1;
00391     tnm= it;
00392     del= _range/tnm;
00393     x= _xmin + 0.5*del;
00394     for(sum=0.0, j=1; j<=it; j++, x+=del) sum += integrand(xvec(x));
00395     return (_savedResult= 0.5*(_savedResult + _range*sum/tnm));
00396   }
00397 }
00398 
00399 
00400 
00401 //_____________________________________________________________________________
00402 void RooIntegrator1D::extrapolate(Int_t n)
00403 {
00404   // Extrapolate result to final value
00405 
00406   Double_t *xa= &_h[n-_nPoints];
00407   Double_t *ya= &_s[n-_nPoints];
00408   Int_t i,m,ns=1;
00409   Double_t den,dif,dift,ho,hp,w;
00410 
00411   dif=fabs(xa[1]);
00412   for (i= 1; i <= _nPoints; i++) {
00413     if ((dift=fabs(xa[i])) < dif) {
00414       ns=i;
00415       dif=dift;
00416     }
00417     _c[i]=ya[i];
00418     _d[i]=ya[i];
00419   }
00420   _extrapValue= ya[ns--];
00421   for(m= 1; m < _nPoints; m++) {
00422     for(i= 1; i <= _nPoints-m; i++) {
00423       ho=xa[i];
00424       hp=xa[i+m];
00425       w=_c[i+1]-_d[i];
00426       if((den=ho-hp) == 0.0) {
00427         oocoutE((TObject*)0,Integration) << "RooIntegrator1D::extrapolate: internal error" << endl;
00428       }
00429       den=w/den;
00430       _d[i]=hp*den;
00431       _c[i]=ho*den;
00432     }
00433     _extrapValue += (_extrapError=(2*ns < (_nPoints-m) ? _c[ns+1] : _d[ns--]));
00434   }
00435 }

Generated on Tue Jul 5 15:06:42 2011 for ROOT_528-00b_version by  doxygen 1.5.1