24 #include <boost/algorithm/string.hpp>
30 #include <TGraphAsymmErrors.h>
43 void error(std::ostream&
out) {
out <<
"Try 'hltDiff --help' for more information" << std::endl; }
45 void error(std::ostream&
out,
const char* message) {
46 out << message << std::endl;
51 out << message << std::endl;
59 virtual unsigned int size()
const = 0;
60 virtual unsigned int size(
unsigned int trigger)
const = 0;
122 ~View()
override =
default;
124 unsigned int size()
const override;
125 unsigned int size(
unsigned int trigger)
const override;
139 for (
unsigned int f = 0;
f <
first.size(); ++
f)
140 for (
unsigned int s = 0;
s <
second.size(); ++
s)
222 return config_.triggerName(index_,
trigger);
226 return config_.triggerIndex(index_,
trigger);
251 static const char* message[] = {
"not run",
"accepted",
"rejected",
"exception",
"prescaled",
"invalid"};
254 return message[
state];
275 size_t end =
s.find_last_of(
':');
276 if (
end > 0 and
s.at(
end - 1) ==
':')
279 return s.substr(0,
end);
303 out <<
" not found\n";
318 <<
"filter id: " <<
id <<
", "
319 <<
"object id: " << candidate.
id() <<
", "
320 <<
"pT: " << candidate.
pt() <<
", "
321 <<
"eta: " << candidate.
eta() <<
", "
322 <<
"phi: " << candidate.
phi() <<
", "
323 <<
"mass: " << candidate.
mass() <<
"\n";
329 if (iterator ==
summary.collectionTags().end()) {
331 out <<
" not found\n";
335 unsigned int index = iterator -
summary.collectionTags().begin();
348 <<
"object id: " << candidate.
id() <<
", "
349 <<
"pT: " << candidate.
pt() <<
", "
350 <<
"eta: " << candidate.
eta() <<
", "
351 <<
"phi: " << candidate.
phi() <<
", "
352 <<
"mass: " << candidate.
mass() <<
"\n";
357 std::vector<boost::iterator_range<std::string::const_iterator>> tokens;
359 return boost::copy_range<std::string>(tokens[3]);
363 auto const& history =
event.processHistory();
372 if (not history.getConfigurationForProcess(
process,
config)) {
373 std::cerr <<
"error: the process " <<
process <<
" is not in the Process History" << std::endl;
377 if (
pset ==
nullptr) {
378 std::cerr <<
"error: the configuration for the process " <<
process <<
" is not available in the Provenance"
391 unsigned int internal;
400 unsigned int digit = 10;
411 unsigned int total()
const {
return this->gained + this->lost + this->
internal; }
428 int nSpaces = tab_spaces;
457 str.append(std::to_string(_int));
464 str.insert(1, _string);
472 for (
auto it = _values.begin(); it != _values.end(); ++it) {
477 if (it != --_values.end())
498 std::ostringstream
json;
500 json << key_string(
"file_base", file_base) <<
',';
506 json <<
key(
"skipped_triggers") << list_string(skipped_triggers);
514 for (
size_t i = 0;
i < file0.length(); ++
i) {
515 bool identicalInAll =
true;
516 char character = file0.at(
i);
518 if (
file.at(
i) == character)
520 identicalInAll =
false;
525 file_base.push_back(character);
527 const unsigned int file_base_len = file_base.length();
528 if (file_base_len < 1)
532 file.erase(0, file_base_len);
546 std::ostringstream
json;
549 json <<
o.serialise(_indent + 2);
552 json <<
n.serialise(_indent + 2);
555 json <<
indent(_indent + 1) <<
key(
"prescales") << prescales_str <<
',';
573 std::ostringstream
json;
577 json <<
indent(_indent + 1) <<
key(
"trigger_passed_count") <<
'[';
578 for (
auto it = trigger_passed_count.begin(); it != trigger_passed_count.end(); ++it) {
579 json <<
'{' <<
key(
"o") << (*it).first <<
',' <<
key(
"n") << (*it).second <<
'}';
580 if (it != trigger_passed_count.end() - 1)
601 if (
id <
vars.label.size())
603 vars.label.push_back(labelName);
604 return vars.label.size() - 1;
609 if (
id <
vars.type.size())
612 return vars.type.size() - 1;
623 std::ostringstream
json;
624 json << key_int(
"s",
int(
s));
629 json << key_int(
"m",
m) <<
',';
630 json << key_int(
"l",
l) <<
',';
631 json << key_int(
"t",
t);
646 std::ostringstream
json;
647 json <<
indent(_indent) << key_int(
"t", tr) <<
',';
648 json <<
indent(_indent) <<
key(
"o") <<
'{' <<
o.serialise() <<
"},";
649 json <<
indent(_indent) <<
key(
"n") <<
'{' <<
n.serialise() <<
"}";
665 std::ostringstream
json;
666 json <<
indent(_indent) <<
'{' <<
"\"r\"" <<
':' <<
run <<
",\"l\":" <<
lumi <<
",\"e\":" <<
event
668 for (
auto it = triggerStates.begin(); it != triggerStates.end(); ++it) {
670 json << (*it).serialise(_indent + 2);
672 if (it != --triggerStates.end())
684 if (!triggerStates.empty()) {
686 if (lastTrigger.
tr == _tr)
690 return triggerStates.back();
699 : writeJson(_writeJson), out_filename_base(
std::
move(_file_name)) {
700 useSingleOutFile = out_filename_base.length() > 0;
705 if ((m_run_events.count(_run) == 0 && !useSingleOutFile) || m_run_events.empty())
706 m_run_events.emplace(_run, std::vector<JsonEvent>());
707 std::vector<JsonEvent>& v_events = useSingleOutFile ? m_run_events.begin()->second : m_run_events.at(_run);
709 if (!v_events.empty()) {
714 v_events.push_back(
JsonEvent(_run, _lumi, _event));
715 return v_events.back();
723 if (useSingleOutFile)
724 return out_filename_base;
728 "DQM_V0001_R%.9d__OLD_%s__NEW_%s_DQM",
739 std::set<std::string> filesCreated, filesNotCreated;
741 if (!m_run_events.empty()) {
743 for (
const auto& runEvents : m_run_events) {
744 const int run = runEvents.first;
745 const std::vector<JsonEvent>& v_events = runEvents.second;
755 for (
auto it = v_events.begin(); it != v_events.end(); ++it) {
757 if (it != --v_events.end())
764 filesCreated.insert(output_name);
766 filesNotCreated.insert(output_name);
770 std::string output_name = output_filename_base(0) +=
".json";
786 filesCreated.insert(output_name);
788 filesNotCreated.insert(output_name);
791 if (!filesCreated.empty()) {
792 std::cout <<
"Created the following JSON files:" << std::endl;
797 if (!filesNotCreated.empty()) {
798 std::cout <<
"Failed to create the following JSON files (check output directory and its permissions):"
817 Pair(
double _v,
double _e) :
v(_v),
e(_e){};
840 name = _names.at(
id);
849 v_lost.insert(
event);
851 v_gained.insert(
event);
853 v_changed.insert(
event);
865 bool keepForC()
const {
return !v_changed.empty(); }
867 bool keepForGL()
const {
return !v_gained.empty() || !v_lost.empty(); }
877 accepted_o(_json.
vars.trigger_passed_count.at(
id).
first),
878 accepted_n(_json.
vars.trigger_passed_count.at(
id).
second) {}
881 const int _triggerIndex,
882 const std::vector<std::string>& _moduleNames) {
883 int moduleLabelId = GenericSummary::addEntry(_event, _triggerIndex);
885 if (m_modules.count(moduleLabelId) == 0)
887 m_modules.at(moduleLabelId).addEntry(_event, _triggerIndex);
891 Pair gained(GenericSummary::gained());
894 double all(accepted_n);
904 Pair lost(GenericSummary::lost());
907 double all(accepted_o);
917 Pair changed(GenericSummary::changed());
920 double all(
json.configuration.events - accepted_o);
934 void prepareSummaries(
const int _run,
const std::vector<JsonOutputProducer::JsonEvent>& _events) {
937 m_triggerSummary.clear();
938 m_moduleSummary.clear();
939 const size_t nTriggers(
json.vars.trigger.size());
940 const size_t nModules(
json.vars.label.size());
941 for (
size_t i = 0;
i < nTriggers; ++
i)
943 for (
size_t i = 0;
i < nModules; ++
i)
948 for (
size_t iTrigger = 0; iTrigger <
event.triggerStates.size(); ++iTrigger) {
950 m_triggerSummary.at(
state.tr).addEntry(
event, iTrigger,
json.vars.label);
966 std::map<std::string, TH1*> m_histo;
969 int nTriggers(0), nTriggers_c(0), nTriggers_gl(0), nModules_c(0), nModules_gl(0);
971 for (
const auto& idSummary : m_triggerSummary) {
972 if (idSummary.second.accepted_o > 0)
974 if (idSummary.second.keepForGL())
976 if (idSummary.second.keepForC())
979 for (
const auto& idSummary : m_moduleSummary) {
980 if (idSummary.second.keepForGL())
982 if (idSummary.second.keepForC())
987 nTriggers_gl =
std::max(1, nTriggers_gl);
988 nTriggers_c =
std::max(1, nTriggers_c);
989 nModules_c =
std::max(1, nModules_c);
990 nModules_gl =
std::max(1, nModules_gl);
994 m_histo.emplace(
name,
new TH1F(
name.c_str(),
";;Events accepted^{OLD}", nTriggers, 0, nTriggers));
995 name =
"trigger_gained";
996 m_histo.emplace(
name,
new TH1F(
name.c_str(),
";;Events gained", nTriggers_gl, 0, nTriggers_gl));
997 name =
"trigger_lost";
998 m_histo.emplace(
name,
new TH1F(
name.c_str(),
";;Events lost", nTriggers_gl, 0, nTriggers_gl));
999 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));
1015 size_t bin(0), bin_c(0), bin_gl(0);
1016 for (
const auto& idSummary : m_triggerSummary) {
1021 m_histo.at(
"trigger_accepted")->SetBinContent(
bin,
summary.accepted_o);
1023 m_histo.at(
"trigger_accepted")->GetXaxis()->SetBinLabel(
bin,
summary.name.c_str());
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);
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);
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());
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);
1047 m_histo.at(
"trigger_changed_frac")->SetBinError(bin_c,
summary.changed(1).e);
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());
1058 for (
const auto& idSummary : m_moduleSummary) {
1064 m_histo.at(
"module_gained")->SetBinContent(bin_gl,
summary.gained().v);
1065 m_histo.at(
"module_lost")->SetBinContent(bin_gl, -
summary.lost().v);
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());
1073 m_histo.at(
"module_changed")->SetBinContent(bin_c,
summary.changed().v);
1075 m_histo.at(
"module_changed")->GetXaxis()->SetBinLabel(bin_c,
summary.name.c_str());
1080 for (
const auto& nameHisto : m_histo) {
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);
1087 if (
name.find(
"lost") != std::string::npos) {
1088 if (
name.find(
"frac") != std::string::npos)
1089 histo->GetYaxis()->SetRangeUser(-1.0, 0.0);
1094 char savePath[1000];
1095 sprintf(savePath,
"DQMData/Run %d/HLT/Run summary/EventByEvent/", this->run);
1097 gDirectory->cd(savePath);
1098 gDirectory->Write();
1099 for (
const auto& nameHisto : m_histo)
1100 nameHisto.second->Write(nameHisto.first.c_str());
1109 file_name =
json.output_filename_base(this->run) +=
"_trigger.csv";
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) {
1119 "%d,%d,%d,%+.f,%+.f,%.2f%%,%.2f%%,~%.f,~%.2f%%,%.2f%%,%s\n",
1125 (
S.gained(1).v +
S.lost(1).v) * 100.0,
1126 (
S.gained(1).e +
S.lost(1).e) * 100.0,
1128 S.changed(1).v * 100.0,
1129 S.changed(1).e * 100.0,
1142 file_name =
json.output_filename_base(this->run) +=
"_module.csv";
1146 fprintf(
out_file,
"Total,Gained,Lost,Changed,module\n");
1147 for (
const auto& idSummary : m_moduleSummary) {
1150 "%d,+%.f,-%.f,~%.f,%s\n",
1172 std::vector<std::string> filesCreated, filesNotCreated;
1174 if (!
json.m_run_events.empty()) {
1175 for (
const auto& runEvents :
json.m_run_events) {
1176 prepareSummaries(runEvents.first, runEvents.second);
1179 auto& fNameVec = writeHistograms(
fName) ? filesCreated : filesNotCreated;
1180 fNameVec.push_back(
fName);
1184 auto& fNameTriggerVec = writeCSV_trigger(fNameTrigger) ? filesCreated : filesNotCreated;
1185 fNameTriggerVec.push_back(fNameTrigger);
1188 auto& fNameModuleVec = writeCSV_module(fNameModule) ? filesCreated : filesNotCreated;
1189 fNameModuleVec.push_back(fNameModule);
1195 auto& fNameVec = writeHistograms(
fName) ? filesCreated : filesNotCreated;
1196 fNameVec.push_back(
fName);
1200 auto& fNameTriggerVec = writeCSV_trigger(fNameTrigger) ? filesCreated : filesNotCreated;
1201 fNameTriggerVec.push_back(fNameTrigger);
1204 auto& fNameModuleVec = writeCSV_module(fNameModule) ? filesCreated : filesNotCreated;
1205 fNameModuleVec.push_back(fNameModule);
1209 if (!filesCreated.empty()) {
1210 std::cout <<
"Created the following summary files:" << std::endl;
1215 if (!filesNotCreated.empty()) {
1216 std::cout <<
"Failed to create the following summary files (check output directory and its permissions):"
1225 std::unique_ptr<TFile>
f(TFile::Open(
file.c_str()));
1226 return (
f and not
f->IsZombie());
1234 std::cerr <<
"hltDiff: error: file " <<
file <<
" does not exist, or is not a regular file." << std::endl;
1262 ignore_prescales(
true),
1273 std::shared_ptr<fwlite::ChainEvent> old_events;
1274 std::shared_ptr<fwlite::ChainEvent> new_events;
1277 old_events = std::make_shared<fwlite::ChainEvent>(old_files);
1281 if (new_files.size() == 1 and new_files[0] ==
"-")
1282 new_events = old_events;
1284 new_events = std::make_shared<fwlite::ChainEvent>(new_files);
1291 json.configuration.prescales = ignore_prescales;
1293 json.configuration.o.process = old_process;
1294 json.configuration.o.files = old_files;
1295 json.configuration.o.extractFileBase();
1297 json.configuration.n.process = new_process;
1298 json.configuration.n.files = new_files;
1299 json.configuration.n.extractFileBase();
1302 std::unique_ptr<HLTConfigDataEx> old_config_data;
1303 std::unique_ptr<HLTConfigDataEx> new_config_data;
1304 std::unique_ptr<HLTCommonConfig> common_config;
1310 unsigned int affected = 0;
1311 bool new_run =
true;
1312 std::vector<TriggerDiff> differences;
1316 const unsigned int counter_denominator =
std::max(1,
int(
nEvents / 10));
1317 for (old_events->toBegin(); not old_events->atEnd(); ++(*old_events)) {
1319 if (
counter % (counter_denominator) == 0) {
1321 << 10 *
counter / (counter_denominator) <<
"%)" << std::endl;
1326 if (new_events != old_events and not new_events->to(
id)) {
1328 std::cerr <<
"run " <<
id.run() <<
", lumi " <<
id.luminosityBlock() <<
", event " <<
id.event()
1329 <<
": not found in the 'new' files, skipping." << std::endl;
1339 old_results = old_results_h.
product();
1342 std::cerr <<
"run " <<
id.run() <<
", lumi " <<
id.luminosityBlock() <<
", event " <<
id.event()
1343 <<
": 'old' TriggerResults not found, skipping." << std::endl;
1349 old_summary_h.
getByLabel<
fwlite::Event>(*old_events->event(),
"hltTriggerSummaryAOD",
"", old_process.c_str());
1351 old_summary = old_summary_h.
product();
1357 new_results = new_results_h.
product();
1360 std::cerr <<
"run " <<
id.run() <<
", lumi " <<
id.luminosityBlock() <<
", event " <<
id.event()
1361 <<
": 'new' TriggerResults not found, skipping." << std::endl;
1367 new_summary_h.
getByLabel<
fwlite::Event>(*new_events->event(),
"hltTriggerSummaryAOD",
"", new_process.c_str());
1369 new_summary = new_summary_h.
product();
1374 old_events->fillParameterSetRegistry();
1375 new_events->fillParameterSetRegistry();
1379 if (new_config_data->triggerNames() == old_config_data->triggerNames()) {
1380 old_config = old_config_data.get();
1381 new_config = new_config_data.get();
1383 common_config = std::make_unique<HLTCommonConfig>(*old_config_data, *new_config_data);
1386 std::cout <<
"Warning: old and new TriggerResults come from different HLT menus. Only the common "
1387 << old_config->
size() <<
" triggers are compared.\n"
1391 differences.clear();
1392 differences.resize(old_config->
size());
1395 std::vector<std::string> states_str;
1398 json.vars.state = states_str;
1399 for (
size_t triggerId = 0; triggerId < old_config->
size(); ++triggerId) {
1401 json.vars.trigger_passed_count.push_back(std::pair<int, int>(0, 0));
1404 for (
auto const& it : old_config_data->triggerNames()) {
1407 json.configuration.o.skipped_triggers.push_back(it);
1410 for (
auto const& it : new_config_data->triggerNames()) {
1413 json.configuration.n.skipped_triggers.push_back(it);
1418 bool needs_header =
true;
1419 bool event_affected =
false;
1420 for (
unsigned int p = 0;
p < old_config->
size(); ++
p) {
1427 if (old_state ==
Pass) {
1428 ++differences.at(
p).count;
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;
1435 bool trigger_affected =
false;
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;
1449 if (not trigger_affected)
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);
1469 needs_header =
false;
1470 std::cout <<
"run " <<
id.run() <<
", lumi " <<
id.luminosityBlock() <<
", event " <<
id.event() <<
": "
1476 <<
" old state is ";
1479 <<
" new state is ";
1483 if (
verbose > 1 and old_summary and new_summary) {
1485 unsigned int module =
std::min(old_moduleIndex, new_moduleIndex);
1487 std::cout <<
" old trigger candidates:\n";
1491 std::cout <<
" new trigger candidates:\n";
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;
1507 for (
auto const& new_collection : new_summary->collectionTags())
1512 std::cout <<
" old trigger candidates:\n";
1514 std::cout <<
" new trigger candidates:\n";
1528 std::cout <<
"There are no common events between the old and new files";
1533 std::cout <<
"Found " <<
counter <<
" matching events, out of which " << affected
1534 <<
" have different HLT results";
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)
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"
1549 <<
"Trigger" << std::endl;
1550 std::cout << std::setw(12) <<
counter << differences.at(
p) <<
" " << old_config->triggerName(
p) << std::endl;
1551 summaryHeaderPrinted =
true;
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\
1569 -o|--old-files FILE1.ROOT [FILE2.ROOT ...]\n\
1570 input file(s) with the old (reference) trigger results\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\
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\
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\
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\
1590 do not ignore differences caused by HLTPrescaler modules\n\
1593 produce comparison results in a CSV format\n\
1596 produce comparison results in a JSON format\n\
1599 produce comparison results as histograms in a ROOT file\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\
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\
1610 display messages about missing events and collections\n\
1613 don't display summary printout with the list of affected trigger paths\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\
1623 print this help message, and exit"
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'},
1654 while ((
c = getopt_long(
argc,
argv, optstring, longopts,
nullptr)) != -1) {
1661 hlt->file_check =
true;
1665 hlt->old_files.emplace_back(optarg);
1666 while (optind <
argc) {
1667 if (
argv[optind][0] ==
'-')
1669 hlt->old_files.emplace_back(
argv[optind]);
1675 hlt->old_process = optarg;
1679 hlt->new_files.emplace_back(optarg);
1680 while (optind <
argc) {
1681 if (
argv[optind][0] ==
'-')
1683 hlt->new_files.emplace_back(
argv[optind]);
1689 hlt->new_process = optarg;
1693 hlt->max_events = atoi(optarg);
1697 hlt->ignore_prescales =
false;
1701 hlt->csv_out =
true;
1705 hlt->json_out =
true;
1709 hlt->root_out =
true;
1713 hlt->output_file = optarg;
1720 }
else if (!optarg &&
nullptr !=
argv[optind] &&
'-' !=
argv[optind][0]) {
1722 const char* tmp_optarg =
argv[optind++];
1743 if (
hlt->old_files.empty()) {
1747 if (
hlt->new_files.empty()) {