Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RooExpPoly.cxx
Go to the documentation of this file.
1/*
2 * Project: RooFit
3 *
4 * Copyright (c) 2022, CERN
5 *
6 * Redistribution and use in source and binary forms,
7 * with or without modification, are permitted according to the terms
8 * listed in LICENSE (http://roofit.sourceforge.net/license.txt)
9 */
10
11/** \class RooExpPoly
12 \ingroup Roofit
13
14RooExpPoly implements a polynomial PDF of the form \f[ f(x) =
15\mathcal{N} \cdot \exp( \sum_{i} a_{i} * x^{i} ) \f] \f$ \mathcal{N}
16\f$ is a normalisation constant that is automatically calculated when
17the function is used in computations.
18
19The sum can be truncated at the low end. See the main constructor
20RooExpPoly::RooExpPoly(const char*, const char*, RooAbsReal&, const RooArgList&, int)
21
22\image html RooExpPoly.png
23
24**/
25
26#include <RooExpPoly.h>
27
28#include <RooAbsReal.h>
29#include <RooArgList.h>
30#include <RooMath.h>
31#include <RooMsgService.h>
32#include <RooRealVar.h>
33#include "RooBatchCompute.h"
34
35#include <TMath.h>
36#include <TError.h>
37
38#include <cmath>
39#include <sstream>
40#include <cassert>
41#include <complex>
42
44
45////////////////////////////////////////////////////////////////////////////////
46/// Create a polynomial in the variable `x`.
47/// \param[in] name Name of the PDF
48/// \param[in] title Title for plotting the PDF
49/// \param[in] x The variable of the polynomial
50/// \param[in] coefList The coefficients \f$ a_i \f$
51/// \param[in] lowestOrder [optional] Truncate the sum such that it skips the lower orders:
52/// \f[
53/// 1. + \sum_{i=0}^{\mathrm{coefList.size()}} a_{i} * x^{(i + \mathrm{lowestOrder})}
54/// \f]
55///
56/// This means that
57/// \code{.cpp}
58/// RooExpPoly pol("pol", "pol", x, RooArgList(a, b), lowestOrder = 2)
59/// \endcode
60/// computes
61/// \f[
62/// \mathrm{pol}(x) = 1 * x^0 + (0 * x^{\ldots}) + a * x^2 + b * x^3.
63/// \f]
64
65RooExpPoly::RooExpPoly(const char *name, const char *title, RooAbsReal &x, const RooArgList &coefList, int lowestOrder)
66 : RooAbsPdf(name, title),
67 _x("x", "Dependent", this, x),
68 _coefList("coefList", "List of coefficients", this),
69 _lowestOrder(lowestOrder)
70{
71 // Check lowest order
72 if (_lowestOrder < 0) {
73 coutE(InputArguments) << "RooExpPoly::ctor(" << GetName()
74 << ") WARNING: lowestOrder must be >=0, setting value to 0" << std::endl;
75 _lowestOrder = 0;
76 }
77
78 for (auto coef : coefList) {
79 if (!dynamic_cast<RooAbsReal *>(coef)) {
80 coutE(InputArguments) << "RooExpPoly::ctor(" << GetName() << ") ERROR: coefficient " << coef->GetName()
81 << " is not of type RooAbsReal" << std::endl;
82 R__ASSERT(0);
83 }
84 _coefList.add(*coef);
85 }
86}
87
88////////////////////////////////////////////////////////////////////////////////
89/// Copy constructor
90
91RooExpPoly::RooExpPoly(const RooExpPoly &other, const char *name)
92 : RooAbsPdf(other, name),
93 _x("x", this, other._x),
94 _coefList("coefList", this, other._coefList),
95 _lowestOrder(other._lowestOrder)
96{
97}
98
99////////////////////////////////////////////////////////////////////////////////
100
102{
103 // Calculate and return value of polynomial
104
105 const unsigned sz = _coefList.size();
106 const int lowestOrder = _lowestOrder;
107 if (!sz)
108 return lowestOrder ? 1. : 0.;
109 std::vector<double> coefs;
110 coefs.reserve(sz);
111
112 const RooArgSet *nset = _coefList.nset();
113 for (auto coef : _coefList) {
114 coefs.push_back(static_cast<RooAbsReal *>(coef)->getVal(nset));
115 };
116 const double x = _x;
117 double xpow = std::pow(x, lowestOrder);
118 double retval = 0;
119 for (size_t i = 0; i < sz; ++i) {
120 retval += coefs[i] * xpow;
121 xpow *= x;
122 }
123
124 if (std::numeric_limits<double>::max_exponent < retval) {
125 coutE(InputArguments) << "RooExpPoly::evaluateLog(" << GetName() << ") ERROR: exponent at " << x
126 << " larger than allowed maximum, result will be infinite! " << retval << " > "
127 << std::numeric_limits<double>::max_exponent << " in " << this->getFormulaExpression(true)
128 << std::endl;
129 }
130 return retval;
131}
132
133////////////////////////////////////////////////////////////////////////////////
134
135/// Compute multiple values of ExpPoly distribution.
136void RooExpPoly::computeBatch(double *output, size_t nEvents, RooFit::Detail::DataMap const &dataMap) const
137{
139 vars.reserve(_coefList.size() + 1);
140 vars.push_back(dataMap.at(_x));
141
142 std::vector<double> coefVals;
143 for (RooAbsArg *coef : _coefList) {
144 vars.push_back(dataMap.at(coef));
145 }
146
148 args.push_back(_lowestOrder);
149 args.push_back(_coefList.size());
150
151 RooBatchCompute::compute(dataMap.config(this), RooBatchCompute::ExpPoly, output, nEvents, vars, args);
152}
153
154////////////////////////////////////////////////////////////////////////////////
155
157{
158 // Adjust the limits of all the coefficients to reflect the numeric boundaries
159
160 const unsigned sz = _coefList.size();
161 double max = std::numeric_limits<double>::max_exponent / sz;
162 const int lowestOrder = _lowestOrder;
163 std::vector<double> coefs;
164 coefs.reserve(sz);
165
166 RooRealVar *x = dynamic_cast<RooRealVar *>(&(*_x));
167 if (x) {
168 const double xmax = x->getMax();
169 double xmaxpow = std::pow(xmax, lowestOrder);
170 for (size_t i = 0; i < sz; ++i) {
171 double thismax = max / xmaxpow;
172 RooRealVar *coef = dynamic_cast<RooRealVar *>(this->_coefList.at(i));
173 if (coef) {
174 coef->setVal(thismax);
175 coef->setMax(thismax);
176 }
177 xmaxpow *= xmax;
178 }
179 }
180}
181
182////////////////////////////////////////////////////////////////////////////////
183
185{
186 // Calculate and return value of function
187
188 const double logval = this->evaluateLog();
189 const double val = std::exp(logval);
190 if (std::isinf(val)) {
191 coutE(InputArguments) << "RooExpPoly::evaluate(" << GetName()
192 << ") ERROR: result of exponentiation is infinite! exponent was " << logval << std::endl;
193 }
194 return val;
195}
196
197////////////////////////////////////////////////////////////////////////////////
198
199double RooExpPoly::getLogVal(const RooArgSet *nset) const
200{
201 return RooAbsPdf::getLogVal(nset);
202 // return this->evaluateLog();
203}
204
205////////////////////////////////////////////////////////////////////////////////
206
207int RooExpPoly::getAnalyticalIntegral(RooArgSet &allVars, RooArgSet &analVars, const char * /*rangeName*/) const
208{
209
210 if ((_coefList.size() + _lowestOrder < 4) &&
211 ((_coefList.size() + _lowestOrder < 3) ||
212 (static_cast<RooAbsReal *>(_coefList.at(2 - _lowestOrder))->getVal() <= 0)) &&
213 matchArgs(allVars, analVars, _x)) {
214 return 0;
215 }
216 return 0;
217}
218
219////////////////////////////////////////////////////////////////////////////////
220
221#define PI TMath::Pi()
222
223namespace {
224double deltaerf(long double x1, long double x2)
225{
226 // several things happening here
227 // 1. use "erf(x) = -erf(-x)" to evaluate the function only ever for the positive side (higher precision)
228 // 2. use "erf(x) = 1.-erfc(x)" and, instead of "erf(x1) - erf(x2)", do "(1.-erfc(x1)) - (1.-erfc(x2)) = erfc(x2) -
229 // erfc(x1)"
230 double y2 = x1 > 0 ? erfc(x1) : -erfc(-x1);
231 double y1 = x2 > 0 ? erfc(x2) : -erfc(-x2);
232 if (y1 == y2) {
233 std::cout << "WARNING in calculation of analytical integral limited by numerical precision" << std::endl;
234 std::cout << "x: " << x1 << " , " << x2 << std::endl;
235 std::cout << "y: " << y1 << " , " << y2 << std::endl;
236 }
237 return y1 - y2;
238}
239
240double deltaerfi(double x1, double x2)
241{
242 std::complex<double> u1 = {x1, 0.};
243 std::complex<double> u2 = {x2, 0.};
244
245 std::complex<double> y2 = x2 > 0 ? RooMath::faddeeva(u2) : RooMath::faddeeva(-u2);
246 std::complex<double> y1 = x1 > 0 ? RooMath::faddeeva(u1) : RooMath::faddeeva(-u1);
247 if (y1 == y2) {
248 std::cout << "WARNING in calculation of analytical integral limited by numerical precision" << std::endl;
249 std::cout << "x: " << x1 << " , " << x2 << std::endl;
250 std::cout << "y: " << y1 << " , " << y2 << std::endl;
251 }
252 return y1.imag() - y2.imag();
253}
254} // namespace
255
256double RooExpPoly::analyticalIntegral(int /*code*/, const char *rangeName) const
257{
258 const double xmin = _x.min(rangeName), xmax = _x.max(rangeName);
259 const unsigned sz = _coefList.size();
260 if (!sz)
261 return xmax - xmin;
262
263 std::vector<double> coefs;
264 coefs.reserve(sz);
265 const RooArgSet *nset = _coefList.nset();
266 for (auto c : _coefList) {
267 coefs.push_back(static_cast<RooAbsReal *>(c)->getVal(nset));
268 }
269
270 switch (_coefList.size() + _lowestOrder) {
271 case 1: return xmax - xmin;
272 case 2: {
273 const double a = coefs[1 - _lowestOrder];
274 if (a != 0) {
275 return 1. / a * (exp(a * xmax) - exp(a * xmin)) * (_lowestOrder == 0 ? exp(coefs[0]) : 1);
276 } else {
277 return xmax - xmin;
278 }
279 }
280 case 3: {
281 const double a = coefs[2 - _lowestOrder];
282 const double b = _lowestOrder == 2 ? 0. : coefs[1 - _lowestOrder];
283 const double c = _lowestOrder == 0 ? coefs[0] : 0.;
284 const double absa = std::abs(a);
285 const double sqrta = std::sqrt(absa);
286 if (a < 0) {
287 double d = ::deltaerf((-b + 2 * absa * xmax) / (2 * sqrta), (-b + 2 * absa * xmin) / (2 * sqrta));
288 double retval = exp(b * b / (4 * absa) + c) * std::sqrt(PI) * d / (2 * sqrta);
289 return retval;
290 } else if (a > 0) {
291 double d = ::deltaerfi((b + 2 * absa * xmax) / (2 * sqrta), (b + 2 * absa * xmin) / (2 * sqrta));
292 double retval = exp(-b * b / (4 * absa) + c) * std::sqrt(PI) * d / (2 * sqrta);
293 return retval;
294 } else if (b != 0) {
295 return 1. / b * (std::exp(b * xmax) - exp(b * xmin)) * exp(c);
296 } else {
297 return xmax - xmin;
298 }
299 }
300 }
301 return 0.;
302}
303
304////////////////////////////////////////////////////////////////////////////////
305
306std::string RooExpPoly::getFormulaExpression(bool expand) const
307{
308 std::stringstream ss;
309 ss << "exp(";
310 int order = _lowestOrder;
311 for (auto coef : _coefList) {
312 if (order != _lowestOrder)
313 ss << "+";
314 if (expand)
315 ss << ((RooAbsReal *)coef)->getVal();
316 else
317 ss << coef->GetName();
318 ss << "*pow(" << _x.GetName() << "," << order << ")";
319 ++order;
320 }
321 ss << ")";
322 return ss.str();
323}
#define d(i)
Definition RSha256.hxx:102
#define b(i)
Definition RSha256.hxx:100
#define c(i)
Definition RSha256.hxx:101
#define a(i)
Definition RSha256.hxx:99
#define coutE(a)
#define ClassImp(name)
Definition Rtypes.h:377
#define PI
#define R__ASSERT(e)
Definition TError.h:118
Option_t Option_t TPoint TPoint const char x2
Option_t Option_t TPoint TPoint const char x1
Option_t Option_t TPoint TPoint const char y2
Option_t Option_t TPoint TPoint const char y1
char name[80]
Definition TGX11.cxx:110
float xmin
float xmax
RooAbsArg is the common abstract base class for objects that represent a value and a "shape" in RooFi...
Definition RooAbsArg.h:80
Storage_t::size_type size() const
virtual double getLogVal(const RooArgSet *set=nullptr) const
Return the log of the current value with given normalization An error message is printed if the argum...
const RooArgSet * nset() const
Definition RooAbsProxy.h:52
RooAbsReal is the common abstract base class for objects that represent a real value and implements f...
Definition RooAbsReal.h:59
double getVal(const RooArgSet *normalisationSet=nullptr) const
Evaluate object.
Definition RooAbsReal.h:103
bool matchArgs(const RooArgSet &allDeps, RooArgSet &numDeps, const RooArgProxy &a) const
Utility function for use in getAnalyticalIntegral().
RooArgList is a container object that can hold multiple RooAbsArg objects.
Definition RooArgList.h:22
RooAbsArg * at(Int_t idx) const
Return object at given index, or nullptr if index is out of range.
Definition RooArgList.h:110
RooArgSet is a container object that can hold multiple RooAbsArg objects.
Definition RooArgSet.h:55
bool add(const RooAbsArg &var, bool valueServer, bool shapeServer, bool silent)
Overloaded RooCollection_t::add() method insert object into set and registers object as server to own...
RooExpPoly implements a polynomial PDF of the form.
Definition RooExpPoly.h:18
double evaluate() const override
Evaluation.
double evaluateLog() const
std::string getFormulaExpression(bool expand) const
int lowestOrder() const
Return the order for the first coefficient in the list.
Definition RooExpPoly.h:33
void computeBatch(double *output, size_t size, RooFit::Detail::DataMap const &) const override
Compute multiple values of ExpPoly distribution.
double analyticalIntegral(int code, const char *rangeName=nullptr) const override
Implements the actual analytical integral(s) advertised by getAnalyticalIntegral.
RooListProxy _coefList
Definition RooExpPoly.h:46
int getAnalyticalIntegral(RooArgSet &allVars, RooArgSet &analVars, const char *rangeName=nullptr) const override
Interface function getAnalyticalIntergral advertises the analytical integrals that are supported.
double getLogVal(const RooArgSet *nset) const override
Return the log of the current value with given normalization An error message is printed if the argum...
void adjustLimits()
RooRealProxy _x
Definition RooExpPoly.h:45
int _lowestOrder
Definition RooExpPoly.h:47
RooAbsReal const & x() const
Get the x variable.
Definition RooExpPoly.h:27
RooArgList const & coefList() const
Get the coefficient list.
Definition RooExpPoly.h:30
RooBatchCompute::Config config(RooAbsArg const *arg) const
Definition DataMap.cxx:40
std::span< const double > at(RooAbsArg const *arg, RooAbsArg const *caller=nullptr)
Definition DataMap.cxx:22
static std::complex< double > faddeeva(std::complex< double > z)
evaluate Faddeeva function for complex argument
Definition RooMath.cxx:30
RooRealVar represents a variable that can be changed from the outside.
Definition RooRealVar.h:37
void setVal(double value) override
Set value of variable to 'value'.
void setMax(const char *name, double value)
Set maximum of name range to given value.
double max(const char *rname=nullptr) const
Query upper limit of range. This requires the payload to be RooAbsRealLValue or derived.
double min(const char *rname=nullptr) const
Query lower limit of range. This requires the payload to be RooAbsRealLValue or derived.
const char * GetName() const override
Returns name of object.
Definition TNamed.h:47
Double_t x[n]
Definition legend1.C:17
std::vector< std::span< const double > > VarVector
std::vector< double > ArgVector
void compute(Config cfg, Computer comp, RestrictArr output, size_t size, const VarVector &vars, ArgVector &extraArgs)
static void output()