Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RooGenericPdf.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 RooGenericPdf.cxx
19\class RooGenericPdf
20\ingroup Roofitcore
21
22Implementation of a probability density function
23that takes a RooArgList of servers and a C++ expression string defining how
24its value should be calculated from the given list of servers.
25A fully numerical integration is automatically performed to normalize the given
26expression. RooGenericPdf uses a RooFormula object to perform the expression evaluation.
27
28The string expression can be any valid TFormula expression referring to the
29listed servers either by name or by their ordinal list position. These three are
30equivalent:
31```
32 RooFormulaVar("gen", "x*y", RooArgList(x,y)) // reference by name
33 RooFormulaVar("gen", "@0*@1", RooArgList(x,y)) // reference by ordinal with @
34 RooFormulaVar("gen", "x[0]*x[1]", RooArgList(x,y)) // TFormula-builtin reference by ordinal
35```
36Note that `x[i]` is an expression reserved for TFormula. All variable references
37are automatically converted to the TFormula-native format. If a variable with
38the name `x` is given, the RooFormula interprets `x[i]` as a list position,
39but `x` without brackets as the name of a RooFit object.
40
41The last two versions, while slightly less readable, are more versatile because
42the names of the arguments are not hard coded.
43**/
44
45#include "RooGenericPdf.h"
46#include "Riostream.h"
47#include "RooStreamParser.h"
48#include "RooMsgService.h"
49#include "RooArgList.h"
50#include "RooFormula.h"
51#include "RooAbsRealLValue.h"
52#include "RooAbsBinning.h"
53#include "RooCurve.h"
54#include "RooFitImplHelpers.h"
55
56using std::istream, std::ostream, std::endl;
57
58
60
65
66
67////////////////////////////////////////////////////////////////////////////////
68/// Constructor with formula expression and list of input variables
69
70RooGenericPdf::RooGenericPdf(const char *name, const char *title, const RooArgList& dependents) :
71 RooAbsPdf(name,title),
72 _actualVars("actualVars","Variables used by PDF expression",this),
73 _formExpr(title)
74{
75 if (dependents.empty()) {
76 _value = traceEval(nullptr);
77 } else {
79 _formExpr = _formula->formulaString().c_str();
80 _actualVars.add(_formula->actualDependents());
81 }
82}
83
84
85
86////////////////////////////////////////////////////////////////////////////////
87/// Constructor with a name, title, formula expression and a list of variables
88
89RooGenericPdf::RooGenericPdf(const char *name, const char *title,
90 const char* inFormula, const RooArgList& dependents) :
91 RooAbsPdf(name,title),
92 _actualVars("actualVars","Variables used by PDF expression",this),
93 _formExpr(inFormula)
94{
95 if (dependents.empty()) {
96 _value = traceEval(nullptr);
97 } else {
99 _formExpr = _formula->formulaString().c_str();
100 _actualVars.add(_formula->actualDependents());
101 }
102}
103
104
105
106////////////////////////////////////////////////////////////////////////////////
107/// Copy constructor
108
111 _actualVars("actualVars",this,other._actualVars),
112 _formExpr(other._formExpr)
113{
114 for (auto const &item : other._binnings) {
115 _binnings[item.first] = std::unique_ptr<RooAbsBinning>{item.second->clone()};
116 }
117 formula();
118}
119
120
121////////////////////////////////////////////////////////////////////////////////
122
124{
125 if (!_formula) {
127 const_cast<TString&>(_formExpr) = _formula->formulaString().c_str();
128 }
129 return *_formula ;
130}
131
132////////////////////////////////////////////////////////////////////////////////
133/// Declare that this pdf is piecewise constant (flat) within the bins of the
134/// given `binning` of the observable `obs`, which must be one of the formula
135/// variables. The method can be called several times to set a binning for more
136/// than one observable. Use a RooUniformBinning to describe many uniform bins
137/// compactly.
138///
139/// Once set, integrals over `obs` use the fast bin integrator (which sums the
140/// central value of each bin times the bin width) instead of the generic
141/// numeric integrator, and plotting samples the step shape exactly.
142///
143/// If `checkFlatness` is true (the default), the function is sampled at several
144/// points inside each bin to verify that it is indeed flat; if it is not, an
145/// error is issued and the binning is not stored.
146
148{
149 // Match the observable to a formula variable by name, so that a same-named
150 // stand-in for the actual server is accepted too.
151 const int idx = _actualVars.index(obs.GetName());
152 if (idx < 0) {
153 coutE(InputArguments) << "RooGenericPdf::setBinning(" << GetName() << ") the observable " << obs.GetName()
154 << " is not one of the formula variables of this pdf, nothing done." << std::endl;
155 return;
156 }
157
158 if (checkFlatness) {
159 // Sample the function by varying the actual formula variable (the server),
160 // which may be a different object than `obs` if `obs` is just a same-named
161 // stand-in: the function's value depends on the server, not on `obs`.
162 if (auto *serverObs = dynamic_cast<RooAbsRealLValue *>(_actualVars.at(idx))) {
163 std::span<const double> boundaries{binning.array(), static_cast<std::size_t>(binning.numBoundaries())};
164 if (!RooHelpers::isFunctionFlatInBins(*this, *serverObs, boundaries)) {
165 coutE(InputArguments) << "RooGenericPdf::setBinning(" << GetName() << ") the expression \"" << _formExpr
166 << "\" is not flat within the given bins of " << obs.GetName()
167 << ". The binning is not set. Pass checkFlatness=false to override this check."
168 << std::endl;
169 return;
170 }
171 }
172 }
173
174 // Key the binning by the observable's index in _actualVars (not its name), so
175 // that it survives a renaming of the variable or a server redirection.
176 _binnings[idx] = std::unique_ptr<RooAbsBinning>{binning.clone()};
177}
178
179////////////////////////////////////////////////////////////////////////////////
180/// Return the binning previously declared with setBinning() for observable
181/// `obs`, or nullptr if no binning was declared. The observable is matched to a
182/// formula variable by name, consistently with setBinning().
183
185{
186 auto found = _binnings.find(_actualVars.index(obs.GetName()));
187 return found != _binnings.end() ? found->second.get() : nullptr;
188}
189
190////////////////////////////////////////////////////////////////////////////////
191/// Remove a binning previously declared with setBinning() for observable `obs`,
192/// reverting to the generic numeric integrator for it. Returns true if a binning
193/// was removed, false if none was set for `obs`.
194
196{
197 return _binnings.erase(_actualVars.index(obs.GetName())) > 0;
198}
199
200////////////////////////////////////////////////////////////////////////////////
201/// Return true if a binning was set with setBinning() for every
202/// observable in the integration set `obs`.
203
205{
206 if (obs.empty() || _binnings.empty()) {
207 return false;
208 }
209 for (RooAbsArg *o : obs) {
210 const int idx = _actualVars.index(o->GetName());
211 // Observables that are not formula variables of this pdf are ones we do
212 // not depend on: the function is constant (hence trivially binned) in
213 // them, so they must be ignored here. This matches the convention that
214 // composite functions like RooProduct rely on, where each component's
215 // isBinnedDistribution() is queried with the full observable set.
216 if (idx < 0) {
217 continue;
218 }
219 if (_binnings.find(idx) == _binnings.end()) {
220 return false;
221 }
222 }
223 return true;
224}
225
226////////////////////////////////////////////////////////////////////////////////
227/// Return the boundaries of the binning set with setBinning() that fall
228/// within [xlo, xhi], or a null pointer if no binning was set for this observable.
229
230std::list<double> *RooGenericPdf::binBoundaries(RooAbsRealLValue &obs, double xlo, double xhi) const
231{
232 auto found = _binnings.find(_actualVars.index(obs.GetName()));
233 if (found == _binnings.end()) {
234 return nullptr;
235 }
236 const RooAbsBinning &binning = *found->second;
237 auto hint = new std::list<double>;
238 for (int i = 0; i < binning.numBoundaries(); ++i) {
239 const double boundary = binning.array()[i];
240 if (boundary >= xlo && boundary <= xhi) {
241 hint->push_back(boundary);
242 }
243 }
244 return hint;
245}
246
247////////////////////////////////////////////////////////////////////////////////
248/// Return sampling hints that draw the piecewise-flat shape exactly (a pair of
249/// points just left and right of every bin boundary), or a null pointer if no
250/// binning was set for this observable.
251
252std::list<double> *RooGenericPdf::plotSamplingHint(RooAbsRealLValue &obs, double xlo, double xhi) const
253{
254 const RooAbsBinning *binning = getBinning(obs);
255 if (!binning) {
256 return nullptr;
257 }
259 {binning->array(), static_cast<std::size_t>(binning->numBoundaries())}, xlo, xhi);
260}
261
262////////////////////////////////////////////////////////////////////////////////
263/// Calculate current value of this object
264
266{
267 return formula().eval(_actualVars.nset()) ;
268}
269
270
271////////////////////////////////////////////////////////////////////////////////
273{
274 formula().doEval(_actualVars, ctx);
275}
276
277
278////////////////////////////////////////////////////////////////////////////////
279/// Propagate server changes to embedded formula object
280
286
287
288
289////////////////////////////////////////////////////////////////////////////////
290/// Print info about this object to the specified stream.
291
292void RooGenericPdf::printMultiline(ostream& os, Int_t content, bool verbose, TString indent) const
293{
295 if (verbose) {
296 os << " --- RooGenericPdf --- " << std::endl ;
297 indent.Append(" ");
298 os << indent ;
299 formula().printMultiline(os,content,verbose,indent);
300 }
301}
302
303
304
305////////////////////////////////////////////////////////////////////////////////
306/// Add formula expression as meta argument in printing interface
307
308void RooGenericPdf::printMetaArgs(ostream& os) const
309{
310 os << "formula=\"" << _formExpr << "\" " ;
311}
312
313
314void RooGenericPdf::dumpFormula() { formula().printMultiline(std::cout, 0) ; }
315
316
317////////////////////////////////////////////////////////////////////////////////
318/// Read object contents from given stream
319
320bool RooGenericPdf::readFromStream(istream& /*is*/, bool /*compact*/, bool /*verbose*/)
321{
322 coutE(InputArguments) << "RooGenericPdf::readFromStream(" << GetName() << "): can't read" << std::endl;
323 return true;
324}
325
326
327////////////////////////////////////////////////////////////////////////////////
328/// Write object contents to given stream
329
330void RooGenericPdf::writeToStream(ostream& os, bool compact) const
331{
332 if (compact) {
333 os << getVal() << std::endl ;
334 } else {
335 os << GetTitle() ;
336 }
337}
338
340{
341 return formula().getTFormula()->GetUniqueFuncName().Data();
342}
#define coutE(a)
static void indent(ostringstream &buf, int indent_level)
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
char name[80]
Definition TGX11.cxx:145
Common abstract base class for objects that represent a value and a "shape" in RooFit.
Definition RooAbsArg.h:76
Abstract base class for RooRealVar binning definitions.
virtual Int_t numBoundaries() const =0
virtual double * array() const =0
virtual RooAbsBinning * clone(const char *name=nullptr) const =0
Abstract container object that can hold multiple RooAbsArg objects.
Int_t index(const RooAbsArg *arg) const
Returns index of given arg, or -1 if arg is not in the collection.
Abstract interface for all probability density functions.
Definition RooAbsPdf.h:32
void printMultiline(std::ostream &os, Int_t contents, bool verbose=false, TString indent="") const override
Print multi line detailed information of this RooAbsPdf.
bool redirectServersHook(const RooAbsCollection &newServerList, bool mustReplaceAll, bool nameChange, bool isRecursiveStep) override
Hook function intercepting redirectServer calls.
const RooArgSet * nset() const
Definition RooAbsProxy.h:52
Abstract base class for objects that represent a real value that may appear on the left hand side of ...
double getVal(const RooArgSet *normalisationSet=nullptr) const
Evaluate object.
Definition RooAbsReal.h:107
double _value
Cache for current value of object.
Definition RooAbsReal.h:566
double traceEval(const RooArgSet *set) const
Calculate current value of object, with error tracing wrapper.
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:24
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...
static std::list< double > * plotSamplingHintForBinBoundaries(std::span< const double > boundaries, double xlo, double xhi)
Returns sampling hints for a histogram with given boundaries.
Definition RooCurve.cxx:897
Implementation of a probability density function that takes a RooArgList of servers and a C++ express...
double evaluate() const override
Calculate current value of this object.
~RooGenericPdf() override
const RooAbsBinning * getBinning(const RooAbsRealLValue &obs) const
Return the binning previously declared with setBinning() for observable obs, or nullptr if no binning...
bool readFromStream(std::istream &is, bool compact, bool verbose=false) override
Read object contents from given stream.
const RooArgList & dependents() const
void printMetaArgs(std::ostream &os) const override
Add formula expression as meta argument in printing interface.
bool isBinnedDistribution(const RooArgSet &obs) const override
Return true if a binning was set with setBinning() for every observable in the integration set obs.
std::string getUniqueFuncName() const
RooListProxy _actualVars
void writeToStream(std::ostream &os, bool compact) const override
Write object contents to given stream.
std::map< int, std::unique_ptr< RooAbsBinning > > _binnings
User-defined binnings, keyed by the observable's index in _actualVars, for a piecewise-flat distribut...
std::list< double > * plotSamplingHint(RooAbsRealLValue &obs, double xlo, double xhi) const override
Return sampling hints that draw the piecewise-flat shape exactly (a pair of points just left and righ...
std::list< double > * binBoundaries(RooAbsRealLValue &obs, double xlo, double xhi) const override
Return the boundaries of the binning set with setBinning() that fall within [xlo, xhi],...
RooFormula * _formula
! Formula engine
bool removeBinning(const RooAbsRealLValue &obs)
Remove a binning previously declared with setBinning() for observable obs, reverting to the generic n...
RooFormula & formula() const
TString _formExpr
Formula expression string.
void doEval(RooFit::EvalContext &) const override
Base function for computing multiple values of a RooAbsReal.
void printMultiline(std::ostream &os, Int_t content, bool verbose=false, TString indent="") const override
Print info about this object to the specified stream.
void setBinning(const RooAbsRealLValue &obs, const RooAbsBinning &binning, bool checkFlatness=true)
Declare that this pdf is piecewise constant (flat) within the bins of the given binning of the observ...
bool redirectServersHook(const RooAbsCollection &newServerList, bool mustReplaceAll, bool nameChange, bool isRecursive) override
Propagate server changes to embedded formula object.
const char * GetName() const override
Returns name of object.
Definition TNamed.h:49
const char * GetTitle() const override
Returns title of object.
Definition TNamed.h:50
Basic string class.
Definition TString.h:138
const char * Data() const
Definition TString.h:384
bool isFunctionFlatInBins(const RooAbsReal &function, RooAbsRealLValue &obs, std::span< const double > boundaries, double relTol=1e-9)
Check that function is constant (flat) inside each bin defined by the sorted boundaries when scanning...