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 };
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
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
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
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
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
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
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
0388 if (!m_valid)
0389 return nullptr;
0390
0391
0392 std::vector<float> bins = bins_parameters.createVector(m_definition.getBinsName());
0393
0394
0395 const Record* good_record = nullptr;
0396 for (const auto& record : m_records) {
0397
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
0426 auto const* pFormula = m_definition.getFormula();
0427 if (!pFormula)
0428 return 1;
0429 auto formula = *pFormula;
0430 #endif
0431
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
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 }
0456
0457 #ifndef STANDALONE
0458 #include "FWCore/Utilities/interface/typelookup.h"
0459 TYPELOOKUP_DATA_REG(JME::JetResolutionObject);
0460 #endif