Crombie Tools
Uncertainty.h
Go to the documentation of this file.
1 #ifndef CROMBIE_UNCERTAINTY_H
2 #define CROMBIE_UNCERTAINTY_H
3 
4 #include <string>
5 #include <map>
6 #include <vector>
7 #include <istream>
8 #include <regex>
9 #include <algorithm>
10 #include <iterator>
11 
12 #include "crombie/Types.h"
13 #include "crombie/Debug.h"
14 #include "crombie/Misc.h"
15 #include "crombie/Parse.h"
16 
17 namespace crombie {
18  namespace Uncertainty {
19 
20  /**
21  The information to hold the information for a plotter to implement a single systematic plot
22  */
23  class SysInfo {
24  public:
25  SysInfo(const std::string& key, const std::string& suff, const unsigned bin = 1)
26  : key{key}, suff{suff}, bin{bin} {
27  Debug::Debug(__PRETTY_FUNCTION__, key, suff, bin);
28  }
29  std::string key {};
30  std::string suff {};
31  unsigned bin {};
32  };
33 
34 
36  public:
37  /**
38  Change the expression for an uncertainty given by the key.
39  @param key The name of the uncertainty switched to. This pulls out the branch name
40  @param inexpr The expression to change in order to match the uncertainty
41  @param suff The suffix to change to, typically "Up" or "Down", but can be any envelope expression too
42  */
43  std::string expr (const std::string& key, const std::string& inexpr, const std::string& suff) const;
44 
45  /// Get all the needed expressions to cover the loaded uncertainties, along with the original expressions
46  template<typename A, typename... Args> Types::strings exprs (A arg, Args... args) const;
47  Types::strings exprs (const Types::strings& args) const;
48  Types::strings exprs (const std::string& arg) const;
49 
50  /// Get a list of the uncertainty names
51  Types::strings systematics () const;
52 
53  /// Returns a list maintained by this object of parameters needed to implement all sysematics
54  const std::list<SysInfo>& full_systematic_infos () const { return full_infos; }
55 
56  private:
57  /// Key is the name of the uncertainty, the first member of the pair is how the branches are named.
59 
60  class Envelope {
61  public:
62  Envelope(const std::string& branch) : branch{branch} {}
63  /// Name of the branch to change in expressions
64  std::string branch;
65  ///< First element is the bin that is normalized, then new branch name
66  std::vector<std::pair<unsigned, std::string>> otherbranches {};
67  };
68 
69  /// Key is the name of the uncertainty, the first member of the pair is which bin to use for total events.
71  /// A central list of all the systematics needed to make plots. Maintained here to avoid needing to duplicate it.
72  std::list<SysInfo> full_infos;
73 
74  friend std::istream& operator>>(std::istream& is, UncertaintyInfo& config);
75  };
76 
77 
78  std::istream& operator>>(std::istream& is, UncertaintyInfo& config) {
79 
80  for (auto& line : Parse::parse(is)) {
81  Debug::Debug(__PRETTY_FUNCTION__, line);
82  // Check for shell input and tokenize line
83  auto tokens = Misc::tokenize(line);
84 
85  // Front token is the name
86 
87  // Get if envelope
88  bool is_env = tokens.front().back() == ':';
89  if (is_env) {
90  tokens.front().pop_back();
91  auto branchname = tokens.back();
92  // Go through rest of tokens
93  auto newenv = config.env_branches.insert({tokens.front(), {branchname}});
94  auto iter = tokens.begin();
95  for (auto splitpos = (++iter)->find(':');
96  iter != tokens.end() and splitpos != std::string::npos;
97  splitpos = (++iter)->find(':')) {
98 
99  unsigned bin = std::stoi(iter->substr(0, splitpos));
100  auto suff = iter->substr(splitpos+1);
101  newenv.first->second.otherbranches.emplace_back(bin, branchname + "_" + suff);
102 
103  config.full_infos.emplace_back(newenv.first->first, suff, bin);
104  }
105 
106  }
107  else { // If not envelope
108  auto eq_pos = tokens.front().find('=');
109  auto sysname = eq_pos == std::string::npos ? tokens.front() : tokens.front().substr(0, eq_pos);
110  auto branchname = eq_pos == std::string::npos ? tokens.front() : tokens.front().substr(eq_pos, tokens.front().size() - eq_pos);
111 
112  // Create the list of branches
113  Types::strings branches{};
114  auto iter = tokens.begin();
115  for (++iter; iter != tokens.end(); ++iter)
116  branches.push_back(*iter);
117 
118  config.updown_branches.insert({sysname, {branchname, std::move(branches)}});
119  for (auto& updown : {"Up", "Down"})
120  config.full_infos.emplace_back(sysname, updown);
121  }
122  }
123  return is;
124  }
125 
126 
127  /// Reads a configuration file and returns an UncertaintyInfo object
128  UncertaintyInfo read(const std::string& config) {
130  std::ifstream{config} >> unc;
131  return unc;
132  }
133 
134 
135  std::string UncertaintyInfo::expr(const std::string& key, const std::string& inexpr, const std::string& suff) const {
136  std::string output = inexpr;
137  std::string name {};
138  Types::strings branches {};
139 
140  bool isupdown = (suff == "Up" or suff == "Down");
141 
142  if (isupdown) {
143  auto& info = updown_branches.at(key);
144  name = info.first;
145  branches = info.second;
146  }
147  else
148  branches.push_back(env_branches.at(key).branch);
149 
150  for (auto& branch : branches) {
151  std::regex expr {std::string("\\b") + branch + "\\b"};
152  std::string replace = branch + '_' + name + suff;
153  output = std::regex_replace(output, expr, replace);
154  }
155 
156  return output;
157  }
158 
159 
160  Types::strings UncertaintyInfo::exprs(const std::string& arg) const {
161  Types::strings output{arg};
162  for (auto& sys : full_systematic_infos()) {
163  Debug::Debug(__PRETTY_FUNCTION__, sys.bin, sys.key, sys.suff);
164  auto check = expr(sys.key, arg, sys.suff);
165  if (check == arg)
166  continue;
167  output.push_back(std::move(check));
168  }
169  return output;
170  }
171 
172 
174  Types::strings output {};
175  for (auto& arg : args) {
176  auto single = exprs(arg);
177  output.insert(output.end(), std::make_move_iterator(single.begin()), std::make_move_iterator(single.end()));
178  }
179  return output;
180  }
181 
182 
183  template<typename A, typename... Args> Types::strings UncertaintyInfo::exprs(A arg, Args... args) const {
184  Types::strings output {};
185 
186  auto single = exprs(arg);
187  output.insert(output.end(), std::make_move_iterator(single.begin()), std::make_move_iterator(single.end()));
188 
189  auto more = exprs(args...);
190  output.insert(output.end(), std::make_move_iterator(more.begin()), std::make_move_iterator(more.end()));
191 
192  return output;
193  }
194 
195 
197  auto comp = [] (auto& branches) {
198  return Misc::comprehension<std::string>(branches, [] (auto& i) {return i.first;});
199  };
200 
201  auto output = comp(updown_branches);
202  auto other = comp(env_branches);
203 
204  output.insert(output.end(),
205  std::make_move_iterator(other.begin()),
206  std::make_move_iterator(other.end()));
207 
208  return output;
209  }
210 
211  }
212 }
213 
214 #endif