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