DESY Hbb Analysis Framework
JetResolutionObject.cc
Go to the documentation of this file.
1 // Original code: CMSSW_10_2_22 - CondFormats/JetMETObjects/src/JetResolutionObject.cc
2 
5 #include <exception>
6 
7 namespace edm {
8  namespace errors {
9  enum ErrorCode {
10  NotFound = 8026,
14  };
15  };
16 };
17 
18 #include <cmath>
19 #include <iostream>
20 #include <fstream>
21 #include <iomanip>
22 #include <algorithm>
23 
24 namespace JME {
25 
26  std::string getDefinitionLine(const std::string& line) {
27  size_t first = line.find ('{');
28  size_t last = line.find ('}');
29 
30  if (first != std::string::npos && last != std::string::npos && first < last)
31  return std::string(line, first + 1, last - first - 1);
32 
33  return "";
34  }
35 
36  void throwException(uint32_t code, const std::string& message) {
37  std::stringstream error;
38  error << message << " Error code: " << code;
39  throw std::runtime_error(error.str());
40  }
41 
42  const bimap<Binning, std::string> JetParameters::binning_to_string = {
43  {Binning::JetPt, "JetPt"}, {Binning::JetEta, "JetEta"},
44  {Binning::JetAbsEta, "JetAbsEta"}, {Binning::JetE, "JetE"},
45  {Binning::JetArea, "JetArea"}, {Binning::Mu, "Mu"},
46  {Binning::Rho, "Rho"}, {Binning::NPV, "NPV"}
47  };
48 
49  JetParameters::JetParameters(JetParameters&& rhs) {
50  m_values = std::move(rhs.m_values);
51  }
52 
53  JetParameters::JetParameters(std::initializer_list<typename value_type::value_type> init) {
54  for (auto& i: init) {
55  set(i.first, i.second);
56  }
57  }
58 
59  JetParameters& JetParameters::setJetPt(float pt) {
60  m_values[Binning::JetPt] = pt;
61  return *this;
62  }
63 
64  JetParameters& JetParameters::setJetEta(float eta) {
65  m_values[Binning::JetEta] = eta;
66  m_values[Binning::JetAbsEta] = fabs(eta);
67  return *this;
68  }
69 
70  JetParameters& JetParameters::setJetE(float e) {
71  m_values[Binning::JetE] = e;
72  return *this;
73  }
74 
75  JetParameters& JetParameters::setJetArea(float area) {
76  m_values[Binning::JetArea] = area;
77  return *this;
78  }
79 
80  JetParameters& JetParameters::setMu(float mu) {
81  m_values[Binning::Mu] = mu;
82  return *this;
83  }
84 
85  JetParameters& JetParameters::setNPV(float npv) {
86  m_values[Binning::NPV] = npv;
87  return *this;
88  }
89 
90  JetParameters& JetParameters::setRho(float rho) {
91  m_values[Binning::Rho] = rho;
92  return *this;
93  }
94 
95  JetParameters& JetParameters::set(const Binning& bin, float value) {
96  m_values.emplace(bin, value);
97 
98  // Special case for eta
99  if (bin == Binning::JetEta) {
100  m_values.emplace(Binning::JetAbsEta, fabs(value));
101  }
102 
103  return *this;
104  }
105 
106  JetParameters& JetParameters::set(const typename value_type::value_type& value) {
107  set(value.first, value.second);
108  return *this;
109  }
110 
111  std::vector<float> JetParameters::createVector(const std::vector<Binning>& binning) const {
112  std::vector<float> values;
113  for (const auto& bin: binning) {
114  const auto& it = m_values.find(bin);
115  if (it == m_values.cend()) {
116  throwException(edm::errors::NotFound, "JER parametrisation depends on '" +
117  JetParameters::binning_to_string.left.at(bin) +
118  "' but no value for this parameter has been specified. Please call the appropriate 'set' function of the JME::JetParameters object");
119  }
120 
121  values.push_back(it->second);
122  }
123 
124  return values;
125  }
126 
127 
128  JetResolutionObject::Definition::Definition(const std::string& definition) {
129 
130  std::vector<std::string> tokens = getTokens(definition);
131 
132  // We need at least 3 tokens
133  if (tokens.size() < 3) {
134  throwException(edm::errors::ConfigFileReadError, "Definition line needs at least three tokens. Please check file format.");
135  }
136 
137  size_t n_bins = std::stoul(tokens[0]);
138 
139  if (tokens.size() < (n_bins + 2)) {
140  throwException(edm::errors::ConfigFileReadError, "Invalid file format. Please check.");
141  }
142 
143  for (size_t i = 0; i < n_bins; i++) {
144  m_bins_name.push_back(tokens[i + 1]);
145  }
146 
147  size_t n_variables = std::stoul(tokens[n_bins + 1]);
148 
149  if (tokens.size() < (1 + n_bins + 1 + n_variables + 1)) {
150  throwException(edm::errors::ConfigFileReadError, "Invalid file format. Please check.");
151  }
152 
153  for (size_t i = 0; i < n_variables; i++) {
154  m_variables_name.push_back(tokens[n_bins + 2 + i]);
155  }
156 
157  m_formula_str = tokens[n_bins + n_variables + 2];
158 
159  std::string formula_str_lower = m_formula_str;
160  std::transform(formula_str_lower.begin(), formula_str_lower.end(), formula_str_lower.begin(), ::tolower);
161 
162  if (formula_str_lower == "none") {
163  m_formula_str = "";
164 
165  if ((tokens.size() > n_bins + n_variables + 3) && (std::atoi(tokens[n_bins + n_variables + 3].c_str()))) {
166  size_t n_parameters = std::stoul(tokens[n_bins + n_variables + 3]);
167 
168  if (tokens.size() < (1 + n_bins + 1 + n_variables + 1 + 1 + n_parameters)) {
169  throwException(edm::errors::ConfigFileReadError, "Invalid file format. Please check.");
170  }
171 
172  for (size_t i = 0; i < n_parameters; i++) {
173  m_formula_str += tokens[n_bins + n_variables + 4 + i] + " ";
174  }
175  }
176  }
177 
178  init();
179  }
180 
181  void JetResolutionObject::Definition::init() {
182  if (!m_formula_str.empty()) {
183  if (m_formula_str.find(' ') == std::string::npos)
184  m_formula = std::make_shared<TFormula>("jet_resolution_formula", m_formula_str.c_str());
185  else
186  m_parameters_name = getTokens(m_formula_str);
187  }
188  for (const auto& bin: m_bins_name) {
189  const auto& b = JetParameters::binning_to_string.right.find(bin);
190  if (b == JetParameters::binning_to_string.right.cend()) {
191  throwException(edm::errors::UnimplementedFeature, "Bin name not supported: '" + bin + "'");
192  }
193  m_bins.push_back(b->second);
194  }
195 
196  for (const auto& v: m_variables_name) {
197  const auto& var = JetParameters::binning_to_string.right.find(v);
198  if (var == JetParameters::binning_to_string.right.cend()) {
199  throwException(edm::errors::UnimplementedFeature, "Variable name not supported: '" + v + "'");
200  }
201  m_variables.push_back(var->second);
202  }
203  }
204 
205  JetResolutionObject::Record::Record(const std::string& line, const Definition& def) {
206 
207  std::vector<std::string> tokens = getTokens(line);
208 
209  if (tokens.size() < (def.nBins() * 2 + def.nVariables() * 2 + 1)) {
210  throwException(edm::errors::ConfigFileReadError, "Invalid record. Please check file format. Record: " + line);
211  }
212 
213  size_t pos = 0;
214 
215  for (size_t i = 0; i < def.nBins(); i++) {
216  Range r(std::stof(tokens[pos]), std::stof(tokens[pos + 1]));
217  pos += 2;
218  m_bins_range.push_back(r);
219  }
220 
221  size_t n_parameters = std::stoul(tokens[pos++]);
222 
223  if (tokens.size() < (def.nBins() * 2 + def.nVariables() * 2 + 1 + (n_parameters - def.nVariables() * 2))) {
224  throwException(edm::errors::ConfigFileReadError, "Invalid record. Please check file format. Record: " + line);
225  }
226 
227  for (size_t i = 0; i < def.nVariables(); i++) {
228  Range r(std::stof(tokens[pos]), std::stof(tokens[pos + 1]));
229  pos += 2;
230  m_variables_range.push_back(r);
231  n_parameters -= 2;
232  }
233 
234  for (size_t i = 0; i < n_parameters; i++) {
235  m_parameters_values.push_back(std::stof(tokens[pos++]));
236  }
237  }
238 
239  JetResolutionObject::JetResolutionObject(const std::string& filename) {
240 
241  // Parse file
242  std::ifstream f(filename);
243 
244  if (! f.good()) {
245  throwException(edm::errors::FileReadError, "Can't read input file '" + filename + "'");
246  }
247 
248  for (std::string line; std::getline(f, line); ) {
249  if ((line.empty()) || (line[0] == '#'))
250  continue;
251 
252  std::string definition = getDefinitionLine(line);
253 
254  if (!definition.empty()) {
255  m_definition = Definition(definition);
256  } else {
257  m_records.push_back(Record(line, m_definition));
258  }
259  }
260 
261  m_valid = true;
262  }
263 
264  JetResolutionObject::JetResolutionObject(const JetResolutionObject& object) {
265  m_definition = object.m_definition;
266  m_records = object.m_records;
267  m_valid = object.m_valid;
268 
269  m_definition.init();
270  }
271 
272  JetResolutionObject::JetResolutionObject() {
273  // Empty
274  }
275 
276 
277  void JetResolutionObject::dump() const {
278  std::cout << "Definition: " << std::endl;
279  std::cout << " Number of binning variables: " << m_definition.nBins() << std::endl;
280  std::cout << " ";
281  for (const auto& bin: m_definition.getBinsName()) {
282  std::cout << bin << ", ";
283  }
284  std::cout << std::endl;
285  std::cout << " Number of variables: " << m_definition.nVariables() << std::endl;
286  std::cout << " ";
287  for (const auto& bin: m_definition.getVariablesName()) {
288  std::cout << bin << ", ";
289  }
290  std::cout << std::endl;
291  std::cout << " Formula: " << m_definition.getFormulaString() << std::endl;
292 
293  std::cout << std::endl << "Bin contents" << std::endl;
294 
295  for (const auto& record: m_records) {
296  std::cout << " Bins" << std::endl;
297  size_t index = 0;
298  for (const auto& bin: record.getBinsRange()) {
299  std::cout << " " << m_definition.getBinName(index) << " [" << bin.min << " - " << bin.max << "]" << std::endl;
300  index++;
301  }
302 
303  std::cout << " Variables" << std::endl;
304  index = 0;
305  for (const auto& r: record.getVariablesRange()) {
306  std::cout << " " << m_definition.getVariableName(index) << " [" << r.min << " - " << r.max << "] " << std::endl;
307  index++;
308  }
309 
310  std::cout << " Parameters" << std::endl;
311  index = 0;
312  for (const auto& par: record.getParametersValues()) {
313  std::cout << " Parameter #" << index << " = " << par << std::endl;
314  index++;
315  }
316  }
317  }
318 
319  void JetResolutionObject::saveToFile(const std::string& file) const {
320 
321  std::ofstream fout(file);
322  fout.setf(std::ios::right);
323 
324  // Definition
325  fout << "{" << m_definition.nBins();
326 
327  for (auto& bin: m_definition.getBinsName())
328  fout << " " << bin;
329 
330  fout << " " << m_definition.nVariables();
331 
332  for (auto& var: m_definition.getVariablesName())
333  fout << " " << var;
334 
335  fout << " " << (m_definition.getFormulaString().empty() ? "None" : m_definition.getFormulaString()) << " Resolution}" << std::endl;
336 
337  // Records
338  for (auto& record: m_records) {
339  for (auto& r: record.getBinsRange()) {
340  fout << std::left << std::setw(15) << r.min << std::setw(15) << r.max << std::setw(15);
341  }
342  fout << (record.nVariables() * 2 + record.nParameters()) << std::setw(15);
343 
344  for (auto& r: record.getVariablesRange()) {
345  fout << r.min << std::setw(15) << r.max << std::setw(15);
346  }
347 
348  for (auto& p: record.getParametersValues()) {
349  fout << p << std::setw(15);
350  }
351 
352  fout << std::endl << std::setw(0);
353  }
354 
355  }
356 
357  const JetResolutionObject::Record* JetResolutionObject::getRecord(const JetParameters& bins_parameters) const {
358  // Find record for bins
359  if (! m_valid)
360  return nullptr;
361 
362  // Create vector of bins value. Throw if some values are missing
363  std::vector<float> bins = bins_parameters.createVector(m_definition.getBins());
364 
365  // Iterate over all records, and find the one for which all bins are valid
366  const Record* good_record = nullptr;
367  for (const auto& record: m_records) {
368 
369  // Iterate over bins
370  size_t valid_bins = 0;
371  size_t current_bin = 0;
372  for (const auto& bin: record.getBinsRange()) {
373  if (bin.is_inside(bins[current_bin]))
374  valid_bins++;
375 
376  current_bin++;
377  }
378 
379  if (valid_bins == m_definition.nBins()) {
380  good_record = &record;
381  break;
382  }
383  }
384 
385  return good_record;
386  }
387 
388  float JetResolutionObject::evaluateFormula(const JetResolutionObject::Record& record, const JetParameters& variables_parameters) const {
389 
390  if (! m_valid)
391  return 1;
392 
393  // Set parameters
394  auto const* pFormula = m_definition.getFormula();
395  if (! pFormula)
396  return 1;
397  auto formula = *pFormula;
398  // Create vector of variables value. Throw if some values are missing
399  std::vector<float> variables = variables_parameters.createVector(m_definition.getVariables());
400 
401  double variables_[4] = {0};
402  for (size_t index = 0; index < m_definition.nVariables(); index++) {
403  variables_[index] = clip(variables[index], record.getVariablesRange()[index].min, record.getVariablesRange()[index].max);
404  }
405  const std::vector<float>& parameters = record.getParametersValues();
406 
407  for (size_t index = 0; index < parameters.size(); index++) {
408  formula.SetParameter(index, parameters[index]);
409  }
410 
411  return formula.EvalPar(variables_);
412  }
413 }
T clip(const T &n, const T &lower, const T &upper)
const std::vector< Range > & getVariablesRange() const
std::vector< float > createVector(const std::vector< Binning > &binning) const
std::string getDefinitionLine(const std::string &line)
const std::vector< float > & getParametersValues() const
TFile * f[10]
Definition: PlotsCompare.cc:24
void throwException(uint32_t code, const std::string &message)