File indexing completed on 2024-12-20 03:13:52
0001
0002
0003
0004
0005
0006
0007 #include <vector>
0008 #include <set>
0009 #include <string>
0010 #include <iostream>
0011 #include <sstream>
0012 #include <fstream>
0013 #include <cstdio>
0014 #include <iomanip>
0015 #include <memory>
0016 #include <algorithm>
0017
0018 #include <cstring>
0019 #include <unistd.h>
0020 #include <getopt.h>
0021 #include <cstdio>
0022 #include <cmath>
0023
0024 #include <boost/algorithm/string.hpp>
0025
0026 #include <TFile.h>
0027 #include <TCanvas.h>
0028 #include <TH1F.h>
0029 #include <TH2F.h>
0030 #include <TGraphAsymmErrors.h>
0031
0032 #include "FWCore/Common/interface/TriggerNames.h"
0033 #include "FWCore/Utilities/interface/InputTag.h"
0034 #include "FWCore/ParameterSet/interface/Registry.h"
0035 #include "DataFormats/Common/interface/TriggerResults.h"
0036 #include "DataFormats/HLTReco/interface/TriggerObject.h"
0037 #include "DataFormats/HLTReco/interface/TriggerEvent.h"
0038 #include "DataFormats/FWLite/interface/Handle.h"
0039 #include "DataFormats/FWLite/interface/Event.h"
0040 #include "DataFormats/FWLite/interface/ChainEvent.h"
0041 #include "HLTrigger/HLTcore/interface/HLTConfigData.h"
0042
0043 void error(std::ostream& out) { out << "Try 'hltDiff --help' for more information" << std::endl; }
0044
0045 void error(std::ostream& out, const char* message) {
0046 out << message << std::endl;
0047 error(out);
0048 }
0049
0050 void error(std::ostream& out, const std::string& message) {
0051 out << message << std::endl;
0052 error(out);
0053 }
0054
0055 class HLTConfigInterface {
0056 public:
0057 virtual ~HLTConfigInterface() = default;
0058 virtual std::string const& processName() const = 0;
0059 virtual unsigned int size() const = 0;
0060 virtual unsigned int size(unsigned int trigger) const = 0;
0061 virtual std::string const& triggerName(unsigned int trigger) const = 0;
0062 virtual unsigned int triggerIndex(unsigned int trigger) const = 0;
0063 virtual std::string const& moduleLabel(unsigned int trigger, unsigned int module) const = 0;
0064 virtual std::string const& moduleType(unsigned int trigger, unsigned int module) const = 0;
0065 virtual bool prescaler(unsigned int trigger, unsigned int module) const = 0;
0066 };
0067
0068 class HLTConfigDataEx : public HLTConfigInterface {
0069 public:
0070 explicit HLTConfigDataEx(HLTConfigData data) : data_(std::move(data)), moduleTypes_(size()), prescalers_(size()) {
0071 for (unsigned int t = 0; t < data_.size(); ++t) {
0072 prescalers_[t].resize(size(t));
0073 moduleTypes_[t].resize(size(t));
0074 for (unsigned int m = 0; m < data_.size(t); ++m) {
0075 std::string type = data_.moduleType(moduleLabel(t, m));
0076 prescalers_[t][m] = (type == "HLTPrescaler");
0077 moduleTypes_[t][m] = &*moduleTypeSet_.insert(std::move(type)).first;
0078 }
0079 }
0080 }
0081 ~HLTConfigDataEx() override = default;
0082 std::string const& processName() const override { return data_.processName(); }
0083
0084 unsigned int size() const override { return data_.size(); }
0085
0086 unsigned int size(unsigned int trigger) const override { return data_.size(trigger); }
0087
0088 virtual std::vector<std::string> const& triggerNames() const { return data_.triggerNames(); }
0089
0090 std::string const& triggerName(unsigned int trigger) const override { return data_.triggerName(trigger); }
0091
0092 unsigned int triggerIndex(unsigned int trigger) const override { return trigger; }
0093
0094 std::string const& moduleLabel(unsigned int trigger, unsigned int module) const override {
0095 return data_.moduleLabel(trigger, module);
0096 }
0097
0098 std::string const& moduleType(unsigned int trigger, unsigned int module) const override {
0099 return *moduleTypes_.at(trigger).at(module);
0100 }
0101
0102 bool prescaler(unsigned int trigger, unsigned int module) const override {
0103 return prescalers_.at(trigger).at(module);
0104 }
0105
0106 private:
0107 HLTConfigData data_;
0108 std::set<std::string> moduleTypeSet_;
0109 std::vector<std::vector<std::string const*>> moduleTypes_;
0110 std::vector<std::vector<bool>> prescalers_;
0111 };
0112
0113 const char* event_state(bool state) { return state ? "accepted" : "rejected"; }
0114
0115 class HLTCommonConfig {
0116 public:
0117 enum class Index { First = 0, Second = 1 };
0118
0119 class View : public HLTConfigInterface {
0120 public:
0121 View(HLTCommonConfig const& config, HLTCommonConfig::Index index) : config_(config), index_(index) {}
0122 ~View() override = default;
0123 std::string const& processName() const override;
0124 unsigned int size() const override;
0125 unsigned int size(unsigned int trigger) const override;
0126 std::string const& triggerName(unsigned int trigger) const override;
0127 unsigned int triggerIndex(unsigned int trigger) const override;
0128 std::string const& moduleLabel(unsigned int trigger, unsigned int module) const override;
0129 std::string const& moduleType(unsigned int trigger, unsigned int module) const override;
0130 bool prescaler(unsigned int trigger, unsigned int module) const override;
0131
0132 private:
0133 HLTCommonConfig const& config_;
0134 Index index_;
0135 };
0136
0137 HLTCommonConfig(HLTConfigDataEx const& first, HLTConfigDataEx const& second)
0138 : first_(first), second_(second), firstView_(*this, Index::First), secondView_(*this, Index::Second) {
0139 for (unsigned int f = 0; f < first.size(); ++f)
0140 for (unsigned int s = 0; s < second.size(); ++s)
0141 if (first.triggerName(f) == second.triggerName(s)) {
0142 triggerIndices_.push_back(std::make_pair(f, s));
0143 break;
0144 }
0145 }
0146
0147 View const& getView(Index index) const {
0148 if (index == Index::First)
0149 return firstView_;
0150 else
0151 return secondView_;
0152 }
0153
0154 std::string const& processName(Index index) const {
0155 if (index == Index::First)
0156 return first_.processName();
0157 else
0158 return second_.processName();
0159 }
0160
0161 unsigned int size(Index index) const { return triggerIndices_.size(); }
0162
0163 unsigned int size(Index index, unsigned int trigger) const {
0164 if (index == Index::First)
0165 return first_.size(trigger);
0166 else
0167 return second_.size(trigger);
0168 }
0169
0170 std::string const& triggerName(Index index, unsigned int trigger) const {
0171 if (index == Index::First)
0172 return first_.triggerName(triggerIndices_.at(trigger).first);
0173 else
0174 return second_.triggerName(triggerIndices_.at(trigger).second);
0175 }
0176
0177 unsigned int triggerIndex(Index index, unsigned int trigger) const {
0178 if (index == Index::First)
0179 return triggerIndices_.at(trigger).first;
0180 else
0181 return triggerIndices_.at(trigger).second;
0182 }
0183
0184 std::string const& moduleLabel(Index index, unsigned int trigger, unsigned int module) const {
0185 if (index == Index::First)
0186 return first_.moduleLabel(triggerIndices_.at(trigger).first, module);
0187 else
0188 return second_.moduleLabel(triggerIndices_.at(trigger).second, module);
0189 }
0190
0191 std::string const& moduleType(Index index, unsigned int trigger, unsigned int module) const {
0192 if (index == Index::First)
0193 return first_.moduleType(triggerIndices_.at(trigger).first, module);
0194 else
0195 return second_.moduleType(triggerIndices_.at(trigger).second, module);
0196 }
0197
0198 bool prescaler(Index index, unsigned int trigger, unsigned int module) const {
0199 if (index == Index::First)
0200 return first_.prescaler(triggerIndices_.at(trigger).first, module);
0201 else
0202 return second_.prescaler(triggerIndices_.at(trigger).second, module);
0203 }
0204
0205 private:
0206 HLTConfigDataEx const& first_;
0207 HLTConfigDataEx const& second_;
0208
0209 View firstView_;
0210 View secondView_;
0211
0212 std::vector<std::pair<unsigned int, unsigned int>> triggerIndices_;
0213 };
0214
0215 std::string const& HLTCommonConfig::View::processName() const { return config_.processName(index_); }
0216
0217 unsigned int HLTCommonConfig::View::size() const { return config_.size(index_); }
0218
0219 unsigned int HLTCommonConfig::View::size(unsigned int trigger) const { return config_.size(index_, trigger); }
0220
0221 std::string const& HLTCommonConfig::View::triggerName(unsigned int trigger) const {
0222 return config_.triggerName(index_, trigger);
0223 }
0224
0225 unsigned int HLTCommonConfig::View::triggerIndex(unsigned int trigger) const {
0226 return config_.triggerIndex(index_, trigger);
0227 }
0228
0229 std::string const& HLTCommonConfig::View::moduleLabel(unsigned int trigger, unsigned int module) const {
0230 return config_.moduleLabel(index_, trigger, module);
0231 }
0232
0233 std::string const& HLTCommonConfig::View::moduleType(unsigned int trigger, unsigned int module) const {
0234 return config_.moduleType(index_, trigger, module);
0235 }
0236
0237 bool HLTCommonConfig::View::prescaler(unsigned int trigger, unsigned int module) const {
0238 return config_.prescaler(index_, trigger, module);
0239 }
0240
0241 enum State {
0242 Ready = edm::hlt::Ready,
0243 Pass = edm::hlt::Pass,
0244 Fail = edm::hlt::Fail,
0245 Exception = edm::hlt::Exception,
0246 Prescaled,
0247 Invalid
0248 };
0249
0250 const char* path_state(State state) {
0251 static const char* message[] = {"not run", "accepted", "rejected", "exception", "prescaled", "invalid"};
0252
0253 if (state > 0 and state < Invalid)
0254 return message[state];
0255 else
0256 return message[Invalid];
0257 }
0258
0259 inline State prescaled_state(int state, int path, int module, HLTConfigInterface const& config) {
0260 if (state == Fail and config.prescaler(path, module))
0261 return Prescaled;
0262 return (State)state;
0263 }
0264
0265
0266
0267
0268
0269
0270
0271
0272 std::string strip_process_name(std::string const& s) {
0273 if (std::count(s.begin(), s.end(), ':') == 2) {
0274
0275 size_t end = s.find_last_of(':');
0276 if (end > 0 and s.at(end - 1) == ':')
0277
0278 --end;
0279 return s.substr(0, end);
0280 } else {
0281
0282 return s;
0283 }
0284 }
0285
0286 void print_detailed_path_state(std::ostream& out, State state, int path, int module, HLTConfigInterface const& config) {
0287 auto const& label = config.moduleLabel(path, module);
0288 auto const& type = config.moduleType(path, module);
0289
0290 out << "'" << path_state(state) << "'";
0291 if (state == Fail)
0292 out << " by module " << module << " '" << label << "' [" << type << "]";
0293 else if (state == Exception)
0294 out << " at module " << module << " '" << label << "' [" << type << "]";
0295 }
0296
0297 void print_trigger_candidates(std::ostream& out, trigger::TriggerEvent const& summary, edm::InputTag const& filter) {
0298
0299 unsigned int index = summary.filterIndex(filter);
0300
0301 if (index >= summary.sizeFilters()) {
0302
0303 out << " not found\n";
0304 return;
0305 }
0306
0307 if (summary.filterKeys(index).empty()) {
0308
0309 out << " none\n";
0310 return;
0311 }
0312
0313 for (unsigned int i = 0; i < summary.filterKeys(index).size(); ++i) {
0314 auto key = summary.filterKeys(index)[i];
0315 auto id = summary.filterIds(index)[i];
0316 trigger::TriggerObject const& candidate = summary.getObjects().at(key);
0317 out << " "
0318 << "filter id: " << id << ", "
0319 << "object id: " << candidate.id() << ", "
0320 << "pT: " << candidate.pt() << ", "
0321 << "eta: " << candidate.eta() << ", "
0322 << "phi: " << candidate.phi() << ", "
0323 << "mass: " << candidate.mass() << "\n";
0324 }
0325 }
0326
0327 void print_trigger_collection(std::ostream& out, trigger::TriggerEvent const& summary, std::string const& tag) {
0328 auto iterator = std::find(summary.collectionTags().begin(), summary.collectionTags().end(), tag);
0329 if (iterator == summary.collectionTags().end()) {
0330
0331 out << " not found\n";
0332 return;
0333 }
0334
0335 unsigned int index = iterator - summary.collectionTags().begin();
0336 unsigned int begin = (index == 0) ? 0 : summary.collectionKey(index - 1);
0337 unsigned int end = summary.collectionKey(index);
0338
0339 if (end == begin) {
0340
0341 out << " none\n";
0342 return;
0343 }
0344
0345 for (unsigned int key = begin; key < end; ++key) {
0346 trigger::TriggerObject const& candidate = summary.getObjects().at(key);
0347 out << " "
0348 << "object id: " << candidate.id() << ", "
0349 << "pT: " << candidate.pt() << ", "
0350 << "eta: " << candidate.eta() << ", "
0351 << "phi: " << candidate.phi() << ", "
0352 << "mass: " << candidate.mass() << "\n";
0353 }
0354 }
0355
0356 std::string getProcessNameFromBranch(std::string const& branch) {
0357 std::vector<boost::iterator_range<std::string::const_iterator>> tokens;
0358 boost::split(tokens, branch, boost::is_any_of("_."), boost::token_compress_off);
0359 return boost::copy_range<std::string>(tokens[3]);
0360 }
0361
0362 std::unique_ptr<HLTConfigDataEx> getHLTConfigData(fwlite::EventBase const& event, std::string process) {
0363 auto const& history = event.processHistory();
0364 if (process.empty()) {
0365
0366 auto const& branch =
0367 event.getBranchNameFor(edm::Wrapper<edm::TriggerResults>::typeInfo(), "TriggerResults", "", process.c_str());
0368 process = getProcessNameFromBranch(branch);
0369 }
0370
0371 edm::ProcessConfiguration config;
0372 if (not history.getConfigurationForProcess(process, config)) {
0373 std::cerr << "error: the process " << process << " is not in the Process History" << std::endl;
0374 exit(1);
0375 }
0376 const edm::ParameterSet* pset = edm::pset::Registry::instance()->getMapped(config.parameterSetID());
0377 if (pset == nullptr) {
0378 std::cerr << "error: the configuration for the process " << process << " is not available in the Provenance"
0379 << std::endl;
0380 exit(1);
0381 }
0382 return std::make_unique<HLTConfigDataEx>(HLTConfigData(pset));
0383 }
0384
0385 struct TriggerDiff {
0386 TriggerDiff() : count(0), gained(0), lost(0), internal(0) {}
0387
0388 unsigned int count;
0389 unsigned int gained;
0390 unsigned int lost;
0391 unsigned int internal;
0392
0393 static std::string format(unsigned int value, char sign = '+') {
0394 if (value == 0)
0395 return std::string("-");
0396
0397 char buffer[12];
0398 memset(buffer, 0, 12);
0399
0400 unsigned int digit = 10;
0401 while (value > 0) {
0402 buffer[digit] = value % 10 + 48;
0403 value /= 10;
0404 --digit;
0405 }
0406 buffer[digit] = sign;
0407
0408 return std::string(buffer + digit);
0409 }
0410
0411 unsigned int total() const { return this->gained + this->lost + this->internal; }
0412 };
0413
0414 std::ostream& operator<<(std::ostream& out, TriggerDiff diff) {
0415 out << std::setw(12) << diff.count << std::setw(12) << TriggerDiff::format(diff.gained, '+') << std::setw(12)
0416 << TriggerDiff::format(diff.lost, '-') << std::setw(12) << TriggerDiff::format(diff.internal, '~');
0417 return out;
0418 }
0419
0420 class JsonOutputProducer {
0421 private:
0422 static size_t tab_spaces;
0423
0424
0425 static std::string indent(size_t _nTabs) {
0426 std::string str = "\n";
0427 while (_nTabs) {
0428 int nSpaces = tab_spaces;
0429 while (nSpaces) {
0430 str.push_back(' ');
0431 nSpaces--;
0432 }
0433 _nTabs--;
0434 }
0435
0436 return str;
0437 }
0438
0439 static std::string key(const std::string& _key, const std::string& _delim = "") {
0440 std::string str = "\"\":";
0441 str.insert(1, _key);
0442 str.append(_delim);
0443
0444 return str;
0445 }
0446
0447 static std::string key_string(const std::string& _key, const std::string& _string, const std::string& _delim = "") {
0448 std::string str = key(_key, _delim);
0449 str.push_back('"');
0450 str.append(_string);
0451 str.push_back('"');
0452 return str;
0453 }
0454
0455 static std::string key_int(const std::string& _key, int _int, const std::string& _delim = "") {
0456 std::string str = key(_key, _delim);
0457 str.append(std::to_string(_int));
0458
0459 return str;
0460 }
0461
0462 static std::string string(const std::string& _string, const std::string& _delim = "") {
0463 std::string str = "\"\"";
0464 str.insert(1, _string);
0465 str.append(_delim);
0466
0467 return str;
0468 }
0469
0470 static std::string list_string(const std::vector<std::string>& _values, const std::string& _delim = "") {
0471 std::string str = "[";
0472 for (auto it = _values.begin(); it != _values.end(); ++it) {
0473 str.append(_delim);
0474 str.push_back('"');
0475 str.append(*it);
0476 str.push_back('"');
0477 if (it != --_values.end())
0478 str.push_back(',');
0479 }
0480 str.append(_delim);
0481 str.push_back(']');
0482
0483 return str;
0484 }
0485
0486 public:
0487 bool writeJson;
0488 std::string out_filename_base;
0489 bool useSingleOutFile;
0490
0491 struct JsonConfigurationBlock {
0492 std::string file_base;
0493 std::vector<std::string> files;
0494 std::string process;
0495 std::vector<std::string> skipped_triggers;
0496
0497 std::string serialise(size_t _indent = 0) const {
0498 std::ostringstream json;
0499 json << indent(_indent);
0500 json << key_string("file_base", file_base) << ',';
0501 json << indent(_indent);
0502 json << key("files") << list_string(files) << ',';
0503 json << indent(_indent);
0504 json << key_string("process", process) << ',';
0505 json << indent(_indent);
0506 json << key("skipped_triggers") << list_string(skipped_triggers);
0507
0508 return json.str();
0509 }
0510
0511 void extractFileBase() {
0512 std::string file0 = files.at(0);
0513
0514 for (size_t i = 0; i < file0.length(); ++i) {
0515 bool identicalInAll = true;
0516 char character = file0.at(i);
0517 for (std::string file : files) {
0518 if (file.at(i) == character)
0519 continue;
0520 identicalInAll = false;
0521 break;
0522 }
0523 if (!identicalInAll)
0524 break;
0525 file_base.push_back(character);
0526 }
0527 const unsigned int file_base_len = file_base.length();
0528 if (file_base_len < 1)
0529 return;
0530
0531 for (std::string& file : files) {
0532 file.erase(0, file_base_len);
0533 }
0534 }
0535
0536 JsonConfigurationBlock() : file_base(""), files(0), process(""), skipped_triggers(0) {}
0537 };
0538
0539 struct JsonConfiguration {
0540 JsonConfigurationBlock o;
0541 JsonConfigurationBlock n;
0542 bool prescales;
0543 int events;
0544
0545 std::string serialise(size_t _indent = 0) const {
0546 std::ostringstream json;
0547 json << indent(_indent) << key("configuration") << '{';
0548 json << indent(_indent + 1) << key("o") << '{';
0549 json << o.serialise(_indent + 2);
0550 json << indent(_indent + 1) << "},";
0551 json << indent(_indent + 1) << key("n") << '{';
0552 json << n.serialise(_indent + 2);
0553 json << indent(_indent + 1) << "},";
0554 std::string prescales_str = prescales ? "true" : "false";
0555 json << indent(_indent + 1) << key("prescales") << prescales_str << ',';
0556 json << indent(_indent + 1) << key("events") << events;
0557 json << indent(_indent) << "}";
0558
0559 return json.str();
0560 }
0561
0562 JsonConfiguration() : o(), n() {}
0563 };
0564
0565 struct JsonVars {
0566 std::vector<std::string> state;
0567 std::vector<std::string> trigger;
0568 std::vector<std::pair<int, int>> trigger_passed_count;
0569 std::vector<std::string> label;
0570 std::vector<std::string> type;
0571
0572 std::string serialise(size_t _indent = 0) const {
0573 std::ostringstream json;
0574 json << indent(_indent) << key("vars") << '{';
0575 json << indent(_indent + 1) << key("state") << list_string(state) << ',';
0576 json << indent(_indent + 1) << key("trigger") << list_string(trigger) << ',';
0577 json << indent(_indent + 1) << key("trigger_passed_count") << '[';
0578 for (auto it = trigger_passed_count.begin(); it != trigger_passed_count.end(); ++it) {
0579 json << '{' << key("o") << (*it).first << ',' << key("n") << (*it).second << '}';
0580 if (it != trigger_passed_count.end() - 1)
0581 json << ',';
0582 }
0583 json << "],";
0584 json << indent(_indent + 1) << key("label") << list_string(label) << ',';
0585 json << indent(_indent + 1) << key("type") << list_string(type);
0586 json << indent(_indent) << '}';
0587
0588 return json.str();
0589 }
0590
0591 JsonVars() : state(0), trigger(0), trigger_passed_count(0), label(0), type(0) {}
0592 };
0593
0594
0595 JsonConfiguration configuration;
0596 JsonVars vars;
0597
0598 private:
0599 unsigned int labelId(std::string labelName) {
0600 unsigned int id = std::find(vars.label.begin(), vars.label.end(), labelName) - vars.label.begin();
0601 if (id < vars.label.size())
0602 return id;
0603 vars.label.push_back(labelName);
0604 return vars.label.size() - 1;
0605 }
0606
0607 unsigned int typeId(std::string typeName) {
0608 unsigned int id = std::find(vars.type.begin(), vars.type.end(), typeName) - vars.type.begin();
0609 if (id < vars.type.size())
0610 return id;
0611 vars.type.push_back(typeName);
0612 return vars.type.size() - 1;
0613 }
0614
0615 public:
0616 struct JsonEventState {
0617 State s;
0618 int m;
0619 int l;
0620 int t;
0621
0622 std::string serialise(size_t _indent = 0) const {
0623 std::ostringstream json;
0624 json << key_int("s", int(s));
0625
0626 if (s == State::Pass)
0627 return json.str();
0628 json << ',';
0629 json << key_int("m", m) << ',';
0630 json << key_int("l", l) << ',';
0631 json << key_int("t", t);
0632
0633 return json.str();
0634 }
0635
0636 JsonEventState() : s(State::Ready), m(-1), l(-1), t(-1) {}
0637 JsonEventState(State _s, int _m, int _l, int _t) : s(_s), m(_m), l(_l), t(_t) {}
0638 };
0639
0640 struct JsonTriggerEventState {
0641 int tr;
0642 JsonEventState o;
0643 JsonEventState n;
0644
0645 std::string serialise(size_t _indent = 0) const {
0646 std::ostringstream json;
0647 json << indent(_indent) << key_int("t", tr) << ',';
0648 json << indent(_indent) << key("o") << '{' << o.serialise() << "},";
0649 json << indent(_indent) << key("n") << '{' << n.serialise() << "}";
0650
0651 return json.str();
0652 }
0653
0654 JsonTriggerEventState() : tr(-1), o(), n() {}
0655 JsonTriggerEventState(int _tr) : tr(_tr), o(), n() {}
0656 };
0657
0658 struct JsonEvent {
0659 int run;
0660 int lumi;
0661 int event;
0662 std::vector<JsonTriggerEventState> triggerStates;
0663
0664 std::string serialise(size_t _indent = 0) const {
0665 std::ostringstream json;
0666 json << indent(_indent) << '{' << "\"r\"" << ':' << run << ",\"l\":" << lumi << ",\"e\":" << event
0667 << ",\"t\":[";
0668 for (auto it = triggerStates.begin(); it != triggerStates.end(); ++it) {
0669 json << '{';
0670 json << (*it).serialise(_indent + 2);
0671 json << indent(_indent + 1) << '}';
0672 if (it != --triggerStates.end())
0673 json << ',';
0674 }
0675 json << indent(_indent) << ']' << '}';
0676
0677 return json.str();
0678 }
0679
0680 JsonEvent(int _run, int _lumi, int _event) : run(_run), lumi(_lumi), event(_event), triggerStates(0) {}
0681
0682 JsonTriggerEventState& pushTrigger(int _tr) {
0683
0684 if (!triggerStates.empty()) {
0685 JsonTriggerEventState& lastTrigger = triggerStates.back();
0686 if (lastTrigger.tr == _tr)
0687 return lastTrigger;
0688 }
0689 triggerStates.push_back(JsonTriggerEventState(_tr));
0690 return triggerStates.back();
0691 }
0692 };
0693
0694
0695 std::map<int, std::vector<JsonEvent>> m_run_events;
0696
0697
0698 JsonOutputProducer(bool _writeJson, std::string _file_name)
0699 : writeJson(_writeJson), out_filename_base(std::move(_file_name)) {
0700 useSingleOutFile = !out_filename_base.empty();
0701 }
0702
0703 JsonEvent& pushEvent(int _run, int _lumi, int _event) {
0704
0705 if ((m_run_events.count(_run) == 0 && !useSingleOutFile) || m_run_events.empty())
0706 m_run_events.emplace(_run, std::vector<JsonEvent>());
0707 std::vector<JsonEvent>& v_events = useSingleOutFile ? m_run_events.begin()->second : m_run_events.at(_run);
0708
0709 if (!v_events.empty()) {
0710 JsonEvent& lastEvent = v_events.back();
0711 if (lastEvent.run == _run && lastEvent.lumi == _lumi && lastEvent.event == _event)
0712 return lastEvent;
0713 }
0714 v_events.push_back(JsonEvent(_run, _lumi, _event));
0715 return v_events.back();
0716 }
0717
0718 JsonEventState eventState(State _s, int _m, const std::string& _l, const std::string& _t) {
0719 return JsonEventState(_s, _m, this->labelId(_l), this->typeId(_t));
0720 }
0721
0722 std::string output_filename_base(int _run) const {
0723 if (useSingleOutFile)
0724 return out_filename_base;
0725
0726 char name[1000];
0727 sprintf(name,
0728 "DQM_V0001_R%.9d__OLD_%s__NEW_%s_DQM",
0729 _run,
0730 configuration.o.process.c_str(),
0731 configuration.n.process.c_str());
0732
0733 return std::string(name);
0734 }
0735
0736 void write() {
0737 if (!writeJson)
0738 return;
0739 std::set<std::string> filesCreated, filesNotCreated;
0740 std::ofstream out_file;
0741 if (!m_run_events.empty()) {
0742
0743 for (const auto& runEvents : m_run_events) {
0744 const int run = runEvents.first;
0745 const std::vector<JsonEvent>& v_events = runEvents.second;
0746
0747 std::string output_name = output_filename_base(run) += ".json";
0748 out_file.open(output_name, std::ofstream::out);
0749 if (out_file.good()) {
0750 out_file << '{';
0751 out_file << configuration.serialise(1) << ',';
0752 out_file << vars.serialise(1) << ',';
0753
0754 out_file << indent(1) << key("events") << '[';
0755 for (auto it = v_events.begin(); it != v_events.end(); ++it) {
0756 out_file << (*it).serialise(2);
0757 if (it != --v_events.end())
0758 out_file << ',';
0759 }
0760 out_file << indent(1) << ']';
0761 out_file << indent(0) << "}";
0762 out_file.close();
0763
0764 filesCreated.insert(output_name);
0765 } else
0766 filesNotCreated.insert(output_name);
0767 }
0768 } else {
0769
0770 std::string output_name = output_filename_base(0) += ".json";
0771 out_file.open(output_name, std::ofstream::out);
0772 if (out_file.good()) {
0773 out_file << '{';
0774 out_file << configuration.serialise(1) << ',';
0775 out_file << vars.serialise(1) << ',';
0776
0777 out_file << indent(1) << key("events") << '[';
0778
0779
0780
0781
0782 out_file << indent(1) << ']';
0783 out_file << indent(0) << "}";
0784 out_file.close();
0785
0786 filesCreated.insert(output_name);
0787 } else
0788 filesNotCreated.insert(output_name);
0789 }
0790
0791 if (!filesCreated.empty()) {
0792 std::cout << "Created the following JSON files:" << std::endl;
0793 for (const std::string& filename : filesCreated)
0794 std::cout << " " << filename << std::endl;
0795 }
0796
0797 if (!filesNotCreated.empty()) {
0798 std::cout << "Failed to create the following JSON files (check output directory and its permissions):"
0799 << std::endl;
0800 for (const std::string& filename : filesNotCreated)
0801 std::cout << " " << filename << std::endl;
0802 }
0803 }
0804 };
0805
0806 size_t JsonOutputProducer::tab_spaces = 0;
0807
0808 class SummaryOutputProducer {
0809 private:
0810 const JsonOutputProducer& json;
0811 int run;
0812
0813 struct Pair {
0814 double v;
0815 double e;
0816
0817 Pair(double _v, double _e) : v(_v), e(_e) {}
0818 Pair(int _v, int _e) : v(_v), e(_e) {}
0819 };
0820
0821 struct Event {
0822 int run;
0823 int lumi;
0824 int event;
0825
0826 Event(int _run, int _lumi, int _event) : run(_run), lumi(_lumi), event(_event) {}
0827 bool operator<(const Event& b) const { return std::tie(run, lumi, event) < std::tie(b.run, b.lumi, b.event); }
0828 };
0829
0830 struct GenericSummary {
0831 const JsonOutputProducer& json;
0832 int id;
0833 std::string name;
0834 std::set<Event> v_gained;
0835 std::set<Event> v_lost;
0836 std::set<Event> v_changed;
0837
0838 GenericSummary(int _id, const JsonOutputProducer& _json, const std::vector<std::string>& _names)
0839 : json(_json), id(_id) {
0840 name = _names.at(id);
0841 }
0842
0843 int addEntry(const JsonOutputProducer::JsonEvent& _event, const int _triggerIndex) {
0844 const JsonOutputProducer::JsonTriggerEventState& state = _event.triggerStates.at(_triggerIndex);
0845 const Event event = Event(_event.run, _event.lumi, _event.event);
0846 int moduleId = state.o.l;
0847 if (state.o.s == State::Pass && state.n.s == State::Fail) {
0848 moduleId = state.n.l;
0849 v_lost.insert(event);
0850 } else if (state.o.s == State::Fail && state.n.s == State::Pass) {
0851 v_gained.insert(event);
0852 } else if (state.o.s == State::Fail && state.n.s == State::Fail) {
0853 v_changed.insert(event);
0854 }
0855
0856 return moduleId;
0857 }
0858
0859 Pair gained() const { return Pair(double(v_gained.size()), sqrt(double(v_gained.size()))); }
0860
0861 Pair lost() const { return Pair(double(v_lost.size()), sqrt(double(v_lost.size()))); }
0862
0863 Pair changed() const { return Pair(double(v_changed.size()), sqrt(double(v_changed.size()))); }
0864
0865 bool keepForC() const { return !v_changed.empty(); }
0866
0867 bool keepForGL() const { return !v_gained.empty() || !v_lost.empty(); }
0868 };
0869
0870 struct TriggerSummary : GenericSummary {
0871 int accepted_o;
0872 int accepted_n;
0873 std::map<int, GenericSummary> m_modules;
0874
0875 TriggerSummary(int _id, const JsonOutputProducer& _json)
0876 : GenericSummary(_id, _json, _json.vars.trigger),
0877 accepted_o(_json.vars.trigger_passed_count.at(id).first),
0878 accepted_n(_json.vars.trigger_passed_count.at(id).second) {}
0879
0880 void addEntry(const JsonOutputProducer::JsonEvent& _event,
0881 const int _triggerIndex,
0882 const std::vector<std::string>& _moduleNames) {
0883 int moduleLabelId = GenericSummary::addEntry(_event, _triggerIndex);
0884
0885 if (m_modules.count(moduleLabelId) == 0)
0886 m_modules.emplace(moduleLabelId, GenericSummary(moduleLabelId, json, _moduleNames));
0887 m_modules.at(moduleLabelId).addEntry(_event, _triggerIndex);
0888 }
0889
0890 Pair gained(int type = 0) const {
0891 Pair gained(GenericSummary::gained());
0892 if (type == 0)
0893 return gained;
0894 double all(accepted_n);
0895 Pair fraction = Pair(gained.v / (all + 1e-10), sqrt(all) / (all + 1e-10));
0896 if (type == 1)
0897 return fraction;
0898 if (type == 2)
0899 return Pair(std::max(0.0, fraction.v - fraction.e), 0.0);
0900 return Pair(fraction.v / (fraction.e + 1e-10), 0.0);
0901 }
0902
0903 Pair lost(int type = 0) const {
0904 Pair lost(GenericSummary::lost());
0905 if (type == 0)
0906 return lost;
0907 double all(accepted_o);
0908 Pair fraction = Pair(lost.v / (all + 1e-10), sqrt(all) / (all + 1e-10));
0909 if (type == 1)
0910 return fraction;
0911 if (type == 2)
0912 return Pair(std::max(0.0, fraction.v - fraction.e), 0.0);
0913 return Pair(fraction.v / (fraction.e + 1e-10), 0.0);
0914 }
0915
0916 Pair changed(int type = 0) const {
0917 Pair changed(GenericSummary::changed());
0918 if (type == 0)
0919 return changed;
0920 double all(json.configuration.events - accepted_o);
0921 Pair fraction = Pair(changed.v / (all + 1e-10), sqrt(all) / (all + 1e-10));
0922 if (type == 1)
0923 return fraction;
0924 if (type == 2)
0925 return Pair(std::max(0.0, fraction.v - fraction.e), 0.0);
0926 return Pair(fraction.v / (fraction.e + 1e-10), 0.0);
0927 }
0928 };
0929
0930 private:
0931 std::map<int, TriggerSummary> m_triggerSummary;
0932 std::map<int, GenericSummary> m_moduleSummary;
0933
0934 void prepareSummaries(const int _run, const std::vector<JsonOutputProducer::JsonEvent>& _events) {
0935 this->run = _run;
0936
0937 m_triggerSummary.clear();
0938 m_moduleSummary.clear();
0939 const size_t nTriggers(json.vars.trigger.size());
0940 const size_t nModules(json.vars.label.size());
0941 for (size_t i = 0; i < nTriggers; ++i)
0942 m_triggerSummary.emplace(i, TriggerSummary(i, json));
0943 for (size_t i = 0; i < nModules; ++i)
0944 m_moduleSummary.emplace(i, GenericSummary(i, json, json.vars.label));
0945
0946
0947 for (const JsonOutputProducer::JsonEvent& event : _events) {
0948 for (size_t iTrigger = 0; iTrigger < event.triggerStates.size(); ++iTrigger) {
0949 const JsonOutputProducer::JsonTriggerEventState& state = event.triggerStates.at(iTrigger);
0950 m_triggerSummary.at(state.tr).addEntry(event, iTrigger, json.vars.label);
0951 const int moduleId = state.o.s == State::Fail ? state.o.l : state.n.l;
0952 m_moduleSummary.at(moduleId).addEntry(event, iTrigger);
0953 }
0954 }
0955 }
0956
0957 bool writeHistograms(std::string& file_name) const {
0958
0959 file_name = json.output_filename_base(this->run) += ".root";
0960 auto out_file = new TFile(file_name.c_str(), "RECREATE");
0961 if (not out_file or out_file->IsZombie()) {
0962 out_file->Close();
0963 return false;
0964 }
0965
0966 std::map<std::string, TH1*> m_histo;
0967
0968
0969 int nTriggers(0), nTriggers_c(0), nTriggers_gl(0), nModules_c(0), nModules_gl(0);
0970
0971 for (const auto& idSummary : m_triggerSummary) {
0972 if (idSummary.second.accepted_o > 0)
0973 ++nTriggers;
0974 if (idSummary.second.keepForGL())
0975 ++nTriggers_gl;
0976 if (idSummary.second.keepForC())
0977 ++nTriggers_c;
0978 }
0979 for (const auto& idSummary : m_moduleSummary) {
0980 if (idSummary.second.keepForGL())
0981 ++nModules_gl;
0982 if (idSummary.second.keepForC())
0983 ++nModules_c;
0984 }
0985
0986 nTriggers = std::max(1, nTriggers);
0987 nTriggers_gl = std::max(1, nTriggers_gl);
0988 nTriggers_c = std::max(1, nTriggers_c);
0989 nModules_c = std::max(1, nModules_c);
0990 nModules_gl = std::max(1, nModules_gl);
0991
0992
0993 std::string name = "trigger_accepted";
0994 m_histo.emplace(name, new TH1F(name.c_str(), ";;Events accepted^{OLD}", nTriggers, 0, nTriggers));
0995 name = "trigger_gained";
0996 m_histo.emplace(name, new TH1F(name.c_str(), ";;Events gained", nTriggers_gl, 0, nTriggers_gl));
0997 name = "trigger_lost";
0998 m_histo.emplace(name, new TH1F(name.c_str(), ";;Events lost", nTriggers_gl, 0, nTriggers_gl));
0999 name = "trigger_changed";
1000 m_histo.emplace(name, new TH1F(name.c_str(), ";;Events changed", nTriggers_c, 0, nTriggers_c));
1001 name = "trigger_gained_frac";
1002 m_histo.emplace(name, new TH1F(name.c_str(), ";;#frac{gained}{accepted}", nTriggers_gl, 0, nTriggers_gl));
1003 name = "trigger_lost_frac";
1004 m_histo.emplace(name, new TH1F(name.c_str(), ";;#frac{lost}{accepted}", nTriggers_gl, 0, nTriggers_gl));
1005 name = "trigger_changed_frac";
1006 m_histo.emplace(name, new TH1F(name.c_str(), ";;#frac{changed}{all - accepted}", nTriggers_c, 0, nTriggers_c));
1007 name = "module_changed";
1008 m_histo.emplace(name, new TH1F(name.c_str(), ";;Events changed", nModules_c, 0, nModules_c));
1009 name = "module_gained";
1010 m_histo.emplace(name, new TH1F(name.c_str(), ";;Events gained", nModules_gl, 0, nModules_gl));
1011 name = "module_lost";
1012 m_histo.emplace(name, new TH1F(name.c_str(), ";;Events lost", nModules_gl, 0, nModules_gl));
1013
1014
1015 size_t bin(0), bin_c(0), bin_gl(0);
1016 for (const auto& idSummary : m_triggerSummary) {
1017 const TriggerSummary& summary = idSummary.second;
1018 if (summary.accepted_o > 0) {
1019 ++bin;
1020
1021 m_histo.at("trigger_accepted")->SetBinContent(bin, summary.accepted_o);
1022
1023 m_histo.at("trigger_accepted")->GetXaxis()->SetBinLabel(bin, summary.name.c_str());
1024 }
1025 if (summary.keepForGL()) {
1026 ++bin_gl;
1027
1028 m_histo.at("trigger_gained")->SetBinContent(bin_gl, summary.gained().v);
1029 m_histo.at("trigger_lost")->SetBinContent(bin_gl, -summary.lost().v);
1030 m_histo.at("trigger_gained_frac")->SetBinContent(bin_gl, summary.gained(1).v);
1031 m_histo.at("trigger_lost_frac")->SetBinContent(bin_gl, -summary.lost(1).v);
1032
1033 m_histo.at("trigger_gained_frac")->SetBinError(bin_gl, summary.gained(1).e);
1034 m_histo.at("trigger_lost_frac")->SetBinError(bin_gl, -summary.lost(1).e);
1035
1036 m_histo.at("trigger_gained")->GetXaxis()->SetBinLabel(bin_gl, summary.name.c_str());
1037 m_histo.at("trigger_lost")->GetXaxis()->SetBinLabel(bin_gl, summary.name.c_str());
1038 m_histo.at("trigger_gained_frac")->GetXaxis()->SetBinLabel(bin_gl, summary.name.c_str());
1039 m_histo.at("trigger_lost_frac")->GetXaxis()->SetBinLabel(bin_gl, summary.name.c_str());
1040 }
1041 if (summary.keepForC()) {
1042 ++bin_c;
1043
1044 m_histo.at("trigger_changed")->SetBinContent(bin_c, summary.changed().v);
1045 m_histo.at("trigger_changed_frac")->SetBinContent(bin_c, summary.changed(1).v);
1046
1047 m_histo.at("trigger_changed_frac")->SetBinError(bin_c, summary.changed(1).e);
1048
1049 m_histo.at("trigger_changed")->GetXaxis()->SetBinLabel(bin_c, summary.name.c_str());
1050 m_histo.at("trigger_changed_frac")->GetXaxis()->SetBinLabel(bin_c, summary.name.c_str());
1051 }
1052 }
1053
1054
1055 bin = 0;
1056 bin_c = 0;
1057 bin_gl = 0;
1058 for (const auto& idSummary : m_moduleSummary) {
1059 ++bin;
1060 const GenericSummary& summary = idSummary.second;
1061 if (summary.keepForGL()) {
1062 ++bin_gl;
1063
1064 m_histo.at("module_gained")->SetBinContent(bin_gl, summary.gained().v);
1065 m_histo.at("module_lost")->SetBinContent(bin_gl, -summary.lost().v);
1066
1067 m_histo.at("module_gained")->GetXaxis()->SetBinLabel(bin_gl, summary.name.c_str());
1068 m_histo.at("module_lost")->GetXaxis()->SetBinLabel(bin_gl, summary.name.c_str());
1069 }
1070 if (summary.keepForC()) {
1071 ++bin_c;
1072
1073 m_histo.at("module_changed")->SetBinContent(bin_c, summary.changed().v);
1074
1075 m_histo.at("module_changed")->GetXaxis()->SetBinLabel(bin_c, summary.name.c_str());
1076 }
1077 }
1078
1079
1080 for (const auto& nameHisto : m_histo) {
1081 const std::string name = nameHisto.first;
1082 TH1* histo = nameHisto.second;
1083 if (name.find("gained") != std::string::npos || name.find("changed") != std::string::npos) {
1084 if (name.find("frac") != std::string::npos)
1085 histo->GetYaxis()->SetRangeUser(0.0, 1.0);
1086 }
1087 if (name.find("lost") != std::string::npos) {
1088 if (name.find("frac") != std::string::npos)
1089 histo->GetYaxis()->SetRangeUser(-1.0, 0.0);
1090 }
1091 }
1092
1093
1094 char savePath[1000];
1095 sprintf(savePath, "DQMData/Run %d/HLT/Run summary/EventByEvent/", this->run);
1096 out_file->mkdir(savePath);
1097 gDirectory->cd(savePath);
1098 gDirectory->Write();
1099 for (const auto& nameHisto : m_histo)
1100 nameHisto.second->Write(nameHisto.first.c_str());
1101 out_file->Close();
1102
1103 return true;
1104 }
1105
1106 bool writeCSV_trigger(std::string& file_name) const {
1107 bool ret = false;
1108
1109 file_name = json.output_filename_base(this->run) += "_trigger.csv";
1110 FILE* out_file = fopen(file_name.c_str(), "w");
1111
1112 if (out_file) {
1113 fprintf(out_file,
1114 "Total,Accepted OLD,Accepted NEW,Gained,Lost,|G|/A_N + "
1115 "|L|/AO,sigma(AN)+sigma(AO),Changed,C/(T-AO),sigma(T-AO),trigger\n");
1116 for (const auto& idSummary : m_triggerSummary) {
1117 const SummaryOutputProducer::TriggerSummary& S = idSummary.second;
1118 fprintf(out_file,
1119 "%d,%d,%d,%+.f,%+.f,%.2f%%,%.2f%%,~%.f,~%.2f%%,%.2f%%,%s\n",
1120 this->json.configuration.events,
1121 S.accepted_o,
1122 S.accepted_n,
1123 S.gained().v,
1124 -1.0 * S.lost().v,
1125 (S.gained(1).v + S.lost(1).v) * 100.0,
1126 (S.gained(1).e + S.lost(1).e) * 100.0,
1127 S.changed().v,
1128 S.changed(1).v * 100.0,
1129 S.changed(1).e * 100.0,
1130 S.name.c_str());
1131 }
1132 fclose(out_file);
1133 ret = true;
1134 }
1135
1136 return ret;
1137 }
1138
1139 bool writeCSV_module(std::string& file_name) const {
1140 bool ret = false;
1141
1142 file_name = json.output_filename_base(this->run) += "_module.csv";
1143 FILE* out_file = fopen(file_name.c_str(), "w");
1144
1145 if (out_file) {
1146 fprintf(out_file, "Total,Gained,Lost,Changed,module\n");
1147 for (const auto& idSummary : m_moduleSummary) {
1148 const SummaryOutputProducer::GenericSummary& S = idSummary.second;
1149 fprintf(out_file,
1150 "%d,+%.f,-%.f,~%.f,%s\n",
1151 this->json.configuration.events,
1152 S.gained().v,
1153 S.lost().v,
1154 S.changed().v,
1155 S.name.c_str());
1156 }
1157 fclose(out_file);
1158 ret = true;
1159 }
1160
1161 return ret;
1162 }
1163
1164 public:
1165 bool storeROOT;
1166 bool storeCSV;
1167
1168 SummaryOutputProducer(const JsonOutputProducer& _json, bool _storeROOT, bool _storeCSV)
1169 : json(_json), run(0), storeROOT(_storeROOT), storeCSV(_storeCSV) {}
1170
1171 void write() {
1172 std::vector<std::string> filesCreated, filesNotCreated;
1173
1174 if (!json.m_run_events.empty()) {
1175 for (const auto& runEvents : json.m_run_events) {
1176 prepareSummaries(runEvents.first, runEvents.second);
1177 if (storeROOT) {
1178 std::string fName;
1179 auto& fNameVec = writeHistograms(fName) ? filesCreated : filesNotCreated;
1180 fNameVec.push_back(fName);
1181 }
1182 if (storeCSV) {
1183 std::string fNameTrigger;
1184 auto& fNameTriggerVec = writeCSV_trigger(fNameTrigger) ? filesCreated : filesNotCreated;
1185 fNameTriggerVec.push_back(fNameTrigger);
1186
1187 std::string fNameModule;
1188 auto& fNameModuleVec = writeCSV_module(fNameModule) ? filesCreated : filesNotCreated;
1189 fNameModuleVec.push_back(fNameModule);
1190 }
1191 }
1192 } else {
1193 if (storeROOT) {
1194 std::string fName;
1195 auto& fNameVec = writeHistograms(fName) ? filesCreated : filesNotCreated;
1196 fNameVec.push_back(fName);
1197 }
1198 if (storeCSV) {
1199 std::string fNameTrigger;
1200 auto& fNameTriggerVec = writeCSV_trigger(fNameTrigger) ? filesCreated : filesNotCreated;
1201 fNameTriggerVec.push_back(fNameTrigger);
1202
1203 std::string fNameModule;
1204 auto& fNameModuleVec = writeCSV_module(fNameModule) ? filesCreated : filesNotCreated;
1205 fNameModuleVec.push_back(fNameModule);
1206 }
1207 }
1208
1209 if (!filesCreated.empty()) {
1210 std::cout << "Created the following summary files:" << std::endl;
1211 for (const std::string& filename : filesCreated)
1212 std::cout << " " << filename << std::endl;
1213 }
1214
1215 if (!filesNotCreated.empty()) {
1216 std::cout << "Failed to create the following summary files (check output directory and its permissions):"
1217 << std::endl;
1218 for (const std::string& filename : filesNotCreated)
1219 std::cout << " " << filename << std::endl;
1220 }
1221 }
1222 };
1223
1224 bool check_file(std::string const& file) {
1225 std::unique_ptr<TFile> f(TFile::Open(file.c_str()));
1226 return (f and not f->IsZombie());
1227 }
1228
1229 bool check_files(std::vector<std::string> const& files) {
1230 bool flag = true;
1231 for (auto const& file : files)
1232 if (not check_file(file)) {
1233 flag = false;
1234 std::cerr << "hltDiff: error: file " << file << " does not exist, or is not a regular file." << std::endl;
1235 }
1236 return flag;
1237 }
1238
1239 class HltDiff {
1240 public:
1241 std::vector<std::string> old_files;
1242 std::string old_process;
1243 std::vector<std::string> new_files;
1244 std::string new_process;
1245 unsigned int max_events;
1246 bool ignore_prescales;
1247 bool csv_out;
1248 bool json_out;
1249 bool root_out;
1250 std::string output_file;
1251 bool file_check;
1252 bool debug;
1253 bool quiet;
1254 unsigned int verbose;
1255
1256 HltDiff()
1257 : old_files(0),
1258 old_process(""),
1259 new_files(0),
1260 new_process(""),
1261 max_events(1e9),
1262 ignore_prescales(true),
1263 csv_out(false),
1264 json_out(false),
1265 root_out(false),
1266 output_file(""),
1267 file_check(false),
1268 debug(false),
1269 quiet(false),
1270 verbose(0) {}
1271
1272 void compare() const {
1273 std::shared_ptr<fwlite::ChainEvent> old_events;
1274 std::shared_ptr<fwlite::ChainEvent> new_events;
1275
1276 if (not file_check or check_files(old_files))
1277 old_events = std::make_shared<fwlite::ChainEvent>(old_files);
1278 else
1279 return;
1280
1281 if (new_files.size() == 1 and new_files[0] == "-")
1282 new_events = old_events;
1283 else if (not file_check or check_files(new_files))
1284 new_events = std::make_shared<fwlite::ChainEvent>(new_files);
1285 else
1286 return;
1287
1288
1289 JsonOutputProducer json(json_out, output_file);
1290
1291 json.configuration.prescales = ignore_prescales;
1292
1293 json.configuration.o.process = old_process;
1294 json.configuration.o.files = old_files;
1295 json.configuration.o.extractFileBase();
1296
1297 json.configuration.n.process = new_process;
1298 json.configuration.n.files = new_files;
1299 json.configuration.n.extractFileBase();
1300
1301
1302 std::unique_ptr<HLTConfigDataEx> old_config_data;
1303 std::unique_ptr<HLTConfigDataEx> new_config_data;
1304 std::unique_ptr<HLTCommonConfig> common_config;
1305 HLTConfigInterface const* old_config = nullptr;
1306 HLTConfigInterface const* new_config = nullptr;
1307
1308 unsigned int counter = 0;
1309 unsigned int skipped = 0;
1310 unsigned int affected = 0;
1311 bool new_run = true;
1312 std::vector<TriggerDiff> differences;
1313
1314
1315 const unsigned int nEvents = std::min((int)old_events->size(), (int)max_events);
1316 const unsigned int counter_denominator = std::max(1, int(nEvents / 10));
1317 for (old_events->toBegin(); not old_events->atEnd(); ++(*old_events)) {
1318
1319 if (counter % (counter_denominator) == 0) {
1320 std::cout << "Processed events: " << counter << " out of " << nEvents << " ("
1321 << 10 * counter / (counter_denominator) << "%)" << std::endl;
1322 }
1323
1324
1325 edm::EventID const& id = old_events->id();
1326 if (new_events != old_events and not new_events->to(id)) {
1327 if (debug)
1328 std::cerr << "run " << id.run() << ", lumi " << id.luminosityBlock() << ", event " << id.event()
1329 << ": not found in the 'new' files, skipping." << std::endl;
1330 ++skipped;
1331 continue;
1332 }
1333
1334
1335 fwlite::Handle<edm::TriggerResults> old_results_h;
1336 edm::TriggerResults const* old_results = nullptr;
1337 old_results_h.getByLabel<fwlite::Event>(*old_events->event(), "TriggerResults", "", old_process.c_str());
1338 if (old_results_h.isValid())
1339 old_results = old_results_h.product();
1340 else {
1341 if (debug)
1342 std::cerr << "run " << id.run() << ", lumi " << id.luminosityBlock() << ", event " << id.event()
1343 << ": 'old' TriggerResults not found, skipping." << std::endl;
1344 continue;
1345 }
1346
1347 fwlite::Handle<trigger::TriggerEvent> old_summary_h;
1348 trigger::TriggerEvent const* old_summary = nullptr;
1349 old_summary_h.getByLabel<fwlite::Event>(*old_events->event(), "hltTriggerSummaryAOD", "", old_process.c_str());
1350 if (old_summary_h.isValid())
1351 old_summary = old_summary_h.product();
1352
1353 fwlite::Handle<edm::TriggerResults> new_results_h;
1354 edm::TriggerResults const* new_results = nullptr;
1355 new_results_h.getByLabel<fwlite::Event>(*new_events->event(), "TriggerResults", "", new_process.c_str());
1356 if (new_results_h.isValid())
1357 new_results = new_results_h.product();
1358 else {
1359 if (debug)
1360 std::cerr << "run " << id.run() << ", lumi " << id.luminosityBlock() << ", event " << id.event()
1361 << ": 'new' TriggerResults not found, skipping." << std::endl;
1362 continue;
1363 }
1364
1365 fwlite::Handle<trigger::TriggerEvent> new_summary_h;
1366 trigger::TriggerEvent const* new_summary = nullptr;
1367 new_summary_h.getByLabel<fwlite::Event>(*new_events->event(), "hltTriggerSummaryAOD", "", new_process.c_str());
1368 if (new_summary_h.isValid())
1369 new_summary = new_summary_h.product();
1370
1371
1372 if (new_run) {
1373 new_run = false;
1374 old_events->fillParameterSetRegistry();
1375 new_events->fillParameterSetRegistry();
1376
1377 old_config_data = getHLTConfigData(*old_events->event(), old_process);
1378 new_config_data = getHLTConfigData(*new_events->event(), new_process);
1379 if (new_config_data->triggerNames() == old_config_data->triggerNames()) {
1380 old_config = old_config_data.get();
1381 new_config = new_config_data.get();
1382 } else {
1383 common_config = std::make_unique<HLTCommonConfig>(*old_config_data, *new_config_data);
1384 old_config = &common_config->getView(HLTCommonConfig::Index::First);
1385 new_config = &common_config->getView(HLTCommonConfig::Index::Second);
1386 std::cout << "Warning: old and new TriggerResults come from different HLT menus. Only the common "
1387 << old_config->size() << " triggers are compared.\n"
1388 << std::endl;
1389 }
1390
1391 differences.clear();
1392 differences.resize(old_config->size());
1393
1394
1395 std::vector<std::string> states_str;
1396 for (int i = State::Ready; i != State::Invalid; i++)
1397 states_str.push_back(std::string(path_state(static_cast<State>(i))));
1398 json.vars.state = states_str;
1399 for (size_t triggerId = 0; triggerId < old_config->size(); ++triggerId) {
1400 json.vars.trigger.push_back(old_config->triggerName(triggerId));
1401 json.vars.trigger_passed_count.push_back(std::pair<int, int>(0, 0));
1402 }
1403
1404 for (auto const& it : old_config_data->triggerNames()) {
1405 if (std::find(json.vars.trigger.begin(), json.vars.trigger.end(), it) != json.vars.trigger.end())
1406 continue;
1407 json.configuration.o.skipped_triggers.push_back(it);
1408 }
1409
1410 for (auto const& it : new_config_data->triggerNames()) {
1411 if (std::find(json.vars.trigger.begin(), json.vars.trigger.end(), it) != json.vars.trigger.end())
1412 continue;
1413 json.configuration.n.skipped_triggers.push_back(it);
1414 }
1415 }
1416
1417
1418 bool needs_header = true;
1419 bool event_affected = false;
1420 for (unsigned int p = 0; p < old_config->size(); ++p) {
1421
1422 unsigned int old_index = old_config->triggerIndex(p);
1423 unsigned int new_index = new_config->triggerIndex(p);
1424 State old_state = prescaled_state(old_results->state(old_index), p, old_results->index(old_index), *old_config);
1425 State new_state = prescaled_state(new_results->state(new_index), p, new_results->index(new_index), *new_config);
1426
1427 if (old_state == Pass) {
1428 ++differences.at(p).count;
1429 }
1430 if (old_state == Pass)
1431 ++json.vars.trigger_passed_count.at(p).first;
1432 if (new_state == Pass)
1433 ++json.vars.trigger_passed_count.at(p).second;
1434
1435 bool trigger_affected = false;
1436 if (not ignore_prescales or (old_state != Prescaled and new_state != Prescaled)) {
1437 if (old_state == Pass and new_state != Pass) {
1438 ++differences.at(p).lost;
1439 trigger_affected = true;
1440 } else if (old_state != Pass and new_state == Pass) {
1441 ++differences.at(p).gained;
1442 trigger_affected = true;
1443 } else if (old_results->index(old_index) != new_results->index(new_index)) {
1444 ++differences.at(p).internal;
1445 trigger_affected = true;
1446 }
1447 }
1448
1449 if (not trigger_affected)
1450 continue;
1451
1452 event_affected = true;
1453 const unsigned int old_moduleIndex = old_results->index(old_index);
1454 const unsigned int new_moduleIndex = new_results->index(new_index);
1455
1456 JsonOutputProducer::JsonEvent& event = json.pushEvent(id.run(), id.luminosityBlock(), id.event());
1457 JsonOutputProducer::JsonTriggerEventState& state = event.pushTrigger(p);
1458 state.o = json.eventState(old_state,
1459 old_moduleIndex,
1460 old_config->moduleLabel(p, old_moduleIndex),
1461 old_config->moduleType(p, old_moduleIndex));
1462 state.n = json.eventState(new_state,
1463 new_moduleIndex,
1464 new_config->moduleLabel(p, new_moduleIndex),
1465 new_config->moduleType(p, new_moduleIndex));
1466
1467 if (verbose > 0) {
1468 if (needs_header) {
1469 needs_header = false;
1470 std::cout << "run " << id.run() << ", lumi " << id.luminosityBlock() << ", event " << id.event() << ": "
1471 << "old result is '" << event_state(old_results->accept()) << "', "
1472 << "new result is '" << event_state(new_results->accept()) << "'" << std::endl;
1473 }
1474
1475 std::cout << " Path " << old_config->triggerName(p) << ":\n"
1476 << " old state is ";
1477 print_detailed_path_state(std::cout, old_state, p, old_moduleIndex, *old_config);
1478 std::cout << ",\n"
1479 << " new state is ";
1480 print_detailed_path_state(std::cout, new_state, p, new_moduleIndex, *new_config);
1481 std::cout << std::endl;
1482 }
1483 if (verbose > 1 and old_summary and new_summary) {
1484
1485 unsigned int module = std::min(old_moduleIndex, new_moduleIndex);
1486 std::cout << " Filter " << old_config->moduleLabel(p, module) << ":\n";
1487 std::cout << " old trigger candidates:\n";
1488 print_trigger_candidates(std::cout,
1489 *old_summary,
1490 edm::InputTag(old_config->moduleLabel(p, module), "", old_config->processName()));
1491 std::cout << " new trigger candidates:\n";
1492 print_trigger_candidates(std::cout,
1493 *new_summary,
1494 edm::InputTag(new_config->moduleLabel(p, module), "", new_config->processName()));
1495 }
1496 if (verbose > 0)
1497 std::cout << std::endl;
1498 }
1499 if (event_affected)
1500 ++affected;
1501
1502
1503 if (event_affected and verbose > 2 and old_summary and new_summary) {
1504 std::map<std::string, std::pair<std::string, std::string>> collections;
1505 for (auto const& old_collection : old_summary->collectionTags())
1506 collections[strip_process_name(old_collection)].first = old_collection;
1507 for (auto const& new_collection : new_summary->collectionTags())
1508 collections[strip_process_name(new_collection)].second = new_collection;
1509
1510 for (auto const& collection : collections) {
1511 std::cout << " Collection " << collection.first << ":\n";
1512 std::cout << " old trigger candidates:\n";
1513 print_trigger_collection(std::cout, *old_summary, collection.second.first);
1514 std::cout << " new trigger candidates:\n";
1515 print_trigger_collection(std::cout, *new_summary, collection.second.second);
1516 std::cout << std::endl;
1517 }
1518 }
1519
1520 ++counter;
1521 if (nEvents and counter >= nEvents)
1522 break;
1523 }
1524
1525 json.configuration.events = counter;
1526
1527 if (not counter) {
1528 std::cout << "There are no common events between the old and new files";
1529 if (skipped)
1530 std::cout << ", " << skipped << " events were skipped";
1531 std::cout << "." << std::endl;
1532 } else {
1533 std::cout << "Found " << counter << " matching events, out of which " << affected
1534 << " have different HLT results";
1535 if (skipped)
1536 std::cout << ", " << skipped << " events were skipped";
1537 std::cout << "\n" << std::endl;
1538 }
1539
1540 if (!quiet and old_config) {
1541 bool summaryHeaderPrinted = false;
1542 for (size_t p = 0; p < old_config->size(); ++p) {
1543 if (differences.at(p).total() < 1)
1544 continue;
1545 if (!summaryHeaderPrinted)
1546 std::cout << std::setw(12) << "Events" << std::setw(12) << "Accepted" << std::setw(12) << "Gained"
1547 << std::setw(12) << "Lost" << std::setw(12) << "Other"
1548 << " "
1549 << "Trigger" << std::endl;
1550 std::cout << std::setw(12) << counter << differences.at(p) << " " << old_config->triggerName(p) << std::endl;
1551 summaryHeaderPrinted = true;
1552 }
1553 }
1554
1555
1556 json.write();
1557 SummaryOutputProducer summary(json, this->root_out, this->csv_out);
1558 summary.write();
1559 }
1560
1561 void usage(std::ostream& out) const {
1562 out << "\
1563 usage: hltDiff -o|--old-files FILE1.ROOT [FILE2.ROOT ...] [-O|--old-process LABEL[:INSTANCE[:PROCESS]]]\n\
1564 -n|--new-files FILE1.ROOT [FILE2.ROOT ...] [-N|--new-process LABEL[:INSTANCE[:PROCESS]]]\n\
1565 [-m|--max-events MAXEVENTS] [-p|--prescales] [-c|--csv-output] [-j|--json-output]\n\
1566 [-r|--root-output] [-f|--file-check] [-d|--debug] [-q|--quiet] [-v|--verbose]\n\
1567 [-h|--help] [-F|--output-file] FILE_NAME\n\
1568 \n\
1569 -o|--old-files FILE1.ROOT [FILE2.ROOT ...]\n\
1570 input file(s) with the old (reference) trigger results\n\
1571 \n\
1572 -O|--old-process PROCESS\n\
1573 process name of the collection with the old (reference) trigger results\n\
1574 default: take the 'TriggerResults' from the last process\n\
1575 \n\
1576 -n|--new-files FILE1.ROOT [FILE2.ROOT ...]\n\
1577 input file(s) with the new trigger results to be compared with the reference\n\
1578 to read these from a different collection in the same files as\n\
1579 the reference, use '-n -' and specify the collection with -N (see below)\n\
1580 \n\
1581 -N|--new-process PROCESS\n\
1582 process name of the collection with the new (reference) trigger results\n\
1583 default: take the 'TriggerResults' from the last process\n\
1584 \n\
1585 -m|--max-events MAXEVENTS\n\
1586 compare only the first MAXEVENTS events\n\
1587 default: compare all the events in the original (reference) files\n\
1588 \n\
1589 -p|--prescales\n\
1590 do not ignore differences caused by HLTPrescaler modules\n\
1591 \n\
1592 -c|--csv-output\n\
1593 produce comparison results in a CSV format\n\
1594 \n\
1595 -j|--json-output\n\
1596 produce comparison results in a JSON format\n\
1597 \n\
1598 -r|--root-output\n\
1599 produce comparison results as histograms in a ROOT file\n\
1600 \n\
1601 -F|--output-file FILE_NAME\n\
1602 combine all RUNs to files with the specified custom name: FILE_NAME.json, FILE_NAME.root\n\
1603 default: a separate output file will be produced for each RUN with names suitable for the DQM GUI\n\
1604 \n\
1605 -f|--file-check\n\
1606 check existence of every old and new file before running the comparison\n\
1607 safer if files are run for the first time, but can cause a substantial delay\n\
1608 \n\
1609 -d|--debug\n\
1610 display messages about missing events and collections\n\
1611 \n\
1612 -q|--quiet\n\
1613 don't display summary printout with the list of affected trigger paths\n\
1614 \n\
1615 -v|--verbose LEVEL\n\
1616 set verbosity level:\n\
1617 1: event-by-event comparison results\n\
1618 2: + print the trigger candidates of the affected filters\n\
1619 3: + print all the trigger candidates for the affected events\n\
1620 default: 1\n\
1621 \n\
1622 -h|--help\n\
1623 print this help message, and exit"
1624 << std::endl;
1625 }
1626 };
1627
1628 int main(int argc, char** argv) {
1629
1630 const char optstring[] = "dfo:O:n:N:m:pcjrF:v::hq";
1631 const option longopts[] = {
1632 option{"debug", no_argument, nullptr, 'd'},
1633 option{"file-check", no_argument, nullptr, 'f'},
1634 option{"old-files", required_argument, nullptr, 'o'},
1635 option{"old-process", required_argument, nullptr, 'O'},
1636 option{"new-files", required_argument, nullptr, 'n'},
1637 option{"new-process", required_argument, nullptr, 'N'},
1638 option{"max-events", required_argument, nullptr, 'm'},
1639 option{"prescales", no_argument, nullptr, 'p'},
1640 option{"csv-output", optional_argument, nullptr, 'c'},
1641 option{"json-output", optional_argument, nullptr, 'j'},
1642 option{"root-output", optional_argument, nullptr, 'r'},
1643 option{"output-file", optional_argument, nullptr, 'F'},
1644 option{"verbose", optional_argument, nullptr, 'v'},
1645 option{"help", no_argument, nullptr, 'h'},
1646 option{"quiet", no_argument, nullptr, 'q'},
1647 };
1648
1649
1650 auto hlt = new HltDiff();
1651
1652
1653 int c = -1;
1654 while ((c = getopt_long(argc, argv, optstring, longopts, nullptr)) != -1) {
1655 switch (c) {
1656 case 'd':
1657 hlt->debug = true;
1658 break;
1659
1660 case 'f':
1661 hlt->file_check = true;
1662 break;
1663
1664 case 'o':
1665 hlt->old_files.emplace_back(optarg);
1666 while (optind < argc) {
1667 if (argv[optind][0] == '-')
1668 break;
1669 hlt->old_files.emplace_back(argv[optind]);
1670 ++optind;
1671 }
1672 break;
1673
1674 case 'O':
1675 hlt->old_process = optarg;
1676 break;
1677
1678 case 'n':
1679 hlt->new_files.emplace_back(optarg);
1680 while (optind < argc) {
1681 if (argv[optind][0] == '-')
1682 break;
1683 hlt->new_files.emplace_back(argv[optind]);
1684 ++optind;
1685 }
1686 break;
1687
1688 case 'N':
1689 hlt->new_process = optarg;
1690 break;
1691
1692 case 'm':
1693 hlt->max_events = atoi(optarg);
1694 break;
1695
1696 case 'p':
1697 hlt->ignore_prescales = false;
1698 break;
1699
1700 case 'c':
1701 hlt->csv_out = true;
1702 break;
1703
1704 case 'j':
1705 hlt->json_out = true;
1706 break;
1707
1708 case 'r':
1709 hlt->root_out = true;
1710 break;
1711
1712 case 'F':
1713 hlt->output_file = optarg;
1714 break;
1715
1716 case 'v':
1717 hlt->verbose = 1;
1718 if (optarg) {
1719 hlt->verbose = std::max(1, atoi(optarg));
1720 } else if (!optarg && nullptr != argv[optind] && '-' != argv[optind][0]) {
1721
1722 const char* tmp_optarg = argv[optind++];
1723 hlt->verbose = std::max(1, atoi(tmp_optarg));
1724 }
1725 break;
1726
1727 case 'h':
1728 hlt->usage(std::cerr);
1729 exit(0);
1730 break;
1731
1732 case 'q':
1733 hlt->quiet = true;
1734 break;
1735
1736 default:
1737 error(std::cerr);
1738 exit(1);
1739 break;
1740 }
1741 }
1742
1743 if (hlt->old_files.empty()) {
1744 error(std::cerr, "hltDiff: please specify the 'old' file(s)");
1745 exit(1);
1746 }
1747 if (hlt->new_files.empty()) {
1748 error(std::cerr, "hltDiff: please specify the 'new' file(s)");
1749 exit(1);
1750 }
1751
1752 hlt->compare();
1753
1754 return 0;
1755 }