Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
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\file RooIntegrator1D.cxx
19\class RooIntegrator1D
20\ingroup Roofitcore
21
22RooIntegrator1D implements an adaptive one-dimensional
23numerical integration algorithm.
24**/
25
26
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"
35#include "RooNumIntConfig.h"
36#include "RooNumIntFactory.h"
37#include "RooMsgService.h"
38
39#include <assert.h>
40
41
42
43using 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
68 fact.storeProtoIntegrator(proto,RooArgSet(sumRule,extrap,maxSteps,minSteps,fixSteps)) ;
70}
71
72
73////////////////////////////////////////////////////////////////////////////////
74/// Construct integrator on given function binding, using specified summation
75/// rule, maximum number of steps and conversion tolerance. The integration
76/// limits are taken from the function binding
77
79 Int_t maxSteps, double eps) :
80 RooAbsIntegrator(function), _rule(rule), _maxSteps(maxSteps), _minStepsZero(999), _fixSteps(0), _epsAbs(eps), _epsRel(eps), _doExtrap(true)
81{
84}
85
86
87////////////////////////////////////////////////////////////////////////////////
88/// Construct integrator on given function binding for given range,
89/// using specified summation rule, maximum number of steps and
90/// conversion tolerance. The integration limits are taken from the
91/// function binding
92
93RooIntegrator1D::RooIntegrator1D(const RooAbsFunc& function, double xmin, double xmax,
94 SummationRule rule, Int_t maxSteps, double eps) :
95 RooAbsIntegrator(function),
96 _rule(rule),
97 _maxSteps(maxSteps),
98 _minStepsZero(999),
99 _fixSteps(0),
100 _epsAbs(eps),
101 _epsRel(eps),
102 _doExtrap(true)
103{
104 _useIntegrandLimits= false;
105 _xmin= xmin;
106 _xmax= xmax;
108}
109
110
111////////////////////////////////////////////////////////////////////////////////
112/// Construct integrator on given function binding, using specified
113/// configuration object. The integration limits are taken from the
114/// function binding
115
117 RooAbsIntegrator(function,config.printEvalCounter()),
118 _epsAbs(config.epsAbs()),
119 _epsRel(config.epsRel())
120{
121 // Extract parameters from config object
122 const RooArgSet& configSet = config.getConfigSection(ClassName()) ;
123 _rule = (SummationRule) configSet.getCatIndex("sumRule",Trapezoid) ;
124 _maxSteps = (Int_t) configSet.getRealValue("maxSteps",20) ;
125 _minStepsZero = (Int_t) configSet.getRealValue("minSteps",999) ;
126 _fixSteps = (Int_t) configSet.getRealValue("fixSteps",0) ;
127 _doExtrap = (bool) configSet.getCatIndex("extrapolation",1) ;
128
129 if (_fixSteps>_maxSteps) {
130 oocoutE(nullptr,Integration) << "RooIntegrator1D::ctor() ERROR: fixSteps>maxSteps, fixSteps set to maxSteps" << endl ;
132 }
133
136}
137
138
139
140////////////////////////////////////////////////////////////////////////////////
141/// Construct integrator on given function binding, using specified
142/// configuration object and integration range
143
144RooIntegrator1D::RooIntegrator1D(const RooAbsFunc& function, double xmin, double xmax,
145 const RooNumIntConfig& config) :
146 RooAbsIntegrator(function,config.printEvalCounter()),
147 _epsAbs(config.epsAbs()),
148 _epsRel(config.epsRel())
149{
150 // Extract parameters from config object
151 const RooArgSet& configSet = config.getConfigSection(ClassName()) ;
152 _rule = (SummationRule) configSet.getCatIndex("sumRule",Trapezoid) ;
153 _maxSteps = (Int_t) configSet.getRealValue("maxSteps",20) ;
154 _minStepsZero = (Int_t) configSet.getRealValue("minSteps",999) ;
155 _fixSteps = (Int_t) configSet.getRealValue("fixSteps",0) ;
156 _doExtrap = (bool) configSet.getCatIndex("extrapolation",1) ;
157
158 _useIntegrandLimits= false;
159 _xmin= xmin;
160 _xmax= xmax;
162}
163
164
165
166////////////////////////////////////////////////////////////////////////////////
167/// Clone integrator with new function binding and configuration. Needed by RooNumIntFactory
168
170{
171 return new RooIntegrator1D(function,config) ;
172}
173
174
175
176////////////////////////////////////////////////////////////////////////////////
177/// Initialize the integrator
178
180{
181 // apply defaults if necessary
182 if(_maxSteps <= 0) {
183 _maxSteps= (_rule == Trapezoid) ? 20 : 14;
184 }
185
186 if(_epsRel <= 0) _epsRel= 1e-6;
187 if(_epsAbs <= 0) _epsAbs= 1e-6;
188
189 // check that the integrand is a valid function
190 if(!isValid()) {
191 oocoutE(nullptr,Integration) << "RooIntegrator1D::initialize: cannot integrate invalid function" << endl;
192 return false;
193 }
194
195 // Allocate coordinate buffer size after number of function dimensions
196 _x.resize(_function->getDimension());
197
198
199 // Allocate workspace for numerical integration engine
200 _h.resize(_maxSteps + 2);
201 _s.resize(_maxSteps + 2);
202 _c.resize(_nPoints + 1);
203 _d.resize(_nPoints + 1);
204
205 return checkLimits();
206}
207
208
209////////////////////////////////////////////////////////////////////////////////
210/// Change our integration limits. Return true if the new limits are
211/// ok, or otherwise false. Always returns false and does nothing
212/// if this object was constructed to always use our integrand's limits.
213
215{
217 oocoutE(nullptr,Integration) << "RooIntegrator1D::setLimits: cannot override integrand's limits" << endl;
218 return false;
219 }
220 _xmin= *xmin;
221 _xmax= *xmax;
222 return checkLimits();
223}
224
225
226////////////////////////////////////////////////////////////////////////////////
227/// Check that our integration range is finite and otherwise return false.
228/// Update the limits from the integrand if requested.
229
231{
233 assert(0 != integrand() && integrand()->isValid());
234 const_cast<double&>(_xmin) = integrand()->getMinLimit(0);
235 const_cast<double&>(_xmax) = integrand()->getMaxLimit(0);
236 }
237 const_cast<double&>(_range) = _xmax - _xmin;
238 if (_range < 0.) {
239 oocoutE(nullptr,Integration) << "RooIntegrator1D::checkLimits: bad range with min > max (_xmin = " << _xmin << " _xmax = " << _xmax << ")" << endl;
240 return false;
241 }
242 return (RooNumber::isInfinite(_xmin) || RooNumber::isInfinite(_xmax)) ? false : true;
243}
244
245
246////////////////////////////////////////////////////////////////////////////////
247/// Calculate numeric integral at given set of function binding parameters
248
249double RooIntegrator1D::integral(const double *yvec)
250{
251 assert(isValid());
252
253 if (_range == 0.)
254 return 0.;
255
256 // Copy yvec to xvec if provided
257 if (yvec) {
258 for (UInt_t i = 0 ; i<_function->getDimension()-1 ; i++) {
259 _x[i+1] = yvec[i] ;
260 }
261 }
262
263
264 _h[1]=1.0;
265 double zeroThresh = _epsAbs/_range ;
266 for(Int_t j = 1; j <= _maxSteps; ++j) {
267 // refine our estimate using the appropriate summation rule
268 _s[j]= (_rule == Trapezoid) ? addTrapezoids(j) : addMidpoints(j);
269
270 if (j >= _minStepsZero) {
271 bool allZero(true) ;
272 for (int jj=0 ; jj<=j ; jj++) {
273 if (_s[j]>=zeroThresh) {
274 allZero=false ;
275 }
276 }
277 if (allZero) {
278 //cout << "Roo1DIntegrator(" << this << "): zero convergence at step " << j << ", value = " << 0 << endl ;
279 return 0;
280 }
281 }
282
283 if (_fixSteps>0) {
284
285 // Fixed step mode, return result after fixed number of steps
286 if (j==_fixSteps) {
287 //cout << "returning result at fixed step " << j << endl ;
288 return _s[j];
289 }
290
291 } else if(j >= _nPoints) {
292
293 // extrapolate the results of recent refinements and check for a stable result
294 if (_doExtrap) {
295 extrapolate(j);
296 } else {
297 _extrapValue = _s[j] ;
298 _extrapError = _s[j]-_s[j-1] ;
299 }
300
301 if(std::abs(_extrapError) <= _epsRel*std::abs(_extrapValue)) {
302 return _extrapValue;
303 }
304 if(std::abs(_extrapError) <= _epsAbs) {
305 return _extrapValue ;
306 }
307
308 }
309 // update the step size for the next refinement of the summation
310 _h[j+1]= (_rule == Trapezoid) ? _h[j]/4. : _h[j]/9.;
311 }
312
313 oocoutW(nullptr,Integration) << "RooIntegrator1D::integral: integral of " << _function->getName() << " over range (" << _xmin << "," << _xmax << ") did not converge after "
314 << _maxSteps << " steps" << endl;
315 for(Int_t j = 1; j <= _maxSteps; ++j) {
316 ooccoutW(nullptr,Integration) << " [" << j << "] h = " << _h[j] << " , s = " << _s[j] << endl;
317 }
318
319 return _s[_maxSteps] ;
320}
321
322
323////////////////////////////////////////////////////////////////////////////////
324/// Calculate the n-th stage of refinement of the Second Euler-Maclaurin
325/// summation rule which has the useful property of not evaluating the
326/// integrand at either of its endpoints but requires more function
327/// evaluations than the trapezoidal rule. This rule can be used with
328/// a suitable change of variables to estimate improper integrals.
329
331{
332 double x,tnm,sum,del,ddel;
333 Int_t it,j;
334
335 if(n == 1) {
336 double xmid= 0.5*(_xmin + _xmax);
337 return (_savedResult= _range*integrand(xvec(xmid)));
338 }
339 else {
340 for(it=1, j=1; j < n-1; j++) it*= 3;
341 tnm= it;
342 del= _range/(3.*tnm);
343 ddel= del+del;
344 x= _xmin + 0.5*del;
345 for(sum= 0, j= 1; j <= it; j++) {
346 sum+= integrand(xvec(x));
347 x+= ddel;
348 sum+= integrand(xvec(x));
349 x+= del;
350 }
351 return (_savedResult= (_savedResult + _range*sum/tnm)/3.);
352 }
353}
354
355
356////////////////////////////////////////////////////////////////////////////////
357/// Calculate the n-th stage of refinement of the extended trapezoidal
358/// summation rule. This is the most efficient rule for a well behaved
359/// integrands that can be evaluated over its entire range, including the
360/// endpoints.
361
363{
364 if (n == 1) {
365 // use a single trapezoid to cover the full range
367 }
368 else {
369 // break the range down into several trapezoids using 2**(n-2)
370 // equally-spaced interior points
371 const int nInt = 1 << (n-2);
372 const double del = _range/nInt;
373 const double xmin = _xmin;
374
375 double sum = 0.;
376 // TODO Replace by batch computation
377 for (int j=0; j<nInt; ++j) {
378 double x = xmin + (0.5+j)*del;
379 sum += integrand(xvec(x));
380 }
381
382 return (_savedResult= 0.5*(_savedResult + _range*sum/nInt));
383 }
384}
385
386
387
388////////////////////////////////////////////////////////////////////////////////
389/// Extrapolate result to final value
390
392{
393 double *xa= &_h[n-_nPoints];
394 double *ya= &_s[n-_nPoints];
395 Int_t i,m,ns=1;
396 double den,dif,dift,ho,hp,w;
397
398 dif=std::abs(xa[1]);
399 for (i= 1; i <= _nPoints; i++) {
400 if ((dift=std::abs(xa[i])) < dif) {
401 ns=i;
402 dif=dift;
403 }
404 _c[i]=ya[i];
405 _d[i]=ya[i];
406 }
407 _extrapValue= ya[ns--];
408 for(m= 1; m < _nPoints; m++) {
409 for(i= 1; i <= _nPoints-m; i++) {
410 ho=xa[i];
411 hp=xa[i+m];
412 w=_c[i+1]-_d[i];
413 if((den=ho-hp) == 0.0) {
414 oocoutE(nullptr,Integration) << "RooIntegrator1D::extrapolate: internal error" << endl;
415 }
416 den=w/den;
417 _d[i]=hp*den;
418 _c[i]=ho*den;
419 }
420 _extrapValue += (_extrapError=(2*ns < (_nPoints-m) ? _c[ns+1] : _d[ns--]));
421 }
422}
#define e(i)
Definition RSha256.hxx:103
#define oocoutW(o, a)
#define oocoutE(o, a)
#define ooccoutW(o, a)
int Int_t
Definition RtypesCore.h:45
#define ClassImp(name)
Definition Rtypes.h:377
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t del
float xmin
float xmax
const char * proto
Definition civetweb.c:17502
double getRealValue(const char *name, double defVal=0.0, bool verbose=false) const
Get value of a RooAbsReal stored in set with given name.
Int_t getCatIndex(const char *name, Int_t defVal=0, bool verbose=false) const
Get index value of a RooAbsCategory stored in set with given name.
Abstract interface for evaluating a real-valued function of one real variable and performing numerica...
Definition RooAbsFunc.h:27
virtual double getMaxLimit(UInt_t dimension) const =0
virtual double getMinLimit(UInt_t dimension) const =0
UInt_t getDimension() const
Definition RooAbsFunc.h:33
virtual const char * getName() const
Name of function binding.
Definition RooAbsFunc.h:65
RooAbsIntegrator is the abstract interface for integrators of real-valued functions that implement th...
bool isValid() const
Is integrator in valid state.
const RooAbsFunc * _function
Pointer to function binding of integrand.
const RooAbsFunc * integrand() const
Return integrand function binding.
bool _valid
Is integrator in valid state?
RooArgSet is a container object that can hold multiple RooAbsArg objects.
Definition RooArgSet.h:55
RooCategory is an object to represent discrete states.
Definition RooCategory.h:28
bool defineType(const std::string &label)
Define a state with given name.
bool setLabel(const char *label, bool printError=true) override
Set value by specifying the name of the desired state.
RooIntegrator1D implements an adaptive one-dimensional numerical integration algorithm.
std::vector< double > _c
! Integrator workspace
RooAbsIntegrator * clone(const RooAbsFunc &function, const RooNumIntConfig &config) const override
Clone integrator with new function binding and configuration. Needed by RooNumIntFactory.
void extrapolate(Int_t n)
Extrapolate result to final value.
double _xmax
! Upper integration bound
double addMidpoints(Int_t n)
Calculate the n-th stage of refinement of the Second Euler-Maclaurin summation rule which has the use...
double _extrapError
! Error on extrapolated value
bool _doExtrap
Apply conversion step?
Int_t _minStepsZero
Minimum number of steps to declare convergence to zero.
SummationRule _rule
double * xvec(double &xx)
double addTrapezoids(Int_t n)
Calculate the n-th stage of refinement of the extended trapezoidal summation rule.
std::vector< double > _d
! Integrator workspace
double integral(const double *yvec=nullptr) override
Calculate numeric integral at given set of function binding parameters.
double _xmin
! Lower integration bound
bool _useIntegrandLimits
If true limits of function binding are used.
std::vector< double > _h
! Integrator workspace
double _epsRel
Relative convergence tolerance.
Int_t _maxSteps
Maximum number of steps.
Int_t _fixSteps
Fixed number of steps.
bool initialize()
Initialize the integrator.
double _savedResult
! Integrator workspace
double _range
! Size of integration range
std::vector< double > _x
static void registerIntegrator(RooNumIntFactory &fact)
Register RooIntegrator1D, is parameters and capabilities with RooNumIntFactory.
bool setLimits(double *xmin, double *xmax) override
Change our integration limits.
std::vector< double > _s
! Integrator workspace
bool checkLimits() const override
Check that our integration range is finite and otherwise return false.
double _epsAbs
Absolute convergence tolerance.
double _extrapValue
! Extrapolated value
RooNumIntConfig holds the configuration parameters of the various numeric integrators used by RooReal...
const RooArgSet & getConfigSection(const char *name) const
Retrieve configuration information specific to integrator with given name.
RooCategory & method1D()
static RooNumIntConfig & defaultConfig()
Return reference to instance of default numeric integrator configuration object.
RooNumIntFactory is a factory to instantiate numeric integrators from a given function binding and a ...
bool storeProtoIntegrator(RooAbsIntegrator *proto, const RooArgSet &defConfig, const char *depName="")
Method accepting registration of a prototype numeric integrator along with a RooArgSet of its default...
static constexpr int isInfinite(double x)
Return true if x is infinite by RooNumber internal specification.
Definition RooNumber.h:34
RooRealVar represents a variable that can be changed from the outside.
Definition RooRealVar.h:40
virtual const char * ClassName() const
Returns name of class to which the object belongs.
Definition TObject.cxx:207
Double_t x[n]
Definition legend1.C:17
const Int_t n
Definition legend1.C:16
TMarker m
Definition textangle.C:8
static uint64_t sum(uint64_t i)
Definition Factory.cxx:2345