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] data RooAbsCollection with the observables to check for overlap.
188/// \param[in] rangeNames The names of the ranges.
189bool checkIfRangesOverlap(RooArgSet const& observables,
190 RooAbsData const& data,
191 std::vector<std::string> const& rangeNames)
192{
193 auto getLimits = [&](RooAbsRealLValue const& rlv, const char* rangeName) {
194
195 // RooDataHistCase
196 if(dynamic_cast<RooDataHist const*>(&data)) {
197 if (auto binning = rlv.getBinningPtr(rangeName)) {
198 return getBinningInterval(*binning);
199 } else {
200 // default binning if range is not defined
201 return getBinningInterval(*rlv.getBinningPtr(nullptr));
202 }
203 }
204
205 // RooDataSet and other cases
206 if (rlv.hasRange(rangeName)) {
207 return std::pair<double, double>{rlv.getMin(rangeName), rlv.getMax(rangeName)};
208 }
209 // default range if range with given name is not defined
210 return std::pair<double, double>{rlv.getMin(), rlv.getMax()};
211 };
212
213 // cache the range limits in a flat vector
214 std::vector<std::pair<double,double>> limits;
215 limits.reserve(rangeNames.size() * observables.size());
216
217 for (auto const& range : rangeNames) {
218 for (auto const& obs : observables) {
219 if(dynamic_cast<RooAbsCategory const*>(obs)) {
220 // Nothing to be done for category observables
221 } else if(auto * rlv = dynamic_cast<RooAbsRealLValue const*>(obs)) {
222 limits.push_back(getLimits(*rlv, range.c_str()));
223 } else {
224 throw std::logic_error("Classes that represent observables are expected to inherit from RooAbsRealLValue or RooAbsCategory!");
225 }
226 }
227 }
228
229 auto nRanges = rangeNames.size();
230 auto nObs = limits.size() / nRanges; // number of observables that are not categories
231
232 // loop over pairs of ranges
233 for(size_t ir1 = 0; ir1 < nRanges; ++ir1) {
234 for(size_t ir2 = ir1 + 1; ir2 < nRanges; ++ir2) {
235
236 // Loop over observables. If all observables have overlapping limits for
237 // these ranges, the hypercubes defining the range are overlapping and we
238 // can return `true`.
239 size_t overlaps = 0;
240 for(size_t io1 = 0; io1 < nObs; ++io1) {
241 auto r1 = limits[ir1 * nObs + io1];
242 auto r2 = limits[ir2 * nObs + io1];
243 overlaps += (r1.second > r2.first && r1.first < r2.second)
244 || (r2.second > r1.first && r2.first < r1.second);
245 }
246 if(overlaps == nObs) return true;
247 }
248 }
249
250 return false;
251}
252
253
254/// Create a string with all sorted names of RooArgSet elements separated by colons.
255/// \param[in] argSet The input RooArgSet.
256std::string getColonSeparatedNameString(RooArgSet const& argSet) {
257
258 RooArgList tmp(argSet);
259 tmp.sort();
260
261 std::string content;
262 for(auto const& arg : tmp) {
263 content += arg->GetName();
264 content += ":";
265 }
266 if(!content.empty()) {
267 content.pop_back();
268 }
269 return content;
270}
271
272
273/// Construct a RooArgSet of objects in a RooArgSet whose names match to those
274/// in the names string.
275/// \param[in] argSet The input RooArgSet.
276/// \param[in] names The names of the objects to select in a colon-separated string.
277RooArgSet selectFromArgSet(RooArgSet const& argSet, std::string const& names) {
279 for(auto const& name : ROOT::Split(names, ":")) {
280 if(auto arg = argSet.find(name.c_str())) output.add(*arg);
281 }
282 return output;
283}
284
285
286std::string getRangeNameForSimComponent(std::string const& rangeName, bool splitRange, std::string const& catName)
287{
288 if (splitRange && !rangeName.empty()) {
289 std::string out;
290 auto tokens = ROOT::Split(rangeName, ",");
291 for(std::string const& token : tokens) {
292 out += token + "_" + catName + ",";
293 }
294 out.pop_back(); // to remove the last comma
295 return out;
296 }
297
298 return rangeName;
299}
300
302{
303 if (pdf.getAttribute("BinnedLikelihood") && pdf.IsA()->InheritsFrom(RooRealSumPdf::Class())) {
304 // Simplest case: top-level of component is a RooRealSumPdf
305 return {&pdf, true};
306 } else if (pdf.IsA()->InheritsFrom(RooProdPdf::Class())) {
307 // Default case: top-level pdf is a product of RooRealSumPdf and other pdfs
308 for (RooAbsArg *component : static_cast<RooProdPdf &>(pdf).pdfList()) {
309 if (component->getAttribute("BinnedLikelihood") && component->IsA()->InheritsFrom(RooRealSumPdf::Class())) {
310 return {static_cast<RooAbsPdf *>(component), true};
311 }
312 if (component->getAttribute("MAIN_MEASUREMENT")) {
313 // not really a binned pdf, but this prevents a (potentially) long list of subsidiary measurements to be passed to the slave calculator
314 return {static_cast<RooAbsPdf *>(component), false};
315 }
316 }
317 }
318 return {nullptr, false};
319}
320
321}
#define oocoutW(o, a)
Definition: RooMsgService.h:51
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void data
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:71
bool getAttribute(const Text_t *name) const
Check if a named attribute is set. By default, all attributes are unset.
Definition: RooAbsArg.cxx:269
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.
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.
RooAbsData is the common abstract base class for binned and unbinned datasets.
Definition: RooAbsData.h:62
TClass * IsA() const override
Definition: RooAbsPdf.h:397
RooAbsRealLValue is the common abstract base class for objects that represent a real value that may a...
virtual double getMax(const char *name=nullptr) const
Get maximum of currently defined range.
virtual double getMin(const char *name=nullptr) const
Get minimum of currently defined range.
const RooAbsBinning * getBinningPtr(const char *rangeName) const override
bool hasRange(const char *name) const override
Check if variable has a binning with given name.
RooAbsReal is the common abstract base class for objects that represent a real value and implements f...
Definition: RooAbsReal.h:62
double getVal(const RooArgSet *normalisationSet=nullptr) const
Evaluate object.
Definition: RooAbsReal.h:91
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
The RooDataHist is a container class to hold N-dimensional binned data.
Definition: RooDataHist.h:39
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:59
MsgTopic
Topics for a RooMsgService::StreamConfig in RooMsgService.
Definition: RooGlobalFunc.h:61
@ InputArguments
Definition: RooGlobalFunc.h:62
bool checkIfRangesOverlap(RooArgSet const &observables, RooAbsData const &data, 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:189
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:301
std::string getRangeNameForSimComponent(std::string const &rangeName, bool splitRange, std::string const &catName)
Definition: RooHelpers.cxx:286
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:277
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:256
static void output()