Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-04-06 12:02:18

0001 #ifndef STANDALONE
0002 #include <CondFormats/JetMETObjects/interface/JetResolutionObject.h>
0003 #include <CondFormats/JetMETObjects/interface/Utilities.h>
0004 #include <FWCore/Utilities/interface/EDMException.h>
0005 
0006 #else
0007 #include "JetResolutionObject.h"
0008 #include "Utilities.h"
0009 #include <exception>
0010 
0011 namespace edm {
0012   namespace errors {
0013     enum ErrorCode { NotFound = 8026, ConfigFileReadError = 7002, UnimplementedFeature = 8011, FileReadError = 8021 };
0014   };
0015 };  // namespace edm
0016 #endif
0017 
0018 #include <cmath>
0019 #include <iostream>
0020 #include <fstream>
0021 #include <iomanip>
0022 #include <algorithm>
0023 
0024 namespace JME {
0025 
0026   std::string getDefinitionLine(const std::string& line) {
0027     size_t first = line.find('{');
0028     size_t last = line.find('}');
0029 
0030     if (first != std::string::npos && last != std::string::npos && first < last)
0031       return std::string(line, first + 1, last - first - 1);
0032 
0033     return "";
0034   }
0035 
0036   void throwException(uint32_t code, const std::string& message) {
0037 #ifndef STANDALONE
0038     throw edm::Exception(static_cast<edm::errors::ErrorCodes>(code), message);
0039 #else
0040     std::stringstream error;
0041     error << message << " Error code: " << code;
0042     throw std::runtime_error(error.str());
0043 
0044 #endif
0045   }
0046 
0047   const bimap<Binning, std::string> JetParameters::binning_to_string = {{Binning::JetPt, "JetPt"},
0048                                                                         {Binning::JetEta, "JetEta"},
0049                                                                         {Binning::JetAbsEta, "JetAbsEta"},
0050                                                                         {Binning::JetE, "JetE"},
0051                                                                         {Binning::JetArea, "JetArea"},
0052                                                                         {Binning::Mu, "Mu"},
0053                                                                         {Binning::Rho, "Rho"},
0054                                                                         {Binning::NPV, "NPV"}};
0055 
0056   JetParameters::JetParameters(JetParameters&& rhs) { m_values = std::move(rhs.m_values); }
0057 
0058   JetParameters::JetParameters(std::initializer_list<typename value_type::value_type> init) {
0059     for (auto& i : init) {
0060       set(i.first, i.second);
0061     }
0062   }
0063 
0064   JetParameters& JetParameters::setJetPt(float pt) {
0065     m_values[Binning::JetPt] = pt;
0066     return *this;
0067   }
0068 
0069   JetParameters& JetParameters::setJetEta(float eta) {
0070     m_values[Binning::JetEta] = eta;
0071     m_values[Binning::JetAbsEta] = fabs(eta);
0072     return *this;
0073   }
0074 
0075   JetParameters& JetParameters::setJetE(float e) {
0076     m_values[Binning::JetE] = e;
0077     return *this;
0078   }
0079 
0080   JetParameters& JetParameters::setJetArea(float area) {
0081     m_values[Binning::JetArea] = area;
0082     return *this;
0083   }
0084 
0085   JetParameters& JetParameters::setMu(float mu) {
0086     m_values[Binning::Mu] = mu;
0087     return *this;
0088   }
0089 
0090   JetParameters& JetParameters::setNPV(float npv) {
0091     m_values[Binning::NPV] = npv;
0092     return *this;
0093   }
0094 
0095   JetParameters& JetParameters::setRho(float rho) {
0096     m_values[Binning::Rho] = rho;
0097     return *this;
0098   }
0099 
0100   JetParameters& JetParameters::set(const Binning& bin, float value) {
0101     m_values.emplace(bin, value);
0102 
0103     // Special case for eta
0104     if (bin == Binning::JetEta) {
0105       m_values.emplace(Binning::JetAbsEta, fabs(value));
0106     }
0107 
0108     return *this;
0109   }
0110 
0111   JetParameters& JetParameters::set(const typename value_type::value_type& value) {
0112     set(value.first, value.second);
0113     return *this;
0114   }
0115 
0116   std::vector<float> JetParameters::createVector(const std::vector<Binning>& binning) const {
0117     std::vector<float> values;
0118 
0119     for (const auto& bin : binning) {
0120       const auto& it = m_values.find(bin);
0121       if (it == m_values.cend()) {
0122         throwException(edm::errors::NotFound,
0123                        "JER parametrisation depends on '" + JetParameters::binning_to_string.left.at(bin) +
0124                            "' but no value for this parameter has been specified. Please call the appropriate 'set' "
0125                            "function of the JME::JetParameters object");
0126       }
0127 
0128       values.push_back(it->second);
0129     }
0130 
0131     return values;
0132   }
0133 
0134   std::vector<float> JetParameters::createVector(const std::vector<std::string>& binname) const {
0135     std::vector<float> values;
0136 
0137     for (const auto& name : binname) {
0138       Binning bi = binning_to_string.right.find(name)->second;
0139 
0140       const auto& it = m_values.find(bi);
0141       if (it == m_values.cend()) {
0142         edm::LogPrint("JPM") << "Bin name " << name << " not found!";
0143         throwException(edm::errors::NotFound,
0144                        "JER parametrisation depends on '" + JetParameters::binning_to_string.left.at(bi) +
0145                            "' but no value for this parameter has been specified. Please call the appropriate 'set' "
0146                            "function of the JME::JetParameters object");
0147       }
0148 
0149       values.push_back(it->second);
0150     }
0151 
0152     return values;
0153   }
0154 
0155   JetResolutionObject::Definition::Definition(const std::string& definition) {
0156     std::vector<std::string> tokens = getTokens(definition);
0157 
0158     // We need at least 3 tokens
0159     if (tokens.size() < 3) {
0160       throwException(edm::errors::ConfigFileReadError,
0161                      "Definition line needs at least three tokens. Please check file format.");
0162     }
0163 
0164     size_t n_bins = std::stoul(tokens[0]);
0165 
0166     if (tokens.size() < (n_bins + 2)) {
0167       throwException(edm::errors::ConfigFileReadError, "Invalid file format. Please check.");
0168     }
0169 
0170     for (size_t i = 0; i < n_bins; i++) {
0171       m_bins_name.push_back(tokens[i + 1]);
0172     }
0173 
0174     size_t n_variables = std::stoul(tokens[n_bins + 1]);
0175 
0176     if (tokens.size() < (1 + n_bins + 1 + n_variables + 1)) {
0177       throwException(edm::errors::ConfigFileReadError, "Invalid file format. Please check.");
0178     }
0179 
0180     for (size_t i = 0; i < n_variables; i++) {
0181       m_variables_name.push_back(tokens[n_bins + 2 + i]);
0182     }
0183 
0184     m_formula_str = tokens[n_bins + n_variables + 2];
0185 
0186     std::string formula_str_lower = m_formula_str;
0187     std::transform(formula_str_lower.begin(), formula_str_lower.end(), formula_str_lower.begin(), ::tolower);
0188 
0189     if (formula_str_lower == "none") {
0190       m_formula_str = "";
0191 
0192       if ((tokens.size() > n_bins + n_variables + 3) && (std::atoi(tokens[n_bins + n_variables + 3].c_str()))) {
0193         size_t n_parameters = std::stoul(tokens[n_bins + n_variables + 3]);
0194 
0195         if (tokens.size() < (1 + n_bins + 1 + n_variables + 1 + 1 + n_parameters)) {
0196           throwException(edm::errors::ConfigFileReadError, "Invalid file format. Please check.");
0197         }
0198 
0199         for (size_t i = 0; i < n_parameters; i++) {
0200           m_formula_str += tokens[n_bins + n_variables + 4 + i] + " ";
0201         }
0202       }
0203     }
0204 
0205     init();
0206   }
0207 
0208   void JetResolutionObject::Definition::init() {
0209     if (!m_formula_str.empty()) {
0210       if (m_formula_str.find(' ') == std::string::npos)
0211 #ifndef STANDALONE
0212         m_formula = std::make_shared<reco::FormulaEvaluator>(m_formula_str);
0213 #else
0214         m_formula = std::make_shared<TFormula>("jet_resolution_formula", m_formula_str.c_str());
0215 #endif
0216       else
0217         m_parameters_name = getTokens(m_formula_str);
0218     }
0219     for (const auto& bin : m_bins_name) {
0220       const auto& b = JetParameters::binning_to_string.right.find(bin);
0221       if (b == JetParameters::binning_to_string.right.cend()) {
0222         throwException(edm::errors::UnimplementedFeature, "Bin name not supported: '" + bin + "'");
0223       }
0224       m_bins.push_back(b->second);
0225     }
0226 
0227     for (const auto& v : m_variables_name) {
0228       const auto& var = JetParameters::binning_to_string.right.find(v);
0229       if (var == JetParameters::binning_to_string.right.cend()) {
0230         throwException(edm::errors::UnimplementedFeature, "Variable name not supported: '" + v + "'");
0231       }
0232       m_variables.push_back(var->second);
0233     }
0234   }
0235 
0236   JetResolutionObject::Record::Record(const std::string& line, const Definition& def) {
0237     std::vector<std::string> tokens = getTokens(line);
0238 
0239     if (tokens.size() < (def.nBins() * 2 + def.nVariables() * 2 + 1)) {
0240       throwException(edm::errors::ConfigFileReadError, "Invalid record. Please check file format. Record: " + line);
0241     }
0242 
0243     size_t pos = 0;
0244 
0245     for (size_t i = 0; i < def.nBins(); i++) {
0246       Range r(std::stof(tokens[pos]), std::stof(tokens[pos + 1]));
0247       pos += 2;
0248       m_bins_range.push_back(r);
0249     }
0250 
0251     size_t n_parameters = std::stoul(tokens[pos++]);
0252 
0253     if (tokens.size() < (def.nBins() * 2 + def.nVariables() * 2 + 1 + (n_parameters - def.nVariables() * 2))) {
0254       throwException(edm::errors::ConfigFileReadError, "Invalid record. Please check file format. Record: " + line);
0255     }
0256 
0257     for (size_t i = 0; i < def.nVariables(); i++) {
0258       Range r(std::stof(tokens[pos]), std::stof(tokens[pos + 1]));
0259       pos += 2;
0260       m_variables_range.push_back(r);
0261       n_parameters -= 2;
0262     }
0263 
0264     for (size_t i = 0; i < n_parameters; i++) {
0265       m_parameters_values.push_back(std::stof(tokens[pos++]));
0266     }
0267   }
0268 
0269   JetResolutionObject::JetResolutionObject(const std::string& filename) {
0270     // Parse file
0271     std::ifstream f(filename);
0272 
0273     if (!f.good()) {
0274       throwException(edm::errors::FileReadError, "Can't read input file '" + filename + "'");
0275     }
0276 
0277     for (std::string line; std::getline(f, line);) {
0278       if ((line.empty()) || (line[0] == '#'))
0279         continue;
0280 
0281       std::string definition = getDefinitionLine(line);
0282 
0283       if (!definition.empty()) {
0284         m_definition = Definition(definition);
0285       } else {
0286         m_records.push_back(Record(line, m_definition));
0287       }
0288     }
0289 
0290     m_valid = true;
0291   }
0292 
0293   JetResolutionObject::JetResolutionObject(const JetResolutionObject& object) {
0294     m_definition = object.m_definition;
0295     m_records = object.m_records;
0296     m_valid = object.m_valid;
0297 
0298     m_definition.init();
0299   }
0300 
0301   JetResolutionObject::JetResolutionObject() {
0302     // Empty
0303   }
0304 
0305   void JetResolutionObject::dump() const {
0306     std::cout << "Definition: " << std::endl;
0307     std::cout << "    Number of binning variables: " << m_definition.nBins() << std::endl;
0308     std::cout << "        ";
0309     for (const auto& bin : m_definition.getBinsName()) {
0310       std::cout << bin << ", ";
0311     }
0312     std::cout << std::endl;
0313     std::cout << "    Number of variables: " << m_definition.nVariables() << std::endl;
0314     std::cout << "        ";
0315     for (const auto& bin : m_definition.getVariablesName()) {
0316       std::cout << bin << ", ";
0317     }
0318     std::cout << std::endl;
0319     std::cout << "    Formula: " << m_definition.getFormulaString() << std::endl;
0320 
0321     std::cout << std::endl << "Bin contents" << std::endl;
0322 
0323     for (const auto& record : m_records) {
0324       std::cout << "    Bins" << std::endl;
0325       size_t index = 0;
0326       for (const auto& bin : record.getBinsRange()) {
0327         std::cout << "        " << m_definition.getBinName(index) << " [" << bin.min << " - " << bin.max << "]"
0328                   << std::endl;
0329         index++;
0330       }
0331 
0332       std::cout << "    Variables" << std::endl;
0333       index = 0;
0334       for (const auto& r : record.getVariablesRange()) {
0335         std::cout << "        " << m_definition.getVariableName(index) << " [" << r.min << " - " << r.max << "] "
0336                   << std::endl;
0337         index++;
0338       }
0339 
0340       std::cout << "    Parameters" << std::endl;
0341       index = 0;
0342       for (const auto& par : record.getParametersValues()) {
0343         std::cout << "        Parameter #" << index << " = " << par << std::endl;
0344         index++;
0345       }
0346     }
0347   }
0348 
0349   void JetResolutionObject::saveToFile(const std::string& file) const {
0350     std::ofstream fout(file);
0351     fout.setf(std::ios::right);
0352 
0353     // Definition
0354     fout << "{" << m_definition.nBins();
0355 
0356     for (auto& bin : m_definition.getBinsName())
0357       fout << "    " << bin;
0358 
0359     fout << "    " << m_definition.nVariables();
0360 
0361     for (auto& var : m_definition.getVariablesName())
0362       fout << "    " << var;
0363 
0364     fout << "    " << (m_definition.getFormulaString().empty() ? "None" : m_definition.getFormulaString())
0365          << "    Resolution}" << std::endl;
0366 
0367     // Records
0368     for (auto& record : m_records) {
0369       for (auto& r : record.getBinsRange()) {
0370         fout << std::left << std::setw(15) << r.min << std::setw(15) << r.max << std::setw(15);
0371       }
0372       fout << (record.nVariables() * 2 + record.nParameters()) << std::setw(15);
0373 
0374       for (auto& r : record.getVariablesRange()) {
0375         fout << r.min << std::setw(15) << r.max << std::setw(15);
0376       }
0377 
0378       for (auto& p : record.getParametersValues()) {
0379         fout << p << std::setw(15);
0380       }
0381 
0382       fout << std::endl << std::setw(0);
0383     }
0384   }
0385 
0386   const JetResolutionObject::Record* JetResolutionObject::getRecord(const JetParameters& bins_parameters) const {
0387     // Find record for bins
0388     if (!m_valid)
0389       return nullptr;
0390 
0391     // Create vector of bins value. Throw if some values are missing
0392     std::vector<float> bins = bins_parameters.createVector(m_definition.getBinsName());
0393 
0394     // Iterate over all records, and find the one for which all bins are valid
0395     const Record* good_record = nullptr;
0396     for (const auto& record : m_records) {
0397       // Iterate over bins
0398       size_t valid_bins = 0;
0399       size_t current_bin = 0;
0400       for (const auto& bin : record.getBinsRange()) {
0401         if (bin.is_inside(bins[current_bin])) {
0402           valid_bins++;
0403         }
0404 
0405         current_bin++;
0406       }
0407 
0408       if (valid_bins == m_definition.nBins()) {
0409         good_record = &record;
0410         break;
0411       }
0412     }
0413 
0414     return good_record;
0415   }
0416 
0417   float JetResolutionObject::evaluateFormula(const JetResolutionObject::Record& record,
0418                                              const JetParameters& variables_parameters) const {
0419     if (!m_valid)
0420       return 1;
0421 
0422 #ifndef STANDALONE
0423     reco::FormulaEvaluator formula = reco::FormulaEvaluator(m_definition.getFormulaString());
0424 #else
0425     // Set parameters
0426     auto const* pFormula = m_definition.getFormula();
0427     if (!pFormula)
0428       return 1;
0429     auto formula = *pFormula;
0430 #endif
0431     // Create vector of variables value. Throw if some values are missing
0432     std::vector<float> variables = variables_parameters.createVector(m_definition.getVariablesName());
0433 
0434     double variables_[4] = {0};
0435     for (size_t index = 0; index < m_definition.nVariables(); index++) {
0436       variables_[index] =
0437           clip(variables[index], record.getVariablesRange()[index].min, record.getVariablesRange()[index].max);
0438     }
0439 
0440     const std::vector<float>& parameters = record.getParametersValues();
0441 
0442 #ifndef STANDALONE
0443     //ArrayAdaptor only takes doubles
0444     std::vector<double> parametersD(parameters.begin(), parameters.end());
0445     return formula.evaluate(reco::formula::ArrayAdaptor(variables_, m_definition.nVariables()),
0446                             reco::formula::ArrayAdaptor(parametersD.data(), parametersD.size()));
0447 #else
0448     for (size_t index = 0; index < parameters.size(); index++) {
0449       formula.SetParameter(index, parameters[index]);
0450     }
0451 
0452     return formula.EvalPar(variables_);
0453 #endif
0454   }
0455 }  // namespace JME
0456 
0457 #ifndef STANDALONE
0458 #include "FWCore/Utilities/interface/typelookup.h"
0459 TYPELOOKUP_DATA_REG(JME::JetResolutionObject);
0460 #endif