Logo ROOT  
Reference Guide
RooHelpers.cxx
Go to the documentation of this file.
1// Author: Stephan Hageboeck, CERN 01/2019
2
3/*****************************************************************************
4 * RooFit
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-2019, 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#include <RooHelpers.h>
18
19#include <RooAbsCategory.h>
20#include <RooAbsData.h>
21#include <RooAbsPdf.h>
22#include <RooAbsRealLValue.h>
23#include <RooArgList.h>
24#include <RooDataHist.h>
25#include <RooDataSet.h>
26#include <RooSimultaneous.h>
27#include <RooProdPdf.h>
28#include <RooRealSumPdf.h>
29
30#include <ROOT/StringUtils.hxx>
31#include <TClass.h>
32
33namespace RooHelpers {
34
36 unsigned int extraTopics, unsigned int removeTopics, bool overrideExternalLevel) {
37 auto& msg = RooMsgService::instance();
38 fOldKillBelow = msg.globalKillBelow();
39 if (overrideExternalLevel) msg.setGlobalKillBelow(lvl);
40
41 for (int i = 0; i < msg.numStreams(); ++i) {
42 fOldConf.push_back(msg.getStream(i));
43 if (overrideExternalLevel) msg.getStream(i).minLevel = lvl;
44 msg.getStream(i).removeTopic(static_cast<RooFit::MsgTopic>(removeTopics));
45 msg.setStreamStatus(i, true);
46 }
47
48 if (extraTopics != 0) {
49 fExtraStream = msg.addStream(lvl);
50 msg.getStream(fExtraStream).addTopic(static_cast<RooFit::MsgTopic>(extraTopics));
51 }
52}
53
55 auto& msg = RooMsgService::instance();
56 msg.setGlobalKillBelow(fOldKillBelow);
57 for (int i=0; i < msg.numStreams(); ++i) {
58 if (i < static_cast<int>(fOldConf.size()))
59 msg.getStream(i) = fOldConf[i];
60 }
61
62 if (fExtraStream > 0)
63 msg.deleteStream(fExtraStream);
64}
65
66
67/// Hijack all messages with given level and topics while this object is alive.
68/// \param[in] level Minimum level to hijack. Higher levels also get captured.
69/// \param[in] topics Topics to hijack. Use `|` to combine different topics, and cast to `RooFit::MsgTopic` if necessary.
70/// \param[in] objectName Only hijack messages from an object with the given name. Defaults to any object.
72{
73 auto& msg = RooMsgService::instance();
74 _oldKillBelow = msg.globalKillBelow();
75 if (_oldKillBelow > level)
76 msg.setGlobalKillBelow(level);
77
78 std::vector<RooMsgService::StreamConfig> tmpStreams;
79 for (int i = 0; i < msg.numStreams(); ++i) {
80 _oldConf.push_back(msg.getStream(i));
81 if (msg.getStream(i).match(level, topics, static_cast<RooAbsArg*>(nullptr))) {
82 tmpStreams.push_back(msg.getStream(i));
83 msg.setStreamStatus(i, false);
84 }
85 }
86
87 _thisStream = msg.addStream(level,
88 RooFit::Topic(topics),
90 objectName ? RooFit::ObjectName(objectName) : RooCmdArg());
91
92 for (RooMsgService::StreamConfig& st : tmpStreams) {
93 msg.addStream(st.minLevel,
94 RooFit::Topic(st.topic),
96 RooFit::ObjectName(st.objectName.c_str()),
97 RooFit::ClassName(st.className.c_str()),
98 RooFit::BaseClassName(st.baseClassName.c_str()),
99 RooFit::TagName(st.tagName.c_str()));
100 }
101}
102
103/// Deregister the hijacked stream and restore the stream state of all previous streams.
105 auto& msg = RooMsgService::instance();
106 msg.setGlobalKillBelow(_oldKillBelow);
107 for (unsigned int i = 0; i < _oldConf.size(); ++i) {
108 msg.getStream(i) = _oldConf[i];
109 }
110
111 while (_thisStream < msg.numStreams()) {
112 msg.deleteStream(_thisStream);
113 }
114}
115
116
117/// \param[in] callingClass Class that's calling. Needed to include name and type name of the class in error message.
118/// \param[in] pars List of all parameters to be checked.
119/// \param[in] min Minimum of allowed range. `min` itself counts as disallowed.
120/// \param[in] max Maximum of allowed range. `max` itself counts as disallowed.
121/// \param[in] limitsInAllowedRange If true, the limits passed as parameters are part of the allowed range.
122/// \param[in] extraMessage Message that should be appended to the warning.
123void checkRangeOfParameters(const RooAbsReal* callingClass, std::initializer_list<const RooAbsReal*> pars,
124 double min, double max, bool limitsInAllowedRange, std::string const& extraMessage) {
125 const char openBr = limitsInAllowedRange ? '[' : '(';
126 const char closeBr = limitsInAllowedRange ? ']' : ')';
127
128 for (auto parameter : pars) {
129 auto par = dynamic_cast<const RooAbsRealLValue*>(parameter);
130 if (par && (
131 (par->getMin() < min || par->getMax() > max)
132 || (!limitsInAllowedRange && (par->getMin() == min || par->getMax() == max)) )) {
133 std::stringstream rangeMsg;
134 rangeMsg << openBr;
135 if (min > -std::numeric_limits<double>::max())
136 rangeMsg << min << ", ";
137 else
138 rangeMsg << "-inf, ";
139
140 if (max < std::numeric_limits<double>::max())
141 rangeMsg << max << closeBr;
142 else
143 rangeMsg << "inf" << closeBr;
144
145 oocoutW(callingClass, InputArguments) << "The parameter '" << par->GetName() << "' with range [" << par->getMin("") << ", "
146 << par->getMax() << "] of the " << callingClass->ClassName() << " '" << callingClass->GetName()
147 << "' exceeds the safe range of " << rangeMsg.str() << ". Advise to limit its range."
148 << (!extraMessage.empty() ? "\n" : "") << extraMessage << std::endl;
149 }
150 }
151}
152
153
154namespace {
155 std::pair<double, double> getBinningInterval(RooAbsBinning const& binning) {
156 if (!binning.isParameterized()) {
157 return {binning.lowBound(), binning.highBound()};
158 } else {
159 return {binning.lowBoundFunc()->getVal(), binning.highBoundFunc()->getVal()};
160 }
161 }
162} // namespace
163
164
165/// Get the lower and upper bound of parameter range if arg can be casted to RooAbsRealLValue.
166/// If no range with rangeName is defined for the argument, this will check if a binning of the
167/// same name exists and return the interval covered by the binning.
168/// Returns `{-infinity, infinity}` if agument can't be casted to RooAbsRealLValue* or if no
169/// range or binning with the requested name exists.
170/// \param[in] arg RooAbsArg for which to get the range.
171/// \param[in] rangeName The name of the range.
172std::pair<double, double> getRangeOrBinningInterval(RooAbsArg const* arg, const char* rangeName) {
173 auto rlv = dynamic_cast<RooAbsRealLValue const*>(arg);
174 if (rlv) {
175 if (rangeName && rlv->hasRange(rangeName)) {
176 return {rlv->getMin(rangeName), rlv->getMax(rangeName)};
177 } else if (auto binning = rlv->getBinningPtr(rangeName)) {
178 return getBinningInterval(*binning);
179 }
180 }
181 return {-std::numeric_limits<double>::infinity(), +std::numeric_limits<double>::infinity()};
182}
183
184
185/// Check if there is any overlap when a list of ranges is applied to a set of observables.
186/// \param[in] observables The observables to check for overlap
187/// \param[in] rangeNames The names of the ranges.
188bool checkIfRangesOverlap(RooArgSet const& observables, std::vector<std::string> const& rangeNames)
189{
190 // cache the range limits in a flat vector
191 std::vector<std::pair<double,double>> limits;
192 limits.reserve(rangeNames.size() * observables.size());
193
194 for (auto const& range : rangeNames) {
195 for (auto const& obs : observables) {
196 if(dynamic_cast<RooAbsCategory const*>(obs)) {
197 // Nothing to be done for category observables
198 } else if(auto * rlv = dynamic_cast<RooAbsRealLValue const*>(obs)) {
199 limits.emplace_back(rlv->getMin(range.c_str()), rlv->getMax(range.c_str()));
200 } else {
201 throw std::logic_error("Classes that represent observables are expected to inherit from RooAbsRealLValue or RooAbsCategory!");
202 }
203 }
204 }
205
206 auto nRanges = rangeNames.size();
207 auto nObs = limits.size() / nRanges; // number of observables that are not categories
208
209 // loop over pairs of ranges
210 for(size_t ir1 = 0; ir1 < nRanges; ++ir1) {
211 for(size_t ir2 = ir1 + 1; ir2 < nRanges; ++ir2) {
212
213 // Loop over observables. If all observables have overlapping limits for
214 // these ranges, the hypercubes defining the range are overlapping and we
215 // can return `true`.
216 size_t overlaps = 0;
217 for(size_t io1 = 0; io1 < nObs; ++io1) {
218 auto r1 = limits[ir1 * nObs + io1];
219 auto r2 = limits[ir2 * nObs + io1];
220 overlaps += (r1.second > r2.first && r1.first < r2.second)
221 || (r2.second > r1.first && r2.first < r1.second);
222 }
223 if(overlaps == nObs) return true;
224 }
225 }
226
227 return false;
228}
229
230
231/// Create a string with all sorted names of RooArgSet elements separated by colons.
232/// \param[in] argSet The input RooArgSet.
233std::string getColonSeparatedNameString(RooArgSet const& argSet) {
234
235 RooArgList tmp(argSet);
236 tmp.sort();
237
238 std::string content;
239 for(auto const& arg : tmp) {
240 content += arg->GetName();
241 content += ":";
242 }
243 if(!content.empty()) {
244 content.pop_back();
245 }
246 return content;
247}
248
249
250/// Construct a RooArgSet of objects in a RooArgSet whose names match to those
251/// in the names string.
252/// \param[in] argSet The input RooArgSet.
253/// \param[in] names The names of the objects to select in a colon-separated string.
254RooArgSet selectFromArgSet(RooArgSet const& argSet, std::string const& names) {
256 for(auto const& name : ROOT::Split(names, ":")) {
257 if(auto arg = argSet.find(name.c_str())) output.add(*arg);
258 }
259 return output;
260}
261
262
263std::string getRangeNameForSimComponent(std::string const& rangeName, bool splitRange, std::string const& catName)
264{
265 if (splitRange && !rangeName.empty()) {
266 std::string out;
267 auto tokens = ROOT::Split(rangeName, ",");
268 for(std::string const& token : tokens) {
269 out += token + "_" + catName + ",";
270 }
271 out.pop_back(); // to remove the last comma
272 return out;
273 }
274
275 return rangeName;
276}
277
279{
280 if (pdf.getAttribute("BinnedLikelihood") && pdf.IsA()->InheritsFrom(RooRealSumPdf::Class())) {
281 // Simplest case: top-level of component is a RooRealSumPdf
282 return {&pdf, true};
283 } else if (pdf.IsA()->InheritsFrom(RooProdPdf::Class())) {
284 // Default case: top-level pdf is a product of RooRealSumPdf and other pdfs
285 for (RooAbsArg *component : static_cast<RooProdPdf &>(pdf).pdfList()) {
286 if (component->getAttribute("BinnedLikelihood") && component->IsA()->InheritsFrom(RooRealSumPdf::Class())) {
287 return {static_cast<RooAbsPdf *>(component), true};
288 }
289 if (component->getAttribute("MAIN_MEASUREMENT")) {
290 // not really a binned pdf, but this prevents a (potentially) long list of subsidiary measurements to be passed to the slave calculator
291 return {static_cast<RooAbsPdf *>(component), false};
292 }
293 }
294 }
295 return {nullptr, false};
296}
297
298/// Get the topologically-sorted list of all nodes in the computation graph.
300{
301 // Get the set of nodes in the computation graph. Do the detour via
302 // RooArgList to avoid deduplication done after adding each element.
303 RooArgList serverList;
304 func.treeNodeServerList(&serverList, nullptr, true, true, false, true);
305 // If we fill the servers in reverse order, they are approximately in
306 // topological order so we save a bit of work in sortTopologically().
307 out.add(serverList.rbegin(), serverList.rend(), /*silent=*/true);
308 // Sort nodes topologically: the servers of any node will be before that
309 // node in the collection.
310 out.sortTopologically();
311}
312
313}
#define oocoutW(o, a)
Definition: RooMsgService.h:51
char name[80]
Definition: TGX11.cxx:110
RooAbsArg is the common abstract base class for objects that represent a value and a "shape" in RooFi...
Definition: RooAbsArg.h:72
bool getAttribute(const Text_t *name) const
Check if a named attribute is set. By default, all attributes are unset.
Definition: RooAbsArg.cxx:268
void treeNodeServerList(RooAbsCollection *list, const RooAbsArg *arg=nullptr, bool doBranch=true, bool doLeaf=true, bool valueOnly=false, bool recurseNonDerived=false) const
Fill supplied list with nodes of the arg tree, following all server links, starting with ourself as t...
Definition: RooAbsArg.cxx:520
RooAbsBinning is the abstract base class for RooRealVar binning definitions.
Definition: RooAbsBinning.h:25
virtual bool isParameterized() const
Interface function.
virtual double highBound() const =0
virtual double lowBound() const =0
virtual RooAbsReal * highBoundFunc() const
Return pointer to RooAbsReal parameterized upper bound, if any.
virtual RooAbsReal * lowBoundFunc() const
Return pointer to RooAbsReal parameterized lower bound, if any.
A space to attach TBranches.
void sortTopologically()
Sort collection topologically: the servers of any RooAbsArg will be before that RooAbsArg in the coll...
Storage_t::const_reverse_iterator rend() const
virtual bool add(const RooAbsArg &var, bool silent=false)
Add the specified argument to list.
Storage_t::const_reverse_iterator rbegin() const
Storage_t::size_type size() const
void sort(bool reverse=false)
Sort collection using std::sort and name comparison.
RooAbsArg * find(const char *name) const
Find object with given name in list.
TClass * IsA() const override
Definition: RooAbsPdf.h:407
RooAbsRealLValue is the common abstract base class for objects that represent a real value that may a...
virtual double getMin(const char *name=nullptr) const
Get minimum of currently defined range.
RooAbsReal is the common abstract base class for objects that represent a real value and implements f...
Definition: RooAbsReal.h:61
double getVal(const RooArgSet *normalisationSet=nullptr) const
Evaluate object.
Definition: RooAbsReal.h:105
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:56
RooCmdArg is a named container for two doubles, two integers two object points and three string point...
Definition: RooCmdArg.h:26
RooFit::MsgLevel _oldKillBelow
Definition: RooHelpers.h:88
HijackMessageStream(RooFit::MsgLevel level, RooFit::MsgTopic topics, const char *objectName=nullptr)
Hijack all messages with given level and topics while this object is alive.
Definition: RooHelpers.cxx:71
std::ostringstream _str
Definition: RooHelpers.h:87
std::vector< RooMsgService::StreamConfig > _oldConf
Definition: RooHelpers.h:89
~HijackMessageStream()
Deregister the hijacked stream and restore the stream state of all previous streams.
Definition: RooHelpers.cxx:104
RooFit::MsgLevel fOldKillBelow
Definition: RooHelpers.h:57
LocalChangeMsgLevel(RooFit::MsgLevel lvl=RooFit::DEBUG, unsigned int extraTopics=0u, unsigned int removeTopics=0u, bool overrideExternalLevel=true)
Change message level (and topics) while this object is alive, reset when it goes out of scope.
Definition: RooHelpers.cxx:35
std::vector< RooMsgService::StreamConfig > fOldConf
Definition: RooHelpers.h:58
static RooMsgService & instance()
Return reference to singleton instance.
RooProdPdf is an efficient implementation of a product of PDFs of the form.
Definition: RooProdPdf.h:33
static TClass * Class()
static TClass * Class()
Bool_t InheritsFrom(const char *cl) const override
Return kTRUE if this class inherits from a class with name "classname".
Definition: TClass.cxx:4863
const char * GetName() const override
Returns name of object.
Definition: TNamed.h:47
virtual const char * ClassName() const
Returns name of class to which the object belongs.
Definition: TObject.cxx:207
RooCmdArg ClassName(const char *name)
RooCmdArg OutputStream(std::ostream &os)
RooCmdArg Topic(Int_t topic)
RooCmdArg TagName(const char *name)
RooCmdArg BaseClassName(const char *name)
RooCmdArg ObjectName(const char *name)
std::vector< std::string > Split(std::string_view str, std::string_view delims, bool skipEmpty=false)
Splits a string at each character in delims.
Definition: StringUtils.cxx:23
MsgLevel
Verbosity level for RooMsgService::StreamConfig in RooMsgService.
Definition: RooGlobalFunc.h:60
MsgTopic
Topics for a RooMsgService::StreamConfig in RooMsgService.
Definition: RooGlobalFunc.h:62
@ InputArguments
Definition: RooGlobalFunc.h:63
void getSortedComputationGraph(RooAbsReal const &func, RooArgSet &out)
Get the topologically-sorted list of all nodes in the computation graph.
Definition: RooHelpers.cxx:299
void checkRangeOfParameters(const RooAbsReal *callingClass, std::initializer_list< const RooAbsReal * > pars, double min=-std::numeric_limits< double >::max(), double max=std::numeric_limits< double >::max(), bool limitsInAllowedRange=false, std::string const &extraMessage="")
Check if the parameters have a range, and warn if the range extends below / above the set limits.
Definition: RooHelpers.cxx:123
BinnedLOutput getBinnedL(RooAbsPdf &pdf)
Definition: RooHelpers.cxx:278
std::string getRangeNameForSimComponent(std::string const &rangeName, bool splitRange, std::string const &catName)
Definition: RooHelpers.cxx:263
RooArgSet selectFromArgSet(RooArgSet const &, std::string const &names)
Construct a RooArgSet of objects in a RooArgSet whose names match to those in the names string.
Definition: RooHelpers.cxx:254
bool checkIfRangesOverlap(RooArgSet const &observables, std::vector< std::string > const &rangeNames)
Check if there is any overlap when a list of ranges is applied to a set of observables.
Definition: RooHelpers.cxx:188
std::pair< double, double > getRangeOrBinningInterval(RooAbsArg const *arg, const char *rangeName)
Get the lower and upper bound of parameter range if arg can be casted to RooAbsRealLValue.
Definition: RooHelpers.cxx:172
std::string getColonSeparatedNameString(RooArgSet const &argSet)
Create a string with all sorted names of RooArgSet elements separated by colons.
Definition: RooHelpers.cxx:233
static void output()