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