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#include "RooAbsPdf.h"
19#include "RooAbsData.h"
20#include "RooDataHist.h"
21#include "RooDataSet.h"
22#include "RooAbsRealLValue.h"
23#include "RooArgList.h"
24#include "RooAbsCategory.h"
25
26#include "ROOT/StringUtils.hxx"
27#include "TClass.h"
28
29namespace RooHelpers {
30
32 unsigned int extraTopics, unsigned int removeTopics, bool overrideExternalLevel) {
33 auto& msg = RooMsgService::instance();
34 fOldKillBelow = msg.globalKillBelow();
35 if (overrideExternalLevel) msg.setGlobalKillBelow(lvl);
36
37 for (int i = 0; i < msg.numStreams(); ++i) {
38 fOldConf.push_back(msg.getStream(i));
39 if (overrideExternalLevel) msg.getStream(i).minLevel = lvl;
40 msg.getStream(i).removeTopic(static_cast<RooFit::MsgTopic>(removeTopics));
41 msg.setStreamStatus(i, true);
42 }
43
44 if (extraTopics != 0) {
45 fExtraStream = msg.addStream(lvl);
46 msg.getStream(fExtraStream).addTopic(static_cast<RooFit::MsgTopic>(extraTopics));
47 }
48}
49
51 auto& msg = RooMsgService::instance();
52 msg.setGlobalKillBelow(fOldKillBelow);
53 for (int i=0; i < msg.numStreams(); ++i) {
54 if (i < static_cast<int>(fOldConf.size()))
55 msg.getStream(i) = fOldConf[i];
56 }
57
58 if (fExtraStream > 0)
59 msg.deleteStream(fExtraStream);
60}
61
62
63/// Hijack all messages with given level and topics while this object is alive.
64/// \param[in] level Minimum level to hijack. Higher levels also get captured.
65/// \param[in] topics Topics to hijack. Use `|` to combine different topics, and cast to `RooFit::MsgTopic` if necessary.
66/// \param[in] objectName Only hijack messages from an object with the given name. Defaults to any object.
68{
69 auto& msg = RooMsgService::instance();
70 _oldKillBelow = msg.globalKillBelow();
71 if (_oldKillBelow > level)
72 msg.setGlobalKillBelow(level);
73
74 std::vector<RooMsgService::StreamConfig> tmpStreams;
75 for (int i = 0; i < msg.numStreams(); ++i) {
76 _oldConf.push_back(msg.getStream(i));
77 if (msg.getStream(i).match(level, topics, static_cast<RooAbsArg*>(nullptr))) {
78 tmpStreams.push_back(msg.getStream(i));
79 msg.setStreamStatus(i, false);
80 }
81 }
82
83 _thisStream = msg.addStream(level,
84 RooFit::Topic(topics),
86 objectName ? RooFit::ObjectName(objectName) : RooCmdArg());
87
88 for (RooMsgService::StreamConfig& st : tmpStreams) {
89 msg.addStream(st.minLevel,
90 RooFit::Topic(st.topic),
92 RooFit::ObjectName(st.objectName.c_str()),
93 RooFit::ClassName(st.className.c_str()),
94 RooFit::BaseClassName(st.baseClassName.c_str()),
95 RooFit::TagName(st.tagName.c_str()));
96 }
97}
98
99/// Deregister the hijacked stream and restore the stream state of all previous streams.
101 auto& msg = RooMsgService::instance();
102 msg.setGlobalKillBelow(_oldKillBelow);
103 for (unsigned int i = 0; i < _oldConf.size(); ++i) {
104 msg.getStream(i) = _oldConf[i];
105 }
106
107 while (_thisStream < msg.numStreams()) {
108 msg.deleteStream(_thisStream);
109 }
110}
111
112
113/// \param[in] callingClass Class that's calling. Needed to include name and type name of the class in error message.
114/// \param[in] pars List of all parameters to be checked.
115/// \param[in] min Minimum of allowed range. `min` itself counts as disallowed.
116/// \param[in] max Maximum of allowed range. `max` itself counts as disallowed.
117/// \param[in] limitsInAllowedRange If true, the limits passed as parameters are part of the allowed range.
118/// \param[in] extraMessage Message that should be appended to the warning.
119void checkRangeOfParameters(const RooAbsReal* callingClass, std::initializer_list<const RooAbsReal*> pars,
120 double min, double max, bool limitsInAllowedRange, std::string const& extraMessage) {
121 const char openBr = limitsInAllowedRange ? '[' : '(';
122 const char closeBr = limitsInAllowedRange ? ']' : ')';
123
124 for (auto parameter : pars) {
125 auto par = dynamic_cast<const RooAbsRealLValue*>(parameter);
126 if (par && (
127 (par->getMin() < min || par->getMax() > max)
128 || (!limitsInAllowedRange && (par->getMin() == min || par->getMax() == max)) )) {
129 std::stringstream rangeMsg;
130 rangeMsg << openBr;
131 if (min > -std::numeric_limits<double>::max())
132 rangeMsg << min << ", ";
133 else
134 rangeMsg << "-inf, ";
135
136 if (max < std::numeric_limits<double>::max())
137 rangeMsg << max << closeBr;
138 else
139 rangeMsg << "inf" << closeBr;
140
141 oocoutW(callingClass, InputArguments) << "The parameter '" << par->GetName() << "' with range [" << par->getMin("") << ", "
142 << par->getMax() << "] of the " << callingClass->ClassName() << " '" << callingClass->GetName()
143 << "' exceeds the safe range of " << rangeMsg.str() << ". Advise to limit its range."
144 << (!extraMessage.empty() ? "\n" : "") << extraMessage << std::endl;
145 }
146 }
147}
148
149
150namespace {
151 std::pair<double, double> getBinningInterval(RooAbsBinning const& binning) {
152 if (!binning.isParameterized()) {
153 return {binning.lowBound(), binning.highBound()};
154 } else {
155 return {binning.lowBoundFunc()->getVal(), binning.highBoundFunc()->getVal()};
156 }
157 }
158} // namespace
159
160
161/// Get the lower and upper bound of parameter range if arg can be casted to RooAbsRealLValue.
162/// If no range with rangeName is defined for the argument, this will check if a binning of the
163/// same name exists and return the interval covered by the binning.
164/// Returns `{-infinity, infinity}` if agument can't be casted to RooAbsRealLValue* or if no
165/// range or binning with the requested name exists.
166/// \param[in] arg RooAbsArg for which to get the range.
167/// \param[in] rangeName The name of the range.
168std::pair<double, double> getRangeOrBinningInterval(RooAbsArg const* arg, const char* rangeName) {
169 auto rlv = dynamic_cast<RooAbsRealLValue const*>(arg);
170 if (rlv) {
171 if (rangeName && rlv->hasRange(rangeName)) {
172 return {rlv->getMin(rangeName), rlv->getMax(rangeName)};
173 } else if (auto binning = rlv->getBinningPtr(rangeName)) {
174 return getBinningInterval(*binning);
175 }
176 }
177 return {-std::numeric_limits<double>::infinity(), +std::numeric_limits<double>::infinity()};
178}
179
180
181/// Check if there is any overlap when a list of ranges is applied to a set of observables.
182/// \param[in] pdf the PDF
183/// \param[in] data RooAbsCollection with the observables to check for overlap.
184/// \param[in] rangeNames The names of the ranges.
185bool checkIfRangesOverlap(RooAbsPdf const& pdf, RooAbsData const& data, std::vector<std::string> const& rangeNames) {
186
187 auto observables = *pdf.getObservables(data);
188
189 auto getLimits = [&](RooAbsRealLValue const& rlv, const char* rangeName) {
190
191 // RooDataHistCase
192 if(dynamic_cast<RooDataHist const*>(&data)) {
193 if (auto binning = rlv.getBinningPtr(rangeName)) {
194 return getBinningInterval(*binning);
195 } else {
196 // default binning if range is not defined
197 return getBinningInterval(*rlv.getBinningPtr(nullptr));
198 }
199 }
200
201 // RooDataSet and other cases
202 if (rlv.hasRange(rangeName)) {
203 return std::pair<double, double>{rlv.getMin(rangeName), rlv.getMax(rangeName)};
204 }
205 // default range if range with given name is not defined
206 return std::pair<double, double>{rlv.getMin(), rlv.getMax()};
207 };
208
209 // cache the range limits in a flat vector
210 std::vector<std::pair<double,double>> limits;
211 limits.reserve(rangeNames.size() * observables.size());
212
213 for (auto const& range : rangeNames) {
214 for (auto const& obs : observables) {
215 if(dynamic_cast<RooAbsCategory const*>(obs)) {
216 // Nothing to be done for category observables
217 } else if(auto * rlv = dynamic_cast<RooAbsRealLValue const*>(obs)) {
218 limits.push_back(getLimits(*rlv, range.c_str()));
219 } else {
220 throw std::logic_error("Classes that represent observables are expected to inherit from RooAbsRealLValue or RooAbsCategory!");
221 }
222 }
223 }
224
225 auto nRanges = rangeNames.size();
226 auto nObs = limits.size() / nRanges; // number of observables that are not categories
227
228 // loop over pairs of ranges
229 for(size_t ir1 = 0; ir1 < nRanges; ++ir1) {
230 for(size_t ir2 = ir1 + 1; ir2 < nRanges; ++ir2) {
231
232 // Loop over observables. If all observables have overlapping limits for
233 // these ranges, the hypercubes defining the range are overlapping and we
234 // can return `true`.
235 size_t overlaps = 0;
236 for(size_t io1 = 0; io1 < nObs; ++io1) {
237 auto r1 = limits[ir1 * nObs + io1];
238 auto r2 = limits[ir2 * nObs + io1];
239 overlaps += (r1.second > r2.first && r1.first < r2.second)
240 || (r2.second > r1.first && r2.first < r1.second);
241 }
242 if(overlaps == nObs) return true;
243 }
244 }
245
246 return false;
247}
248
249
250/// Create a string with all sorted names of RooArgSet elements separated by colons.
251/// \param[in] argSet The input RooArgSet.
252std::string getColonSeparatedNameString(RooArgSet const& argSet) {
253
254 RooArgList tmp(argSet);
255 tmp.sort();
256
257 std::string content;
258 for(auto const& arg : tmp) {
259 content += arg->GetName();
260 content += ":";
261 }
262 if(!content.empty()) {
263 content.pop_back();
264 }
265 return content;
266}
267
268
269/// Construct a RooArgSet of objects in a RooArgSet whose names match to those
270/// in the names string.
271/// \param[in] argSet The input RooArgSet.
272/// \param[in] names The names of the objects to select in a colon-separated string.
273RooArgSet selectFromArgSet(RooArgSet const& argSet, std::string const& names) {
275 for(auto const& name : ROOT::Split(names, ":")) {
276 if(auto arg = argSet.find(name.c_str())) output.add(*arg);
277 }
278 return output;
279}
280
281
282}
#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:72
RooArgSet * getObservables(const RooArgSet &set, bool valueOnly=true) const
Given a set of possible observables, return the observables that this PDF depends on.
Definition: RooAbsArg.h:312
RooAbsBinning is the abstract base class for RooRealVar binning definitions.
Definition: RooAbsBinning.h:26
virtual bool isParameterized() const
Interface function.
Definition: RooAbsBinning.h:80
virtual double highBound() const =0
virtual double lowBound() const =0
virtual RooAbsReal * highBoundFunc() const
Return pointer to RooAbsReal parameterized upper bound, if any.
Definition: RooAbsBinning.h:88
virtual RooAbsReal * lowBoundFunc() const
Return pointer to RooAbsReal parameterized lower bound, if any.
Definition: RooAbsBinning.h:84
A space to attach TBranches.
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
RooAbsRealLValue is the common abstract base class for objects that represent a real value that may a...
virtual double getMax(const char *name=0) const
Get maximum of currently defined range.
virtual double getMin(const char *name=0) 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:64
double getVal(const RooArgSet *normalisationSet=nullptr) const
Evaluate object.
Definition: RooAbsReal.h:94
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:57
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:45
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:67
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:100
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:31
std::vector< RooMsgService::StreamConfig > fOldConf
Definition: RooHelpers.h:58
static RooMsgService & instance()
Return reference to singleton instance.
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:130
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:61
MsgTopic
Topics for a RooMsgService::StreamConfig in RooMsgService.
Definition: RooGlobalFunc.h:63
@ InputArguments
Definition: RooGlobalFunc.h:64
bool checkIfRangesOverlap(RooAbsPdf const &pdf, 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:185
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:119
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:273
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:168
std::string getColonSeparatedNameString(RooArgSet const &argSet)
Create a string with all sorted names of RooArgSet elements separated by colons.
Definition: RooHelpers.cxx:252
static void output()