52constexpr int nPoints = 5;
61double addMidpoints(std::function<
double(
double)>
const &func,
double savedResult,
int n,
double xmin,
double xmax)
67 return range * func(xmid);
71 for (
int j = 1; j <
n - 1; j++) {
75 double del = range / (3. * tnm);
76 double ddel = del + del;
77 double x =
xmin + 0.5 * del;
79 for (
int j = 1; j <= it; j++) {
85 return (savedResult + range *
sum / tnm) / 3.;
94double addTrapezoids(std::function<
double(
double)>
const &func,
double savedResult,
int n,
double xmin,
double xmax)
100 return 0.5 * range * (func(
xmin) + func(
xmax));
105 const int nInt = 1 << (
n - 2);
106 const double del = range / nInt;
110 for (
int j = 0; j < nInt; ++j) {
111 double x =
xmin + (0.5 + j) * del;
115 return 0.5 * (savedResult + range *
sum / nInt);
121std::pair<double, double> extrapolate(
int n,
double const *
h,
double const *s,
double *
c,
double *
d)
123 double const *xa = &
h[
n - nPoints];
124 double const *ya = &s[
n - nPoints];
127 double dif = std::abs(xa[1]);
128 for (
int i = 1; i <= nPoints; i++) {
129 double dift = std::abs(xa[i]);
137 double extrapError = 0.0;
138 double extrapValue = ya[ns--];
139 for (
int m = 1;
m < nPoints;
m++) {
140 for (
int i = 1; i <= nPoints -
m; i++) {
142 double hp = xa[i +
m];
143 double w =
c[i + 1] -
d[i];
144 double den = ho - hp;
146 throw std::runtime_error(
"RooRombergIntegrator::extrapolate: internal error");
152 extrapError = 2 * ns < (nPoints -
m) ?
c[ns + 1] :
d[ns--];
153 extrapValue += extrapError;
155 return {extrapValue, extrapError};
163std::pair<double, int> integrate1d(std::function<
double(
double)> func,
bool doTrapezoid,
int maxSteps,
int minStepsZero,
164 int fixSteps,
double epsAbs,
double epsRel,
bool doExtrap,
double xmin,
double xmax,
165 std::span<double> hArr, std::span<double> sArr)
167 assert(
int(hArr.size()) == maxSteps + 2);
168 assert(
int(sArr.size()) == maxSteps + 2);
173 std::array<double, nPoints + 1> cArr = {};
174 std::array<double, nPoints + 1> dArr = {};
177 double zeroThresh = epsAbs / range;
178 for (
int j = 1; j <= maxSteps; ++j) {
181 doTrapezoid ? addTrapezoids(func, sArr[j - 1], j,
xmin,
xmax) : addMidpoints(func, sArr[j - 1], j,
xmin,
xmax);
183 if (j >= minStepsZero) {
185 for (
int jj = 0; jj <= j; jj++) {
186 if (sArr[j] >= zeroThresh) {
205 }
else if (j >= nPoints) {
207 double extrapValue = 0.0;
208 double extrapError = 0.0;
212 std::tie(extrapValue, extrapError) = extrapolate(j, hArr.data(), sArr.data(), cArr.data(), dArr.data());
214 extrapValue = sArr[j];
215 extrapError = sArr[j] - sArr[j - 1];
218 if (std::abs(extrapError) <= epsRel * std::abs(extrapValue)) {
219 return {extrapValue, j};
221 if (std::abs(extrapError) <= epsAbs) {
222 return {extrapValue, j};
226 hArr[j + 1] = doTrapezoid ? hArr[j] / 4. : hArr[j] / 9.;
229 return {sArr[maxSteps], maxSteps};
244 sumRule.defineType(
"Trapezoid", RooRombergIntegrator::Trapezoid);
245 sumRule.defineType(
"Midpoint", RooRombergIntegrator::Midpoint);
246 sumRule.setLabel(
"Trapezoid");
247 RooCategory extrap(
"extrapolation",
"Extrapolation procedure");
248 extrap.defineType(
"None", 0);
249 extrap.defineType(
"Wynn-Epsilon", 1);
250 extrap.setLabel(
"Wynn-Epsilon");
251 RooRealVar maxSteps(
"maxSteps",
"Maximum number of steps", 20);
252 RooRealVar minSteps(
"minSteps",
"Minimum number of steps", 999);
253 RooRealVar fixSteps(
"fixSteps",
"Fixed number of steps", 0);
254 RooRealVar numSeg(
"numSeg",
"Number of segments", 3);
256 std::string
name =
"RooIntegrator1D";
259 return std::make_unique<RooRombergIntegrator>(function, config, 1,
false);
271 return std::make_unique<RooRombergIntegrator>(function, config, 2,
false);
273 std::string name2d =
"RooIntegrator2D";
283 return std::make_unique<RooRombergIntegrator>(function, config, 1,
true);
286 fact.
registerPlugin(
"RooSegmentedIntegrator1D", creatorSeg, {numSeg},
294 return std::make_unique<RooRombergIntegrator>(function, config, 2,
true);
302 "RooSegmentedIntegrator1D");
310RooRombergIntegrator::RooRombergIntegrator(
const RooAbsFunc &function, SummationRule rule,
int maxSteps,
double eps)
311 :
RooAbsIntegrator(
function), _useIntegrandLimits(true), _rule(rule), _maxSteps(maxSteps), _epsAbs(eps), _epsRel(eps)
322RooRombergIntegrator::RooRombergIntegrator(
const RooAbsFunc &function,
double xmin,
double xmax, SummationRule rule,
323 int maxSteps,
double eps)
325 _useIntegrandLimits(false),
331 _xmin.push_back(
xmin);
332 _xmax.push_back(
xmax);
345 _epsAbs(config.epsAbs()),
346 _epsRel(config.epsRel())
350 _rule = (SummationRule)configSet.
getCatIndex(
"sumRule", Trapezoid);
355 if (doSegmentation) {
357 _epsAbs /= std::sqrt(_nSeg);
358 _epsRel /= std::sqrt(_nSeg);
361 if (_fixSteps > _maxSteps) {
362 oocoutE(
nullptr, Integration) <<
"RooRombergIntegrator::ctor() ERROR: fixSteps>maxSteps, fixSteps set to maxSteps"
364 _fixSteps = _maxSteps;
367 _useIntegrandLimits =
true;
375RooRombergIntegrator::RooRombergIntegrator(
const RooAbsFunc &function,
double xmin,
double xmax,
378 _useIntegrandLimits(false),
380 _epsAbs(config.epsAbs()),
381 _epsRel(config.epsRel())
385 _rule = (SummationRule)configSet.
getCatIndex(
"sumRule", Trapezoid);
391 _xmin.push_back(
xmin);
392 _xmax.push_back(
xmax);
399bool RooRombergIntegrator::initialize()
402 if (_maxSteps <= 0) {
403 _maxSteps = (_rule == Trapezoid) ? 20 : 14;
413 oocoutE(
nullptr, Integration) <<
"RooRombergIntegrator::initialize: cannot integrate invalid function"
419 _x.resize(_function->getDimension());
422 _wksp.resize(_nDim * 2 * _maxSteps + 4);
424 return checkLimits();
432bool RooRombergIntegrator::setLimits(
double *
xmin,
double *
xmax)
434 if (_useIntegrandLimits) {
435 oocoutE(
nullptr, Integration) <<
"RooRombergIntegrator::setLimits: cannot override integrand's limits"
441 for (
int iDim = 0; iDim < _nDim; ++iDim) {
442 _xmin[iDim] =
xmin[iDim];
443 _xmax[iDim] =
xmax[iDim];
445 return checkLimits();
452bool RooRombergIntegrator::checkLimits()
const
454 if (_useIntegrandLimits) {
455 assert(
nullptr != integrand() && integrand()->isValid());
456 const_cast<std::vector<double> &
>(_xmin).resize(_nDim);
457 const_cast<std::vector<double> &
>(_xmax).resize(_nDim);
458 for (
int iDim = 0; iDim < _nDim; ++iDim) {
459 const_cast<double &
>(_xmin[iDim]) = integrand()->getMinLimit(iDim);
460 const_cast<double &
>(_xmax[iDim]) = integrand()->getMaxLimit(iDim);
463 for (
int iDim = 0; iDim < _nDim; ++iDim) {
464 const double xmin = _xmin[iDim];
465 const double xmax = _xmax[iDim];
468 oocoutE(
nullptr, Integration) <<
"RooRombergIntegrator::checkLimits: bad range with min > max (_xmin[" << iDim
469 <<
"] = " <<
xmin <<
" _xmax[" << iDim <<
"] = " <<
xmax <<
")" << std::endl;
479double RooRombergIntegrator::integral(
const double *yvec)
483 for (
unsigned int i = 0; i < _function->getDimension() - 1; i++) {
484 _x[i + _nDim] = yvec[i];
488 return integral(_nDim - 1, _nSeg, _wksp);
494double RooRombergIntegrator::integral(
int iDim,
int nSeg, std::span<double> wksp)
498 const double xmin = _xmin[iDim];
499 const double xmax = _xmax[iDim];
507 const double segSize = (
xmax -
xmin) / nSeg;
509 for (
int iSeg = 0; iSeg < nSeg; iSeg++) {
510 _xmin[iDim] =
xmin + iSeg * segSize;
511 _xmax[iDim] =
xmin + (iSeg + 1) * segSize;
512 double part = integral(iDim, 1, wksp);
524 std::size_t nWorkingArr = _maxSteps + 2;
525 double *hArr = wksp.data();
526 double *sArr = wksp.data() + nWorkingArr;
531 std::span<double> nextWksp{wksp.data() + 2 * _maxSteps + 4, wksp.data() + wksp.size()};
533 auto func = [&](
double x) {
536 return iDim == 0 ? integrand(_x.data()) : integral(iDim - 1, _nSeg, nextWksp);
539 std::tie(output, steps) =
540 RooFit::Detail::integrate1d(func, _rule == Trapezoid, _maxSteps, _minStepsZero, _fixSteps, _epsAbs, _epsRel,
541 _doExtrap,
xmin,
xmax, {hArr, nWorkingArr}, {sArr, nWorkingArr});
543 if (steps == _maxSteps) {
545 oocoutW(
nullptr, Integration) <<
"RooRombergIntegrator::integral: integral of " << _function->getName()
546 <<
" over range (" <<
xmin <<
"," <<
xmax <<
") did not converge after "
547 << _maxSteps <<
" steps" << std::endl;
548 for (
int j = 1; j <= _maxSteps; ++j) {
549 ooccoutW(
nullptr, Integration) <<
" [" << j <<
"] h = " << hArr[j] <<
" , s = " << sArr[j] << std::endl;
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...
Abstract interface for integrators of real-valued functions that implement the RooAbsFunc interface.
RooArgSet is a container object that can hold multiple RooAbsArg objects.
Object to represent discrete states.
bool setLabel(const char *label, bool printError=true) override
Set value by specifying the name of the desired state.
Holds the configuration parameters of the various numeric integrators used by RooRealIntegral.
const RooArgSet & getConfigSection(const char *name) const
Retrieve configuration information specific to integrator with given name.
static RooNumIntConfig & defaultConfig()
Return reference to instance of default numeric integrator configuration object.
Factory to instantiate numeric integrators from a given function binding and a given configuration.
bool registerPlugin(std::string const &name, Creator const &creator, const RooArgSet &defConfig, bool canIntegrate1D, bool canIntegrate2D, bool canIntegrateND, bool canIntegrateOpenEnded, 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.
Variable that can be changed from the outside.
void function(const Char_t *name_, T fun, const Char_t *docstring=0)
The namespace RooFit contains mostly switches that change the behaviour of functions of PDFs (or othe...
static uint64_t sum(uint64_t i)