ROOT  6.06/09
Reference Guide
RooIntegrator1D.cxx
Go to the documentation of this file.
1 /*****************************************************************************
2  * Project: RooFit *
3  * Package: RooFitCore *
4  * @(#)root/roofitcore:$Id$
5  * Authors: *
6  * WV, Wouter Verkerke, UC Santa Barbara, verkerke@slac.stanford.edu *
7  * DK, David Kirkby, UC Irvine, dkirkby@uci.edu *
8  * *
9  * Copyright (c) 2000-2005, Regents of the University of California *
10  * and Stanford University. All rights reserved. *
11  * *
12  * Redistribution and use in source and binary forms, *
13  * with or without modification, are permitted according to the terms *
14  * listed in LICENSE (http://roofit.sourceforge.net/license.txt) *
15  *****************************************************************************/
16 
17 //////////////////////////////////////////////////////////////////////////////
18 //
19 // BEGIN_HTML
20 // RooIntegrator1D implements an adaptive one-dimensional
21 // numerical integration algorithm.
22 // END_HTML
23 //
24 
25 
26 #include "RooFit.h"
27 #include "Riostream.h"
28 
29 #include "TClass.h"
30 #include "RooIntegrator1D.h"
31 #include "RooArgSet.h"
32 #include "RooRealVar.h"
33 #include "RooNumber.h"
34 #include "RooIntegratorBinding.h"
35 #include "RooNumIntConfig.h"
36 #include "RooNumIntFactory.h"
37 #include "RooMsgService.h"
38 
39 #include <assert.h>
40 
41 
42 
43 using namespace std;
44 
46 ;
47 
48 // Register this class with RooNumIntConfig
49 
50 ////////////////////////////////////////////////////////////////////////////////
51 /// Register RooIntegrator1D, is parameters and capabilities with RooNumIntFactory
52 
54 {
55  RooCategory sumRule("sumRule","Summation Rule") ;
56  sumRule.defineType("Trapezoid",RooIntegrator1D::Trapezoid) ;
57  sumRule.defineType("Midpoint",RooIntegrator1D::Midpoint) ;
58  sumRule.setLabel("Trapezoid") ;
59  RooCategory extrap("extrapolation","Extrapolation procedure") ;
60  extrap.defineType("None",0) ;
61  extrap.defineType("Wynn-Epsilon",1) ;
62  extrap.setLabel("Wynn-Epsilon") ;
63  RooRealVar maxSteps("maxSteps","Maximum number of steps",20) ;
64  RooRealVar minSteps("minSteps","Minimum number of steps",999) ;
65  RooRealVar fixSteps("fixSteps","Fixed number of steps",0) ;
66 
67  RooIntegrator1D* proto = new RooIntegrator1D() ;
68  fact.storeProtoIntegrator(proto,RooArgSet(sumRule,extrap,maxSteps,minSteps,fixSteps)) ;
70 }
71 
72 
73 
74 ////////////////////////////////////////////////////////////////////////////////
75 /// coverity[UNINIT_CTOR]
76 /// Default constructor
77 
79  _h(0), _s(0), _c(0), _d(0), _x(0)
80 {
81 }
82 
83 
84 ////////////////////////////////////////////////////////////////////////////////
85 /// Construct integrator on given function binding, using specified summation
86 /// rule, maximum number of steps and conversion tolerance. The integration
87 /// limits are taken from the function binding
88 
90  Int_t maxSteps, Double_t eps) :
91  RooAbsIntegrator(function), _rule(rule), _maxSteps(maxSteps), _minStepsZero(999), _fixSteps(0), _epsAbs(eps), _epsRel(eps), _doExtrap(kTRUE)
92 {
94  _valid= initialize();
95 }
96 
97 
98 ////////////////////////////////////////////////////////////////////////////////
99 /// Construct integrator on given function binding for given range,
100 /// using specified summation rule, maximum number of steps and
101 /// conversion tolerance. The integration limits are taken from the
102 /// function binding
103 
105  SummationRule rule, Int_t maxSteps, Double_t eps) :
107  _rule(rule),
108  _maxSteps(maxSteps),
109  _minStepsZero(999),
110  _fixSteps(0),
111  _epsAbs(eps),
112  _epsRel(eps),
113  _doExtrap(kTRUE)
114 {
116  _xmin= xmin;
117  _xmax= xmax;
118  _valid= initialize();
119 }
120 
121 
122 ////////////////////////////////////////////////////////////////////////////////
123 /// Construct integrator on given function binding, using specified
124 /// configuration object. The integration limits are taken from the
125 /// function binding
126 
128  RooAbsIntegrator(function,config.printEvalCounter()),
129  _epsAbs(config.epsAbs()),
130  _epsRel(config.epsRel())
131 {
132  // Extract parameters from config object
133  const RooArgSet& configSet = config.getConfigSection(IsA()->GetName()) ;
134  _rule = (SummationRule) configSet.getCatIndex("sumRule",Trapezoid) ;
135  _maxSteps = (Int_t) configSet.getRealValue("maxSteps",20) ;
136  _minStepsZero = (Int_t) configSet.getRealValue("minSteps",999) ;
137  _fixSteps = (Int_t) configSet.getRealValue("fixSteps",0) ;
138  _doExtrap = (Bool_t) configSet.getCatIndex("extrapolation",1) ;
139 
140  if (_fixSteps>_maxSteps) {
141  oocoutE((TObject*)0,Integration) << "RooIntegrator1D::ctor() ERROR: fixSteps>maxSteps, fixSteps set to maxSteps" << endl ;
142  _fixSteps = _maxSteps ;
143  }
144 
146  _valid= initialize();
147 }
148 
149 
150 
151 ////////////////////////////////////////////////////////////////////////////////
152 /// Construct integrator on given function binding, using specified
153 /// configuration object and integration range
154 
156  const RooNumIntConfig& config) :
157  RooAbsIntegrator(function,config.printEvalCounter()),
158  _epsAbs(config.epsAbs()),
159  _epsRel(config.epsRel())
160 {
161  // Extract parameters from config object
162  const RooArgSet& configSet = config.getConfigSection(IsA()->GetName()) ;
163  _rule = (SummationRule) configSet.getCatIndex("sumRule",Trapezoid) ;
164  _maxSteps = (Int_t) configSet.getRealValue("maxSteps",20) ;
165  _minStepsZero = (Int_t) configSet.getRealValue("minSteps",999) ;
166  _fixSteps = (Int_t) configSet.getRealValue("fixSteps",0) ;
167  _doExtrap = (Bool_t) configSet.getCatIndex("extrapolation",1) ;
168 
170  _xmin= xmin;
171  _xmax= xmax;
172  _valid= initialize();
173 }
174 
175 
176 
177 ////////////////////////////////////////////////////////////////////////////////
178 /// Clone integrator with new function binding and configuration. Needed by RooNumIntFactory
179 
181 {
182  return new RooIntegrator1D(function,config) ;
183 }
184 
185 
186 
187 ////////////////////////////////////////////////////////////////////////////////
188 /// Initialize the integrator
189 
191 {
192  // apply defaults if necessary
193  if(_maxSteps <= 0) {
194  _maxSteps= (_rule == Trapezoid) ? 20 : 14;
195  }
196 
197  if(_epsRel <= 0) _epsRel= 1e-6;
198  if(_epsAbs <= 0) _epsAbs= 1e-6;
199 
200  // check that the integrand is a valid function
201  if(!isValid()) {
202  oocoutE((TObject*)0,Integration) << "RooIntegrator1D::initialize: cannot integrate invalid function" << endl;
203  return kFALSE;
204  }
205 
206  // Allocate coordinate buffer size after number of function dimensions
207  _x = new Double_t[_function->getDimension()] ;
208 
209 
210  // Allocate workspace for numerical integration engine
211  _h= new Double_t[_maxSteps + 2];
212  _s= new Double_t[_maxSteps + 2];
213  _c= new Double_t[_nPoints + 1];
214  _d= new Double_t[_nPoints + 1];
215 
216  return checkLimits();
217 }
218 
219 
220 ////////////////////////////////////////////////////////////////////////////////
221 /// Destructor
222 
224 {
225  // Release integrator workspace
226  if(_h) delete[] _h;
227  if(_s) delete[] _s;
228  if(_c) delete[] _c;
229  if(_d) delete[] _d;
230  if(_x) delete[] _x;
231 }
232 
233 
234 ////////////////////////////////////////////////////////////////////////////////
235 /// Change our integration limits. Return kTRUE if the new limits are
236 /// ok, or otherwise kFALSE. Always returns kFALSE and does nothing
237 /// if this object was constructed to always use our integrand's limits.
238 
240 {
241  if(_useIntegrandLimits) {
242  oocoutE((TObject*)0,Integration) << "RooIntegrator1D::setLimits: cannot override integrand's limits" << endl;
243  return kFALSE;
244  }
245  _xmin= *xmin;
246  _xmax= *xmax;
247  return checkLimits();
248 }
249 
250 
251 ////////////////////////////////////////////////////////////////////////////////
252 /// Check that our integration range is finite and otherwise return kFALSE.
253 /// Update the limits from the integrand if requested.
254 
256 {
257  if(_useIntegrandLimits) {
258  assert(0 != integrand() && integrand()->isValid());
259  _xmin= integrand()->getMinLimit(0);
260  _xmax= integrand()->getMaxLimit(0);
261  }
262  _range= _xmax - _xmin;
263  if(_range < 0) {
264  oocoutE((TObject*)0,Integration) << "RooIntegrator1D::checkLimits: bad range with min >= max (_xmin = " << _xmin << " _xmax = " << _xmax << ")" << endl;
265  return kFALSE;
266  }
268 }
269 
270 
271 ////////////////////////////////////////////////////////////////////////////////
272 /// Calculate numeric integral at given set of function binding parameters
273 
275 {
276  assert(isValid());
277 
278  // Copy yvec to xvec if provided
279  if (yvec) {
280  UInt_t i ; for (i=0 ; i<_function->getDimension()-1 ; i++) {
281  _x[i+1] = yvec[i] ;
282  }
283  }
284 
285  Int_t j;
286  _h[1]=1.0;
287  Double_t zeroThresh = _epsAbs/_range ;
288  for(j= 1; j<=_maxSteps; j++) {
289  // refine our estimate using the appropriate summation rule
290  _s[j]= (_rule == Trapezoid) ? addTrapezoids(j) : addMidpoints(j);
291 
292  if (j >= _minStepsZero) {
293  Bool_t allZero(kTRUE) ;
294  Int_t jj ; for (jj=0 ; jj<=j ; jj++) {
295  if (_s[j]>=zeroThresh) {
296  allZero=kFALSE ;
297  }
298  }
299  if (allZero) {
300  //cout << "Roo1DIntegrator(" << this << "): zero convergence at step " << j << ", value = " << 0 << endl ;
301  return 0;
302  }
303  }
304 
305  if (_fixSteps>0) {
306 
307  // Fixed step mode, return result after fixed number of steps
308  if (j==_fixSteps) {
309  //cout << "returning result at fixed step " << j << endl ;
310  return _s[j];
311  }
312 
313  } else if(j >= _nPoints) {
314 
315  // extrapolate the results of recent refinements and check for a stable result
316  if (_doExtrap) {
317  extrapolate(j);
318  } else {
319  _extrapValue = _s[j] ;
320  _extrapError = _s[j]-_s[j-1] ;
321  }
322 
324  return _extrapValue;
325  }
326  if(fabs(_extrapError) <= _epsAbs) {
327  return _extrapValue ;
328  }
329 
330  }
331  // update the step size for the next refinement of the summation
332  _h[j+1]= (_rule == Trapezoid) ? _h[j]/4. : _h[j]/9.;
333  }
334 
335  oocoutW((TObject*)0,Integration) << "RooIntegrator1D::integral: integral of " << _function->getName() << " over range (" << _xmin << "," << _xmax << ") did not converge after "
336  << _maxSteps << " steps" << endl;
337  for(j= 1; j <= _maxSteps; j++) {
338  ooccoutW((TObject*)0,Integration) << " [" << j << "] h = " << _h[j] << " , s = " << _s[j] << endl;
339  }
340 
341  return _s[_maxSteps] ;
342 
343 }
344 
345 
346 ////////////////////////////////////////////////////////////////////////////////
347 /// Calculate the n-th stage of refinement of the Second Euler-Maclaurin
348 /// summation rule which has the useful property of not evaluating the
349 /// integrand at either of its endpoints but requires more function
350 /// evaluations than the trapezoidal rule. This rule can be used with
351 /// a suitable change of variables to estimate improper integrals.
352 
354 {
355  Double_t x,tnm,sum,del,ddel;
356  Int_t it,j;
357 
358  if(n == 1) {
359  Double_t xmid= 0.5*(_xmin + _xmax);
360  return (_savedResult= _range*integrand(xvec(xmid)));
361  }
362  else {
363  for(it=1, j=1; j < n-1; j++) it*= 3;
364  tnm= it;
365  del= _range/(3.*tnm);
366  ddel= del+del;
367  x= _xmin + 0.5*del;
368  for(sum= 0, j= 1; j <= it; j++) {
369  sum+= integrand(xvec(x));
370  x+= ddel;
371  sum+= integrand(xvec(x));
372  x+= del;
373  }
374  return (_savedResult= (_savedResult + _range*sum/tnm)/3.);
375  }
376 }
377 
378 
379 ////////////////////////////////////////////////////////////////////////////////
380 /// Calculate the n-th stage of refinement of the extended trapezoidal
381 /// summation rule. This is the most efficient rule for a well behaved
382 /// integrand that can be evaluated over its entire range, including the
383 /// endpoints.
384 
386 {
387  Double_t x,tnm,sum,del;
388  Int_t it,j;
389 
390  if (n == 1) {
391  // use a single trapezoid to cover the full range
392  return (_savedResult= 0.5*_range*(integrand(xvec(_xmin)) + integrand(xvec(_xmax))));
393  }
394  else {
395  // break the range down into several trapezoids using 2**(n-2)
396  // equally-spaced interior points
397  for(it=1, j=1; j < n-1; j++) it <<= 1;
398  tnm= it;
399  del= _range/tnm;
400  x= _xmin + 0.5*del;
401  for(sum=0.0, j=1; j<=it; j++, x+=del) sum += integrand(xvec(x));
402  return (_savedResult= 0.5*(_savedResult + _range*sum/tnm));
403  }
404 }
405 
406 
407 
408 ////////////////////////////////////////////////////////////////////////////////
409 /// Extrapolate result to final value
410 
412 {
413  Double_t *xa= &_h[n-_nPoints];
414  Double_t *ya= &_s[n-_nPoints];
415  Int_t i,m,ns=1;
416  Double_t den,dif,dift,ho,hp,w;
417 
418  dif=fabs(xa[1]);
419  for (i= 1; i <= _nPoints; i++) {
420  if ((dift=fabs(xa[i])) < dif) {
421  ns=i;
422  dif=dift;
423  }
424  _c[i]=ya[i];
425  _d[i]=ya[i];
426  }
427  _extrapValue= ya[ns--];
428  for(m= 1; m < _nPoints; m++) {
429  for(i= 1; i <= _nPoints-m; i++) {
430  ho=xa[i];
431  hp=xa[i+m];
432  w=_c[i+1]-_d[i];
433  if((den=ho-hp) == 0.0) {
434  oocoutE((TObject*)0,Integration) << "RooIntegrator1D::extrapolate: internal error" << endl;
435  }
436  den=w/den;
437  _d[i]=hp*den;
438  _c[i]=ho*den;
439  }
440  _extrapValue += (_extrapError=(2*ns < (_nPoints-m) ? _c[ns+1] : _d[ns--]));
441  }
442 }
static RooNumIntConfig & defaultConfig()
Return reference to instance of default numeric integrator configuration object.
Double_t * _s
Integrator workspace.
float xmin
Definition: THbookFile.cxx:93
virtual const char * getName() const
Definition: RooAbsFunc.h:59
Double_t _extrapError
Extrapolated value.
RooIntegrator1D()
coverity[UNINIT_CTOR] Default constructor
Double_t * _c
Integrator workspace.
#define assert(cond)
Definition: unittest.h:542
Double_t * xvec(Double_t &xx)
Integrator workspace.
Bool_t initialize()
Initialize the integrator.
static void registerIntegrator(RooNumIntFactory &fact)
Register RooIntegrator1D, is parameters and capabilities with RooNumIntFactory.
Double_t _extrapValue
Size of integration range.
int Int_t
Definition: RtypesCore.h:41
bool Bool_t
Definition: RtypesCore.h:59
Double_t addMidpoints(Int_t n)
Calculate the n-th stage of refinement of the Second Euler-Maclaurin summation rule which has the use...
const Bool_t kFALSE
Definition: Rtypes.h:92
static Int_t isInfinite(Double_t x)
Return true if x is infinite by RooNumBer internal specification.
Definition: RooNumber.cxx:57
STL namespace.
virtual ~RooIntegrator1D()
Destructor.
UInt_t getDimension() const
Definition: RooAbsFunc.h:29
Double_t addTrapezoids(Int_t n)
Calculate the n-th stage of refinement of the extended trapezoidal summation rule.
#define ooccoutW(o, a)
Definition: RooMsgService.h:54
virtual Bool_t setLabel(const char *label, Bool_t printError=kTRUE)
Set value by specifying the name of the desired state If printError is set, a message will be printed...
Double_t _savedResult
Integrator workspace.
ClassImp(RooIntegrator1D)
RooCategory & method1D()
Double_t x[n]
Definition: legend1.C:17
#define oocoutE(o, a)
Definition: RooMsgService.h:48
Double_t _range
Upper integration bound.
Double_t * _d
Integrator workspace.
VecExpr< UnaryOp< Fabs< T >, VecExpr< A, T, D >, T >, T, D > fabs(const VecExpr< A, T, D > &rhs)
void function(const char *name_, T fun, const char *docstring=0)
Definition: RExports.h:159
virtual Double_t integral(const Double_t *yvec=0)
Calculate numeric integral at given set of function binding parameters.
Int_t getCatIndex(const char *name, Int_t defVal=0, Bool_t verbose=kFALSE) const
Get index value of a RooAbsCategory stored in set with given name.
Definition: RooArgSet.cxx:613
TClass * IsA() const
unsigned int UInt_t
Definition: RtypesCore.h:42
TMarker * m
Definition: textangle.C:8
const RooAbsFunc * _function
virtual Double_t getMinLimit(UInt_t dimension) const =0
virtual Bool_t checkLimits() const
Check that our integration range is finite and otherwise return kFALSE.
float xmax
Definition: THbookFile.cxx:93
Bool_t setLimits(Double_t *xmin, Double_t *xmax)
Change our integration limits.
virtual Double_t getMaxLimit(UInt_t dimension) const =0
virtual const char * GetName() const
Returns name of object.
Definition: TObject.cxx:415
double Double_t
Definition: RtypesCore.h:55
virtual RooAbsIntegrator * clone(const RooAbsFunc &function, const RooNumIntConfig &config) const
Clone integrator with new function binding and configuration. Needed by RooNumIntFactory.
Double_t * _h
Error on extrapolated value.
#define oocoutW(o, a)
Definition: RooMsgService.h:47
Mother of all ROOT objects.
Definition: TObject.h:58
Bool_t _useIntegrandLimits
Double_t _xmax
Lower integration bound.
const RooAbsFunc * integrand() const
Bool_t defineType(const char *label)
Define a state with given name, the lowest available positive integer is assigned as index...
Bool_t isValid() const
void extrapolate(Int_t n)
Extrapolate result to final value.
SummationRule _rule
const Bool_t kTRUE
Definition: Rtypes.h:91
const Int_t n
Definition: legend1.C:16
const RooArgSet & getConfigSection(const char *name) const
Retrieve configuration information specific to integrator with given name.
Bool_t storeProtoIntegrator(RooAbsIntegrator *proto, const RooArgSet &defConfig, const char *depName="")
Method accepting registration of a prototype numeric integrator along with a RooArgSet of its default...
Double_t getRealValue(const char *name, Double_t defVal=0, Bool_t verbose=kFALSE) const
Get value of a RooAbsReal stored in set with given name.
Definition: RooArgSet.cxx:527