CombineHarvester
Utilities.cc
Go to the documentation of this file.
2 #include <iostream>
3 #include <vector>
4 #include <set>
5 #include <string>
6 #include <fstream>
7 #include <map>
8 #include "boost/format.hpp"
9 #include "RooFitResult.h"
10 #include "RooRealVar.h"
11 #include "RooDataHist.h"
12 #include "RooAbsReal.h"
13 #include "RooAbsData.h"
15 
16 namespace ch {
17 
18 RooArgSet ParametersByName(RooAbsReal const* pdf, RooArgSet const* dat_vars) {
19  // Get all pdf parameters first
20  // We are expected to manage the memory of the RooArgSet pointer we're given,
21  // so let's use a unique_ptr to ensure it gets cleaned up
22  std::unique_ptr<RooArgSet> all_vars(pdf->getParameters(RooArgSet()));
23  // Get the data variables and fill a set with all the names
24  std::set<std::string> names;
25  RooFIter dat_it = dat_vars->fwdIterator();
26  RooAbsArg *dat_arg = nullptr;
27  while((dat_arg = dat_it.next())) {
28  names.insert(dat_arg->GetName());
29  }
30 
31  // Build a new RooArgSet from all_vars, excluding any in names
32  RooArgSet result_set;
33  RooFIter vars_it = all_vars->fwdIterator();
34  RooAbsArg *vars_arg = nullptr;
35  while((vars_arg = vars_it.next())) {
36  if (!names.count(vars_arg->GetName())) {
37  result_set.add(*vars_arg);
38  }
39  }
40  return result_set;
41 }
42 
43 // ---------------------------------------------------------------------------
44 // Paramter extraction/manipulation
45 // ---------------------------------------------------------------------------
46 std::vector<ch::Parameter> ExtractFitParameters(RooFitResult const& res) {
47  std::vector<ch::Parameter> params;
48  params.resize(res.floatParsFinal().getSize());
49  for (int i = 0; i < res.floatParsFinal().getSize(); ++i) {
50  RooRealVar const* var =
51  dynamic_cast<RooRealVar const*>(res.floatParsFinal().at(i));
52  params[i].set_name(std::string(var->GetName()));
53  params[i].set_val(var->getVal());
54  params[i].set_err_d(var->getErrorLo());
55  params[i].set_err_u(var->getErrorHi());
56  }
57  return params;
58 }
59 
60 std::vector<ch::Parameter> ExtractSampledFitParameters(
61  RooFitResult const& res) {
62  std::vector<ch::Parameter> params;
63  params.resize(res.floatParsFinal().getSize());
64  RooArgList const& rands = res.randomizePars();
65  for (int i = 0; i < res.floatParsFinal().getSize(); ++i) {
66  RooRealVar const* var = dynamic_cast<RooRealVar const*>(rands.at(i));
67  params[i].set_name(std::string(var->GetName()));
68  params[i].set_val(var->getVal());
69  params[i].set_err_d(var->getErrorLo());
70  params[i].set_err_u(var->getErrorHi());
71  }
72  return params;
73 }
74 
75 // ---------------------------------------------------------------------------
76 // Property matching & editing
77 // ---------------------------------------------------------------------------
78 void SetStandardBinNames(CombineHarvester& cb, std::string const& pattern) {
79  cb.ForEachObj([&](ch::Object* obj) {
80  ch::SetStandardBinName(obj, pattern);
81  });
82 }
83 
84 void SetStandardBinName(ch::Object* obj, std::string pattern) {
85  boost::replace_all(pattern, "$BINID",
86  boost::lexical_cast<std::string>(obj->bin_id()));
87  boost::replace_all(pattern, "$BIN", obj->bin());
88  boost::replace_all(pattern, "$PROCESS", obj->process());
89  boost::replace_all(pattern, "$MASS", obj->mass());
90  boost::replace_all(pattern, "$ERA", obj->era());
91  boost::replace_all(pattern, "$CHANNEL", obj->channel());
92  boost::replace_all(pattern, "$ANALYSIS", obj->analysis());
93  obj->set_bin(pattern);
94 }
95 
96 void SetFromBinName(ch::Object *input, std::string parse_rules) {
97  boost::replace_all(parse_rules, "$ANALYSIS", "(?<ANALYSIS>\\w+)");
98  boost::replace_all(parse_rules, "$ERA", "(?<ERA>\\w+)");
99  boost::replace_all(parse_rules, "$CHANNEL", "(?<CHANNEL>\\w+)");
100  boost::replace_all(parse_rules, "$BINID", "(?<BINID>\\w+)");
101  boost::replace_all(parse_rules, "$MASS", "(?<MASS>\\w+)");
102  boost::regex rgx(parse_rules);
103  boost::smatch matches;
104  boost::regex_search(input->bin(), matches, rgx);
105  if (matches.str("ANALYSIS").length())
106  input->set_analysis(matches.str("ANALYSIS"));
107  if (matches.str("ERA").length())
108  input->set_era(matches.str("ERA"));
109  if (matches.str("CHANNEL").length())
110  input->set_channel(matches.str("CHANNEL"));
111  if (matches.str("BINID").length())
112  input->set_bin_id(boost::lexical_cast<int>(matches.str("BINID")));
113  if (matches.str("MASS").length())
114  input->set_mass(matches.str("MASS"));
115 }
116 
117 
118 // ---------------------------------------------------------------------------
119 // Rate scaling
120 // ---------------------------------------------------------------------------
121 TGraph TGraphFromTable(std::string filename, std::string const& x_column, std::string const& y_column) {
122  auto lines = ch::ParseFileLines(filename);
123  if (lines.size() == 0) throw std::runtime_error(FNERROR("Table is empty"));
124  std::vector<std::string> fields;
125  boost::split(fields, lines[0], boost::is_any_of("\t "),
126  boost::token_compress_on);
127  auto x_it = std::find(fields.begin(), fields.end(), x_column);
128  if (x_it == fields.end())
129  throw std::runtime_error(FNERROR("No column with label " + x_column));
130  auto y_it = std::find(fields.begin(), fields.end(), y_column);
131  if (y_it == fields.end())
132  throw std::runtime_error(FNERROR("No column with label " + y_column));
133  unsigned x_col(x_it - fields.begin());
134  unsigned y_col(y_it - fields.begin());
135  TGraph res(lines.size() - 1);
136  for (unsigned i = 1; i < lines.size(); ++i) {
137  std::vector<std::string> words;
138  boost::split(words, lines[i], boost::is_any_of("\t "),
139  boost::token_compress_on);
140  if (words.size() != fields.size()) {
141  FNLOG(std::cout) << "Skipped this line:\n" << lines[i] << "\n";
142  continue;
143  }
144  res.SetPoint(i, boost::lexical_cast<double>(words.at(x_col)),
145  boost::lexical_cast<double>(words.at(y_col)));
146  }
147  return res;
148 }
149 
150 // ---------------------------------------------------------------------------
151 // Misc
152 // ---------------------------------------------------------------------------
153 std::vector<std::string> JoinStr(
154  std::vector<std::vector<std::string>> const& in) {
155  return Join<std::string>(in);
156 }
157 
158 RooDataHist TH1F2Data(TH1F const& hist, RooRealVar const& x,
159  std::string const& name) {
160  TH1F shape("tmp", "tmp", hist.GetNbinsX(), 0.,
161  static_cast<float>(hist.GetNbinsX()));
162  for (int i = 1; i <= hist.GetNbinsX(); ++i) {
163  shape.SetBinContent(i, hist.GetBinContent(i));
164  }
165  RooDataHist dh(name.c_str(), name.c_str(),
166  RooArgList(x), RooFit::Import(shape, false));
167  return dh;
168 }
169 
170 TH1F RebinHist(TH1F const& hist) {
171  TH1::AddDirectory(0);
172  TH1F shape("tmp", "tmp", hist.GetNbinsX(), 0.,
173  static_cast<float>(hist.GetNbinsX()));
174  for (int i = 1; i <= hist.GetNbinsX(); ++i) {
175  shape.SetBinContent(i, hist.GetBinContent(i));
176  shape.SetBinError(i, hist.GetBinError(i));
177  }
178  return shape;
179 }
180 
181 TH1F RestoreBinning(TH1F const& src, TH1F const& ref) {
182  TH1F res = ref;
183  res.Reset();
184  for (int x = 1; x <= res.GetNbinsX(); ++x) {
185  res.SetBinContent(x, src.GetBinContent(x));
186  res.SetBinError(x, src.GetBinError(x));
187  }
188  return res;
189 }
190 
191 std::vector<std::vector<unsigned>> GenerateCombinations(
192  std::vector<unsigned> vec) {
193  unsigned n = vec.size();
194  std::vector<unsigned> idx(n, 0);
195  std::vector<std::vector<unsigned>> result;
196  // if any one of the elements is zero there are no
197  // combinations to build
198  if (std::find(vec.begin(), vec.end(), 0) != vec.end()) {
199  return result;
200  }
201  result.push_back(idx);
202  bool exit_loop = false;
203  while (exit_loop == false) {
204  // Find the first index we can increment (if possible)
205  for (unsigned i = 0; i < n; ++i) {
206  if ((idx[i] + 1) == vec[i]) {
207  if (i != n - 1) {
208  idx[i] = 0;
209  } else {
210  // we're done
211  exit_loop = true;
212  break;
213  }
214  } else {
215  ++(idx[i]);
216  result.push_back(idx);
217  break;
218  }
219  }
220  }
221  return result;
222 }
223 
224 std::vector<std::string> ParseFileLines(std::string const& file_name) {
225  // Build a vector of input files
226  std::vector<std::string> files;
227  std::ifstream file;
228  file.open(file_name.c_str());
229  if (!file.is_open()) {
230  throw std::runtime_error(
231  FNERROR("File " + file_name + " could not be opened"));
232  }
233  std::string line = "";
234  while (std::getline(file, line)) { // while loop through lines
235  files.push_back(line);
236  }
237  file.close();
238  return files;
239 }
240 
241 bool is_float(std::string const& str) {
242  std::istringstream iss(str);
243  float f;
244  iss >> std::noskipws >> f; // noskipws considers leading whitespace invalid
245  // Check the entire string was consumed and if either failbit or badbit is set
246  return iss.eof() && !iss.fail();
247 }
248 
249 std::vector<std::string> MassesFromRange(std::string const& input,
250  std::string const& fmt) {
251  std::set<double> mass_set;
252  std::vector<std::string> tokens;
253  boost::split(tokens, input, boost::is_any_of(","));
254  for (auto const& t : tokens) {
255  std::vector<std::string> sub_tokens;
256  boost::split(sub_tokens, t, boost::is_any_of("-:"));
257  if (sub_tokens.size() == 1) {
258  double mass_val = boost::lexical_cast<double>(sub_tokens[0]);
259  mass_set.insert(mass_val);
260  } else if (sub_tokens.size() == 3) {
261  double lo = boost::lexical_cast<double>(sub_tokens[0]);
262  double hi = boost::lexical_cast<double>(sub_tokens[1]);
263  double step = boost::lexical_cast<double>(sub_tokens[2]);
264  if (hi <= lo)
265  throw std::runtime_error(
266  "[MassesFromRange] High mass is smaller than low mass!");
267  double start = lo;
268  while (start < hi + 0.001) {
269  mass_set.insert(start);
270  start += step;
271  }
272  }
273  }
274  std::vector<std::string> result;
275  for (auto const& m : mass_set) {
276  result.push_back((boost::format(fmt) % m).str());
277  }
278  return result;
279 }
280 
281 std::vector<std::string> ValsFromRange(std::string const& input,
282  std::string const& fmt) {
283  std::set<double> mass_set;
284  std::vector<std::string> tokens;
285  boost::split(tokens, input, boost::is_any_of(","));
286  for (auto const& t : tokens) {
287  std::vector<std::string> sub_tokens;
288  boost::split(sub_tokens, t, boost::is_any_of(":|"));
289  if (sub_tokens.size() == 1) {
290  double mass_val = boost::lexical_cast<double>(sub_tokens[0]);
291  mass_set.insert(mass_val);
292  } else if (sub_tokens.size() == 3) {
293  double lo = boost::lexical_cast<double>(sub_tokens[0]);
294  double hi = boost::lexical_cast<double>(sub_tokens[1]);
295  double step = boost::lexical_cast<double>(sub_tokens[2]);
296  if (hi <= lo)
297  throw std::runtime_error(
298  "[ValsFromRange] High mass is smaller than low mass!");
299  double start = lo;
300  while (start < hi + 1E-4) {
301  mass_set.insert(start);
302  start += step;
303  }
304  }
305  }
306  std::vector<std::string> result;
307  for (auto const& m : mass_set) {
308  result.push_back((boost::format(fmt) % m).str());
309  }
310  return result;
311 }
312 
313 boost::filesystem::path make_relative(boost::filesystem::path p_from,
314  boost::filesystem::path p_to) {
315  p_from = boost::filesystem::absolute(p_from);
316  p_to = boost::filesystem::absolute(p_to);
317  boost::filesystem::path ret;
318  boost::filesystem::path::const_iterator itrFrom(p_from.begin()),
319  itrTo(p_to.begin());
320  // Find common base
321  for (boost::filesystem::path::const_iterator toEnd(p_to.end()),
322  fromEnd(p_from.end());
323  itrFrom != fromEnd && itrTo != toEnd && *itrFrom == *itrTo;
324  ++itrFrom, ++itrTo);
325  // Navigate backwards in directory to reach previously found base
326  for (boost::filesystem::path::const_iterator fromEnd(p_from.end());
327  itrFrom != fromEnd; ++itrFrom) {
328  if ((*itrFrom) != ".") ret /= "..";
329  }
330  // Now navigate down the directory branch
331  // ret.append(itrTo, p_to.end());
332  for (boost::filesystem::path::const_iterator toEnd(p_to.end());
333  itrTo != toEnd; ++itrTo) {
334  ret /= *itrTo;
335  }
336  return ret;
337 }
338 
339 bool HasNegativeBins(TH1 const* h) {
340  bool has_negative = false;
341  for (int i = 1; i <= h->GetNbinsX(); ++i) {
342  if (h->GetBinContent(i) < 0.) {
343  has_negative = true;
344  }
345  }
346  return has_negative;
347 }
348 
349 void ZeroNegativeBins(TH1 *h) {
350  for (int i = 1; i <= h->GetNbinsX(); ++i) {
351  if (h->GetBinContent(i) < 0.) {
352  h->SetBinContent(i, 0.);
353  }
354  }
355 }
356 }
#define FNERROR(x)
Definition: Logging.h:9
#define FNLOG(x)
Definition: Logging.h:13
void ForEachObj(Function func)
virtual void set_analysis(std::string const &analysis)
Definition: Object.h:25
virtual void set_mass(std::string const &mass)
Definition: Object.h:37
virtual std::string const & process() const
Definition: Object.h:20
virtual void set_bin(std::string const &bin)
Definition: Object.h:16
virtual std::string const & bin() const
Definition: Object.h:17
virtual int bin_id() const
Definition: Object.h:35
virtual std::string const & analysis() const
Definition: Object.h:26
virtual std::string const & era() const
Definition: Object.h:29
virtual std::string const & mass() const
Definition: Object.h:38
virtual void set_era(std::string const &era)
Definition: Object.h:28
virtual std::string const & channel() const
Definition: Object.h:32
virtual void set_channel(std::string const &channel)
Definition: Object.h:31
virtual void set_bin_id(int const &bin_id)
Definition: Object.h:34
Definition: Algorithm.h:10
RooDataHist TH1F2Data(TH1F const &hist, RooRealVar const &x, std::string const &name)
Definition: Utilities.cc:158
void SetStandardBinName(ch::Object *obj, std::string pattern)
Definition: Utilities.cc:84
std::vector< std::string > ParseFileLines(std::string const &file_name)
Definition: Utilities.cc:224
TH1F RestoreBinning(TH1F const &src, TH1F const &ref)
Definition: Utilities.cc:181
TH1F RebinHist(TH1F const &hist)
Definition: Utilities.cc:170
boost::filesystem::path make_relative(boost::filesystem::path p_from, boost::filesystem::path p_to)
Determine the relative path from one file to another.
Definition: Utilities.cc:313
std::vector< ch::Parameter > ExtractFitParameters(RooFitResult const &res)
Definition: Utilities.cc:46
bool HasNegativeBins(TH1 const *h)
Definition: Utilities.cc:339
TGraph TGraphFromTable(std::string filename, std::string const &x_column, std::string const &y_column)
Definition: Utilities.cc:121
std::vector< std::vector< unsigned > > GenerateCombinations(std::vector< unsigned > vec)
Definition: Utilities.cc:191
void SetStandardBinNames(CombineHarvester &cb, std::string const &pattern="$ANALYSIS_$CHANNEL_$BINID_$ERA")
Definition: Utilities.cc:78
std::vector< std::string > MassesFromRange(std::string const &input, std::string const &fmt="%.0f")
Generate a vector of mass values using ranges and intervals specified in a string.
Definition: Utilities.cc:249
std::vector< ch::Parameter > ExtractSampledFitParameters(RooFitResult const &res)
Definition: Utilities.cc:60
std::vector< std::string > ValsFromRange(std::string const &input, std::string const &fmt="%.0f")
Generate a vector of values using ranges and intervals specified in a string.
Definition: Utilities.cc:281
std::vector< std::string > JoinStr(std::vector< std::vector< std::string >> const &in)
Definition: Utilities.cc:153
bool is_float(std::string const &str)
Definition: Utilities.cc:241
void ZeroNegativeBins(TH1 *h)
Definition: Utilities.cc:349
RooArgSet ParametersByName(RooAbsReal const *pdf, RooArgSet const *dat_vars)
Definition: Utilities.cc:18
void SetFromBinName(ch::Object *input, std::string parse_rules)
Definition: Utilities.cc:96