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 "RooHelpers.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/// Remove a binning previously declared with setBinning() for observable `obs`,
181/// reverting to the generic numeric integrator for it. Returns true if a binning
182/// was removed, false if none was set for `obs`.
183
185{
186 return _binnings.erase(_actualVars.index(obs.GetName())) > 0;
187}
188
189////////////////////////////////////////////////////////////////////////////////
190/// Return true if a binning was set with setBinning() for every
191/// observable in the integration set `obs`.
192
194{
195 if (obs.empty() || _binnings.empty()) {
196 return false;
197 }
198 for (RooAbsArg *o : obs) {
199 const int idx = _actualVars.index(o->GetName());
200 // Observables that are not formula variables of this pdf are ones we do
201 // not depend on: the function is constant (hence trivially binned) in
202 // them, so they must be ignored here. This matches the convention that
203 // composite functions like RooProduct rely on, where each component's
204 // isBinnedDistribution() is queried with the full observable set.
205 if (idx < 0) {
206 continue;
207 }
208 if (_binnings.find(idx) == _binnings.end()) {
209 return false;
210 }
211 }
212 return true;
213}
214
215////////////////////////////////////////////////////////////////////////////////
216/// Return the boundaries of the binning set with setBinning() that fall
217/// within [xlo, xhi], or a null pointer if no binning was set for this observable.
218
219std::list<double> *RooGenericPdf::binBoundaries(RooAbsRealLValue &obs, double xlo, double xhi) const
220{
221 auto found = _binnings.find(_actualVars.index(obs.GetName()));
222 if (found == _binnings.end()) {
223 return nullptr;
224 }
225 const RooAbsBinning &binning = *found->second;
226 return RooHelpers::binBoundariesInRange({binning.array(), static_cast<std::size_t>(binning.numBoundaries())}, xlo,
227 xhi);
228}
229
230////////////////////////////////////////////////////////////////////////////////
231/// Return sampling hints that draw the piecewise-flat shape exactly (a pair of
232/// points just left and right of every bin boundary), or a null pointer if no
233/// binning was set for this observable.
234
235std::list<double> *RooGenericPdf::plotSamplingHint(RooAbsRealLValue &obs, double xlo, double xhi) const
236{
237 auto found = _binnings.find(_actualVars.index(obs.GetName()));
238 if (found == _binnings.end()) {
239 return nullptr;
240 }
241 const RooAbsBinning &binning = *found->second;
243 {binning.array(), static_cast<std::size_t>(binning.numBoundaries())}, xlo, xhi);
244}
245
246////////////////////////////////////////////////////////////////////////////////
247/// Calculate current value of this object
248
250{
251 return formula().eval(_actualVars.nset()) ;
252}
253
254
255////////////////////////////////////////////////////////////////////////////////
257{
258 formula().doEval(_actualVars, ctx);
259}
260
261
262////////////////////////////////////////////////////////////////////////////////
263/// Propagate server changes to embedded formula object
264
270
271
272
273////////////////////////////////////////////////////////////////////////////////
274/// Print info about this object to the specified stream.
275
276void RooGenericPdf::printMultiline(ostream& os, Int_t content, bool verbose, TString indent) const
277{
279 if (verbose) {
280 os << " --- RooGenericPdf --- " << std::endl ;
281 indent.Append(" ");
282 os << indent ;
283 formula().printMultiline(os,content,verbose,indent);
284 }
285}
286
287
288
289////////////////////////////////////////////////////////////////////////////////
290/// Add formula expression as meta argument in printing interface
291
292void RooGenericPdf::printMetaArgs(ostream& os) const
293{
294 os << "formula=\"" << _formExpr << "\" " ;
295}
296
297
298void RooGenericPdf::dumpFormula() { formula().printMultiline(std::cout, 0) ; }
299
300
301////////////////////////////////////////////////////////////////////////////////
302/// Read object contents from given stream
303
304bool RooGenericPdf::readFromStream(istream& /*is*/, bool /*compact*/, bool /*verbose*/)
305{
306 coutE(InputArguments) << "RooGenericPdf::readFromStream(" << GetName() << "): can't read" << std::endl;
307 return true;
308}
309
310
311////////////////////////////////////////////////////////////////////////////////
312/// Write object contents to given stream
313
314void RooGenericPdf::writeToStream(ostream& os, bool compact) const
315{
316 if (compact) {
317 os << getVal() << std::endl ;
318 } else {
319 os << GetTitle() ;
320 }
321}
322
324{
325 return formula().getTFormula()->GetUniqueFuncName().Data();
326}
#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:148
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:539
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
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:386
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...
std::list< double > * binBoundariesInRange(std::span< const double > boundaries, double xlo, double xhi)
Return a newly allocated list with the subset of boundaries that lies strictly inside [xlo,...