Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RooFormulaVar.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/// \class RooFormulaVar
19///
20/// A RooFormulaVar is a generic implementation of a real-valued object,
21/// which takes a RooArgList of servers and a C++ expression string defining how
22/// its value should be calculated from the given list of servers.
23///
24/// If RooAbsPdf objects are supplied to RooFormulaVar as servers, their
25/// raw (unnormalized) values will be evaluated. Use RooGenericPdf, which
26/// constructs generic PDF functions, to access their properly normalized
27/// values.
28///
29/// The string expression can be any valid TFormula expression referring to the
30/// listed servers either by name or by their ordinal list position. These three are
31/// equivalent:
32/// ```
33/// RooFormulaVar("gen", "x*y", RooArgList(x,y)) // reference by name
34/// RooFormulaVar("gen", "@0*@1", RooArgList(x,y)) // reference by ordinal with @
35/// RooFormulaVar("gen", "x[0]*x[1]", RooArgList(x,y)) // TFormula-builtin reference by ordinal
36/// ```
37/// Note that `x[i]` is an expression reserved for TFormula. All variable references
38/// are automatically converted to the TFormula-native format. If a variable with
39/// the name `x` is given, `x[i]` is interpreted as a list position,
40/// but `x` without brackets as the name of a RooFit object.
41///
42/// The last two versions, while slightly less readable, are more versatile because
43/// the names of the arguments are not hard coded.
44///
45
46#include "RooFormulaVar.h"
47#include "RooStreamParser.h"
48#include "RooMsgService.h"
49#include "RooFormulaUtils.h"
50#include "RooAbsRealLValue.h"
52
53#include "TFormula.h"
54
55
56#include <iostream>
57#include <list>
58
59using std::ostream, std::istream, std::list;
60
61
63
65
66////////////////////////////////////////////////////////////////////////////////
67/// Constructor with formula expression and list of input variables.
68/// \param[in] name Name of the formula.
69/// \param[in] title Title of the formula.
70/// \param[in] inFormula Expression to be evaluated.
71/// \param[in] dependents Variables that should be passed to the formula.
72/// \param[in] checkVariables Unused parameter.
73RooFormulaVar::RooFormulaVar(const char *name, const char *title, const char* inFormula, const RooArgList& dependents,
74 bool /*checkVariables*/) :
75 RooAbsReal(name,title),
76 _actualVars("actualVars","Variables used by formula expression",this),
77 _formExpr(inFormula)
78{
79 if (dependents.empty()) {
80 _value = traceEval(nullptr);
81 } else {
82 RooFormulaUtils::initFormula(_evaluator, _formExpr, _actualVars, dependents, GetName());
83 }
84}
85
86
87
88////////////////////////////////////////////////////////////////////////////////
89/// Constructor with formula expression, title and list of input variables.
90/// \param[in] name Name of the formula.
91/// \param[in] title Formula expression. Will also be used as the title.
92/// \param[in] dependents Variables that should be passed to the formula.
93/// \param[in] checkVariables Check that all variables from `dependents` are used in the expression.
94RooFormulaVar::RooFormulaVar(const char *name, const char *title, const RooArgList &dependents, bool checkVariables)
95 : RooFormulaVar(name, title, title, dependents, checkVariables)
96{
97}
98
99////////////////////////////////////////////////////////////////////////////////
100/// Copy constructor
101
103 RooAbsReal(other, name),
104 _actualVars("actualVars",this,other._actualVars),
105 _formExpr(other._formExpr)
106{
107 _binnings = RooFormulaUtils::cloneBinnings(other._binnings);
108 if (other._evaluator) {
109 _evaluator = RooFormulaUtils::cloneEvaluator(*other._evaluator, GetName());
110 }
111}
112
113////////////////////////////////////////////////////////////////////////////////
114/// Return reference to the formula evaluation engine.
115/// If it doesn't exist, create it on the fly. Throws if the formula is invalid.
116RooFormulaEvaluator &RooFormulaVar::evaluator() const
117{
118 return RooFormulaUtils::ensureEvaluator(_evaluator, const_cast<TString &>(_formExpr), _actualVars, GetName());
119}
120
122{
123 evaluator();
124 return true;
125}
126
128{
129 RooFormulaUtils::printFormula(std::cout, "", _formExpr.Data(), _actualVars);
130}
131
132////////////////////////////////////////////////////////////////////////////////
133/// Calculate current value of object from internal formula
134
136{
137 return RooFormulaUtils::evalFormula(evaluator(), _actualVars, _actualVars.nset());
138}
139
140
142{
143 RooFormulaUtils::doEvalFormula(evaluator(), _actualVars, ctx);
144}
145
146////////////////////////////////////////////////////////////////////////////////
147/// Print info about this object to the specified stream.
148
149void RooFormulaVar::printMultiline(ostream& os, Int_t contents, bool verbose, TString indent) const
150{
151 RooAbsReal::printMultiline(os,contents,verbose,indent);
152 if(verbose) {
153 indent.Append(" ");
154 os << indent;
155 RooFormulaUtils::printFormula(os, indent, _formExpr.Data(), _actualVars);
156 }
157}
158
159
160
161////////////////////////////////////////////////////////////////////////////////
162/// Add formula expression as meta argument in printing interface
163
164void RooFormulaVar::printMetaArgs(ostream& os) const
165{
166 os << "formula=\"" << _formExpr << "\" " ;
167}
168
169
170
171
172////////////////////////////////////////////////////////////////////////////////
173/// Read object contents from given stream
174
175bool RooFormulaVar::readFromStream(istream& /*is*/, bool /*compact*/, bool /*verbose*/)
176{
177 coutE(InputArguments) << "RooFormulaVar::readFromStream(" << GetName() << "): can't read" << std::endl ;
178 return true ;
179}
180
181
182
183////////////////////////////////////////////////////////////////////////////////
184/// Write object contents to given stream
185
186void RooFormulaVar::writeToStream(ostream& os, bool compact) const
187{
188 if (compact) {
189 std::cout << getVal() << std::endl ;
190 } else {
191 os << GetTitle() ;
192 }
193}
194
195////////////////////////////////////////////////////////////////////////////////
196/// Declare that this function is piecewise constant (flat) within the bins of
197/// the given `binning` of the observable `obs`, which must be one of the formula
198/// variables. The method can be called several times to set a binning for more
199/// than one observable. See RooGenericPdf::setBinning() for details.
200
201void RooFormulaVar::setBinning(const RooAbsRealLValue &obs, const RooAbsBinning &binning, bool checkFlatness)
202{
203 RooFormulaUtils::setBinning(_binnings, *this, _actualVars, _formExpr.Data(), obs, binning, checkFlatness);
204}
205
206////////////////////////////////////////////////////////////////////////////////
207/// Return the binning previously declared with setBinning() for observable
208/// `obs`, or nullptr if no binning was declared. This reports only binnings
209/// owned by this formula, not binning hints forwarded by its servers.
210
212{
213 return RooFormulaUtils::getBinning(_binnings, _actualVars, obs);
214}
215
216////////////////////////////////////////////////////////////////////////////////
217/// Remove a binning previously declared with setBinning() for observable `obs`,
218/// reverting to the generic numeric integrator for it. Returns true if a binning
219/// was removed, false if none was set for `obs`.
220
222{
223 return _binnings.erase(_actualVars.index(obs.GetName())) > 0;
224}
225
226////////////////////////////////////////////////////////////////////////////////
227/// Return true if a binning was set with setBinning() for every
228/// observable in the integration set `obs`.
229
231{
232 return RooFormulaUtils::isBinnedDistribution(_binnings, _actualVars, obs);
233}
234
235////////////////////////////////////////////////////////////////////////////////
236/// Return the boundaries of the binning set with setBinning() that fall
237/// within [xlo, xhi]. If no binning was set for this observable, forward the bin
238/// boundaries from the server that defines the observable obs.
239
240std::list<double>* RooFormulaVar::binBoundaries(RooAbsRealLValue& obs, double xlo, double xhi) const
241{
242 if (auto *hint = RooFormulaUtils::binBoundaries(_binnings, _actualVars, obs, xlo, xhi)) {
243 return hint;
244 }
245
246 for (const auto par : _actualVars) {
247 auto func = static_cast<const RooAbsReal*>(par);
248 list<double>* binb = nullptr;
249
250 if (func && (binb = func->binBoundaries(obs,xlo,xhi)) ) {
251 return binb;
252 }
253 }
254
255 return nullptr;
256}
257
258////////////////////////////////////////////////////////////////////////////////
259/// Return sampling hints that draw the piecewise-flat shape exactly if a binning
260/// was set for this observable. Otherwise, forward the plot sampling hint from
261/// the server that defines the observable obs.
262
263std::list<double>* RooFormulaVar::plotSamplingHint(RooAbsRealLValue& obs, double xlo, double xhi) const
264{
265 if (auto *hint = RooFormulaUtils::plotSamplingHint(_binnings, _actualVars, obs, xlo, xhi)) {
266 return hint;
267 }
268
269 for (const auto par : _actualVars) {
270 auto func = dynamic_cast<const RooAbsReal*>(par);
271 list<double>* hint = nullptr;
272
273 if (func && (hint = func->plotSamplingHint(obs,xlo,xhi)) ) {
274 return hint;
275 }
276 }
277
278 return nullptr;
279}
280
281
282
283////////////////////////////////////////////////////////////////////////////////
284/// Return the default error level for MINUIT error analysis.
285/// If the formula contains a test statistic implemented by RooNLLVarNew,
286/// return its defaultErrorLevel(). Otherwise, issue a warning message and
287/// return a value of 1.
288
290{
291 RooAbsReal* nllArg(nullptr) ;
292
293 std::unique_ptr<RooArgSet> comps{getComponents()};
294 for(RooAbsArg * arg : *comps) {
295 if (dynamic_cast<RooFit::Detail::RooNLLVarNew*>(arg)) {
296 nllArg = static_cast<RooAbsReal*>(arg) ;
297 }
298 }
299
300 if (nllArg) {
301 coutI(Minimization) << "RooFormulaVar::defaultErrorLevel(" << GetName()
302 << ") Formula contains a test statistic, using its error level" << std::endl ;
303 return nllArg->defaultErrorLevel() ;
304 }
305
306 coutI(Minimization) << "RooFormulaVar::defaultErrorLevel(" << GetName() << ") WARNING: "
307 << "Formula contains no test statistic server, using default level of 1.0" << std::endl ;
308
309 return 1.0 ;
310}
311
313{
314 return evaluator().getTFormula()->GetUniqueFuncName().Data();
315}
316
317std::unique_ptr<RooAbsArg>
319{
320 // Some users exploit unnormalized RooAbsPdfs as inputs for RooFormulaVars,
321 // relying on what the pdf returns from RooAbsPdf::evaluate(). This is in
322 // principle not allowed because every pdf needs to be evaluated with a
323 // normalization set, but it's so common in user code that we need to
324 // support it. To make this work, we need to make sure that the no
325 // normalization over non-dependents is happening at this point, reducing
326 // the normalization set to the subset of actual dependents.
327 // See also the "PdfAsFunctionInFormulaVar" test in testRooAbsPdf.
328 RooArgSet depList;
329 getObservables(&normSet, depList);
330 auto newArg = std::unique_ptr<RooAbsArg>{static_cast<RooAbsArg *>(Clone())};
331 ctx.markAsCompiled(*newArg);
332 ctx.compileServers(*newArg, depList);
333 return newArg;
334}
#define coutI(a)
#define coutE(a)
static void indent(ostringstream &buf, int indent_level)
char name[80]
Definition TGX11.cxx:142
Common abstract base class for objects that represent a value and a "shape" in RooFit.
Definition RooAbsArg.h:77
RooFit::OwningPtr< RooArgSet > getObservables(const RooArgSet &set, bool valueOnly=true) const
Given a set of possible observables, return the observables that this PDF depends on.
RooFit::OwningPtr< RooArgSet > getComponents() const
Create a RooArgSet with all components (branch nodes) of the expression tree headed by this object.
TObject * Clone(const char *newname=nullptr) const override
Make a clone of an object using the Streamer facility.
Definition RooAbsArg.h:89
Abstract base class for RooRealVar binning definitions.
Int_t index(const RooAbsArg *arg) const
Returns index of given arg, or -1 if arg is not in the collection.
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 ...
Abstract base class for objects that represent a real value and implements functionality common to al...
Definition RooAbsReal.h:63
double getVal(const RooArgSet *normalisationSet=nullptr) const
Evaluate object.
Definition RooAbsReal.h:107
virtual double defaultErrorLevel() const
Definition RooAbsReal.h:245
void printMultiline(std::ostream &os, Int_t contents, bool verbose=false, TString indent="") const override
Structure printing.
double _value
Cache for current value of object.
Definition RooAbsReal.h:541
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
RooArgSet is a container object that can hold multiple RooAbsArg objects.
Definition RooArgSet.h:24
void markAsCompiled(RooAbsArg &arg) const
void compileServers(RooAbsArg &arg, RooArgSet const &normSet)
A RooFormulaVar is a generic implementation of a real-valued object, which takes a RooArgList of serv...
~RooFormulaVar() override
std::map< int, std::unique_ptr< RooAbsBinning > > _binnings
User-defined binnings, keyed by the observable's index in _actualVars, for a piecewise-flat distribut...
RooListProxy _actualVars
Actual parameters used by formula engine.
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].
bool isBinnedDistribution(const RooArgSet &obs) const override
Return true if a binning was set with setBinning() for every observable in the integration set obs.
void doEval(RooFit::EvalContext &ctx) const override
Base function for computing multiple values of a RooAbsReal.
void dumpFormula()
Dump the formula to stdout.
RooFormulaEvaluator & evaluator() const
Return reference to the formula evaluation engine.
double defaultErrorLevel() const override
Return the default error level for MINUIT error analysis.
std::unique_ptr< RooFormulaEvaluator > _evaluator
! Formula evaluation engine
std::unique_ptr< RooAbsArg > compileForNormSet(RooArgSet const &normSet, RooFit::Detail::CompileContext &ctx) const override
std::list< double > * plotSamplingHint(RooAbsRealLValue &obs, double xlo, double xhi) const override
Return sampling hints that draw the piecewise-flat shape exactly if a binning was set for this observ...
void setBinning(const RooAbsRealLValue &obs, const RooAbsBinning &binning, bool checkFlatness=true)
Declare that this function is piecewise constant (flat) within the bins of the given binning of the o...
bool ok() const
const RooArgList & dependents() const
bool removeBinning(const RooAbsRealLValue &obs)
Remove a binning previously declared with setBinning() for observable obs, reverting to the generic n...
bool readFromStream(std::istream &is, bool compact, bool verbose=false) override
Read object contents from given stream.
const RooAbsBinning * getBinning(const RooAbsRealLValue &obs) const
Return the binning previously declared with setBinning() for observable obs, or nullptr if no binning...
TString _formExpr
Formula expression string.
void printMultiline(std::ostream &os, Int_t contents, bool verbose=false, TString indent="") const override
Print info about this object to the specified stream.
std::string getUniqueFuncName() const
double evaluate() const override
Calculate current value of object from internal formula.
void writeToStream(std::ostream &os, bool compact) const override
Write object contents to given stream.
void printMetaArgs(std::ostream &os) const override
Add formula expression as meta argument in printing interface.
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:137
const char * Data() const
Definition TString.h:385