Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
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 {const_cast<RooAbsPdf *>(&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 const &>(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
291 // passed to the slave calculator
292 return {static_cast<RooAbsPdf *>(component), false};
293 }
294 }
295 }
296 return {nullptr, false};
297}
298
299/// Get the topologically-sorted list of all nodes in the computation graph.
301{
302 // Get the set of nodes in the computation graph. Do the detour via
303 // RooArgList to avoid deduplication done after adding each element.
304 RooArgList serverList;
305 func.treeNodeServerList(&serverList, nullptr, true, true, false, true);
306 // If we fill the servers in reverse order, they are approximately in
307 // topological order so we save a bit of work in sortTopologically().
308 out.add(serverList.rbegin(), serverList.rend(), /*silent=*/true);
309 // Sort nodes topologically: the servers of any node will be before that
310 // node in the collection.
311 out.sortTopologically();
312}
313
314}
#define oocoutW(o, a)
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:74
bool getAttribute(const Text_t *name) const
Check if a named attribute is set. By default, all attributes are unset.
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...
RooAbsBinning is the abstract base class for RooRealVar binning definitions.
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:409
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: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:55
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.
std::vector< RooMsgService::StreamConfig > _oldConf
Definition RooHelpers.h:89
~HijackMessageStream()
Deregister the hijacked stream and restore the stream state of all previous streams.
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.
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:4874
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.
MsgLevel
Verbosity level for RooMsgService::StreamConfig in RooMsgService.
MsgTopic
Topics for a RooMsgService::StreamConfig in RooMsgService.
void getSortedComputationGraph(RooAbsReal const &func, RooArgSet &out)
Get the topologically-sorted list of all nodes in the computation graph.
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.
std::string getRangeNameForSimComponent(std::string const &rangeName, bool splitRange, std::string const &catName)
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.
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.
BinnedLOutput getBinnedL(RooAbsPdf const &pdf)
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.
std::string getColonSeparatedNameString(RooArgSet const &argSet)
Create a string with all sorted names of RooArgSet elements separated by colons.
static void output()