24 #include <boost/algorithm/string.hpp>
25 #include <boost/filesystem.hpp>
31 #include <TGraphAsymmErrors.h>
44 void error(std::ostream&
out) {
out <<
"Try 'hltDiff --help' for more information" << std::endl; }
46 void error(std::ostream&
out,
const char* message) {
47 out << message << std::endl;
52 out << message << std::endl;
60 virtual unsigned int size()
const = 0;
61 virtual unsigned int size(
unsigned int trigger)
const = 0;
114 const char*
event_state(
bool state) {
return state ?
"accepted" :
"rejected"; }
123 ~View()
override =
default;
125 unsigned int size()
const override;
126 unsigned int size(
unsigned int trigger)
const override;
140 for (
unsigned int f = 0;
f <
first.size(); ++
f)
141 for (
unsigned int s = 0;
s <
second.size(); ++
s)
223 return config_.triggerName(index_,
trigger);
227 return config_.triggerIndex(index_,
trigger);
252 static const char* message[] = {
"not run",
"accepted",
"rejected",
"exception",
"prescaled",
"invalid"};
254 if (state > 0 and state <
Invalid)
255 return message[state];
276 size_t end =
s.find_last_of(
':');
277 if (
end > 0 and
s.at(
end - 1) ==
':')
280 return s.substr(0,
end);
304 out <<
" not found\n";
319 <<
"filter id: " <<
id <<
", "
320 <<
"object id: " << candidate.
id() <<
", "
321 <<
"pT: " << candidate.
pt() <<
", "
322 <<
"eta: " << candidate.
eta() <<
", "
323 <<
"phi: " << candidate.
phi() <<
", "
324 <<
"mass: " << candidate.
mass() <<
"\n";
330 if (iterator ==
summary.collectionTags().end()) {
332 out <<
" not found\n";
336 unsigned int index = iterator -
summary.collectionTags().begin();
349 <<
"object id: " << candidate.
id() <<
", "
350 <<
"pT: " << candidate.
pt() <<
", "
351 <<
"eta: " << candidate.
eta() <<
", "
352 <<
"phi: " << candidate.
phi() <<
", "
353 <<
"mass: " << candidate.
mass() <<
"\n";
358 std::vector<boost::iterator_range<std::string::const_iterator>> tokens;
360 return boost::copy_range<std::string>(tokens[3]);
364 auto const& history =
event.processHistory();
373 if (not history.getConfigurationForProcess(
process,
config)) {
374 std::cerr <<
"error: the process " <<
process <<
" is not in the Process History" << std::endl;
378 if (
pset ==
nullptr) {
379 std::cerr <<
"error: the configuration for the process " <<
process <<
" is not available in the Provenance"
392 unsigned int internal;
401 unsigned int digit = 10;
412 unsigned int total()
const {
return this->gained + this->lost + this->
internal; }
429 int nSpaces = tab_spaces;
458 str.append(std::to_string(_int));
465 str.insert(1, _string);
473 for (
auto it = _values.begin(); it != _values.end(); ++it) {
478 if (it != --_values.end())
499 std::ostringstream
json;
501 json << key_string(
"file_base", file_base) <<
',';
507 json <<
key(
"skipped_triggers") << list_string(skipped_triggers);
515 for (
size_t i = 0;
i < file0.length(); ++
i) {
516 bool identicalInAll =
true;
517 char character = file0.at(
i);
519 if (
file.at(
i) == character)
521 identicalInAll =
false;
526 file_base.push_back(character);
528 const unsigned int file_base_len = file_base.length();
529 if (file_base_len < 1)
533 file.erase(0, file_base_len);
547 std::ostringstream
json;
550 json <<
o.serialise(_indent + 2);
553 json <<
n.serialise(_indent + 2);
556 json <<
indent(_indent + 1) <<
key(
"prescales") << prescales_str <<
',';
574 std::ostringstream
json;
576 json <<
indent(_indent + 1) <<
key(
"state") << list_string(state) <<
',';
578 json <<
indent(_indent + 1) <<
key(
"trigger_passed_count") <<
'[';
579 for (
auto it = trigger_passed_count.begin(); it != trigger_passed_count.end(); ++it) {
580 json <<
'{' <<
key(
"o") << (*it).first <<
',' <<
key(
"n") << (*it).second <<
'}';
581 if (it != trigger_passed_count.end() - 1)
602 if (
id <
vars.label.size())
604 vars.label.push_back(labelName);
605 return vars.label.size() - 1;
610 if (
id <
vars.type.size())
613 return vars.type.size() - 1;
624 std::ostringstream
json;
625 json << key_int(
"s",
int(
s));
630 json << key_int(
"m",
m) <<
',';
631 json << key_int(
"l",
l) <<
',';
632 json << key_int(
"t",
t);
647 std::ostringstream
json;
648 json <<
indent(_indent) << key_int(
"t", tr) <<
',';
649 json <<
indent(_indent) <<
key(
"o") <<
'{' <<
o.serialise() <<
"},";
650 json <<
indent(_indent) <<
key(
"n") <<
'{' <<
n.serialise() <<
"}";
666 std::ostringstream
json;
667 json <<
indent(_indent) <<
'{' <<
"\"r\"" <<
':' <<
run <<
",\"l\":" <<
lumi <<
",\"e\":" <<
event
669 for (
auto it = triggerStates.begin(); it != triggerStates.end(); ++it) {
671 json << (*it).serialise(_indent + 2);
673 if (it != --triggerStates.end())
685 if (!triggerStates.empty()) {
687 if (lastTrigger.
tr == _tr)
691 return triggerStates.back();
700 : writeJson(_writeJson), out_filename_base(
std::
move(_file_name)) {
701 useSingleOutFile = out_filename_base.length() > 0;
706 if ((m_run_events.count(_run) == 0 && !useSingleOutFile) || m_run_events.empty())
707 m_run_events.emplace(_run, std::vector<JsonEvent>());
708 std::vector<JsonEvent>& v_events = useSingleOutFile ? m_run_events.begin()->second : m_run_events.at(_run);
710 if (!v_events.empty()) {
715 v_events.push_back(
JsonEvent(_run, _lumi, _event));
716 return v_events.back();
724 if (useSingleOutFile)
725 return out_filename_base;
729 "DQM_V0001_R%.9d__OLD_%s__NEW_%s_DQM",
740 std::set<std::string> filesCreated;
742 if (!m_run_events.empty()) {
744 for (
const auto& runEvents : m_run_events) {
745 const int run = runEvents.first;
746 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);
768 std::string output_name = output_filename_base(0) +=
".json";
783 filesCreated.insert(output_name);
786 if (!filesCreated.empty()) {
787 std::cout <<
"Created the following JSON files:" << std::endl;
804 Pair(
double _v,
double _e) :
v(_v),
e(_e){};
827 name = _names.at(
id);
833 int moduleId = state.
o.
l;
835 moduleId = state.
n.
l;
836 v_lost.insert(
event);
838 v_gained.insert(
event);
840 v_changed.insert(
event);
852 bool keepForC()
const {
return !v_changed.empty(); }
854 bool keepForGL()
const {
return !v_gained.empty() || !v_lost.empty(); }
864 accepted_o(_json.
vars.trigger_passed_count.at(
id).
first),
865 accepted_n(_json.
vars.trigger_passed_count.at(
id).
second) {}
868 const int _triggerIndex,
869 const std::vector<std::string>& _moduleNames) {
870 int moduleLabelId = GenericSummary::addEntry(_event, _triggerIndex);
872 if (m_modules.count(moduleLabelId) == 0)
874 m_modules.at(moduleLabelId).addEntry(_event, _triggerIndex);
878 Pair gained(GenericSummary::gained());
881 double all(accepted_n);
891 Pair lost(GenericSummary::lost());
894 double all(accepted_o);
904 Pair changed(GenericSummary::changed());
907 double all(
json.configuration.events - accepted_o);
921 void prepareSummaries(
const int _run,
const std::vector<JsonOutputProducer::JsonEvent>& _events) {
924 m_triggerSummary.clear();
925 m_moduleSummary.clear();
926 const size_t nTriggers(
json.vars.trigger.size());
927 const size_t nModules(
json.vars.label.size());
928 for (
size_t i = 0;
i < nTriggers; ++
i)
930 for (
size_t i = 0;
i < nModules; ++
i)
935 for (
size_t iTrigger = 0; iTrigger <
event.triggerStates.size(); ++iTrigger) {
937 m_triggerSummary.at(state.
tr).addEntry(
event, iTrigger,
json.vars.label);
939 m_moduleSummary.at(moduleId).addEntry(
event, iTrigger);
945 std::map<std::string, TH1*> m_histo;
948 int nTriggers(0), nTriggers_c(0), nTriggers_gl(0), nModules_c(0), nModules_gl(0);
950 for (
const auto& idSummary : m_triggerSummary) {
951 if (idSummary.second.accepted_o > 0)
953 if (idSummary.second.keepForGL())
955 if (idSummary.second.keepForC())
958 for (
const auto& idSummary : m_moduleSummary) {
959 if (idSummary.second.keepForGL())
961 if (idSummary.second.keepForC())
966 nTriggers_gl =
std::max(1, nTriggers_gl);
967 nTriggers_c =
std::max(1, nTriggers_c);
968 nModules_c =
std::max(1, nModules_c);
969 nModules_gl =
std::max(1, nModules_gl);
973 m_histo.emplace(
name,
new TH1F(
name.c_str(),
";;Events accepted^{OLD}", nTriggers, 0, nTriggers));
974 name =
"trigger_gained";
975 m_histo.emplace(
name,
new TH1F(
name.c_str(),
";;Events gained", nTriggers_gl, 0, nTriggers_gl));
976 name =
"trigger_lost";
977 m_histo.emplace(
name,
new TH1F(
name.c_str(),
";;Events lost", nTriggers_gl, 0, nTriggers_gl));
978 name =
"trigger_changed";
979 m_histo.emplace(
name,
new TH1F(
name.c_str(),
";;Events changed", nTriggers_c, 0, nTriggers_c));
980 name =
"trigger_gained_frac";
981 m_histo.emplace(
name,
new TH1F(
name.c_str(),
";;#frac{gained}{accepted}", nTriggers_gl, 0, nTriggers_gl));
982 name =
"trigger_lost_frac";
983 m_histo.emplace(
name,
new TH1F(
name.c_str(),
";;#frac{lost}{accepted}", nTriggers_gl, 0, nTriggers_gl));
984 name =
"trigger_changed_frac";
985 m_histo.emplace(
name,
new TH1F(
name.c_str(),
";;#frac{changed}{all - accepted}", nTriggers_c, 0, nTriggers_c));
986 name =
"module_changed";
987 m_histo.emplace(
name,
new TH1F(
name.c_str(),
";;Events changed", nModules_c, 0, nModules_c));
988 name =
"module_gained";
989 m_histo.emplace(
name,
new TH1F(
name.c_str(),
";;Events gained", nModules_gl, 0, nModules_gl));
990 name =
"module_lost";
991 m_histo.emplace(
name,
new TH1F(
name.c_str(),
";;Events lost", nModules_gl, 0, nModules_gl));
994 size_t bin(0), bin_c(0), bin_gl(0);
995 for (
const auto& idSummary : m_triggerSummary) {
1000 m_histo.at(
"trigger_accepted")->SetBinContent(
bin,
summary.accepted_o);
1002 m_histo.at(
"trigger_accepted")->GetXaxis()->SetBinLabel(
bin,
summary.name.c_str());
1007 m_histo.at(
"trigger_gained")->SetBinContent(bin_gl,
summary.gained().v);
1008 m_histo.at(
"trigger_lost")->SetBinContent(bin_gl, -
summary.lost().v);
1009 m_histo.at(
"trigger_gained_frac")->SetBinContent(bin_gl,
summary.gained(1).v);
1010 m_histo.at(
"trigger_lost_frac")->SetBinContent(bin_gl, -
summary.lost(1).v);
1012 m_histo.at(
"trigger_gained_frac")->SetBinError(bin_gl,
summary.gained(1).e);
1013 m_histo.at(
"trigger_lost_frac")->SetBinError(bin_gl, -
summary.lost(1).e);
1015 m_histo.at(
"trigger_gained")->GetXaxis()->SetBinLabel(bin_gl,
summary.name.c_str());
1016 m_histo.at(
"trigger_lost")->GetXaxis()->SetBinLabel(bin_gl,
summary.name.c_str());
1017 m_histo.at(
"trigger_gained_frac")->GetXaxis()->SetBinLabel(bin_gl,
summary.name.c_str());
1018 m_histo.at(
"trigger_lost_frac")->GetXaxis()->SetBinLabel(bin_gl,
summary.name.c_str());
1023 m_histo.at(
"trigger_changed")->SetBinContent(bin_c,
summary.changed().v);
1024 m_histo.at(
"trigger_changed_frac")->SetBinContent(bin_c,
summary.changed(1).v);
1026 m_histo.at(
"trigger_changed_frac")->SetBinError(bin_c,
summary.changed(1).e);
1028 m_histo.at(
"trigger_changed")->GetXaxis()->SetBinLabel(bin_c,
summary.name.c_str());
1029 m_histo.at(
"trigger_changed_frac")->GetXaxis()->SetBinLabel(bin_c,
summary.name.c_str());
1037 for (
const auto& idSummary : m_moduleSummary) {
1043 m_histo.at(
"module_gained")->SetBinContent(bin_gl,
summary.gained().v);
1044 m_histo.at(
"module_lost")->SetBinContent(bin_gl, -
summary.lost().v);
1046 m_histo.at(
"module_gained")->GetXaxis()->SetBinLabel(bin_gl,
summary.name.c_str());
1047 m_histo.at(
"module_lost")->GetXaxis()->SetBinLabel(bin_gl,
summary.name.c_str());
1052 m_histo.at(
"module_changed")->SetBinContent(bin_c,
summary.changed().v);
1054 m_histo.at(
"module_changed")->GetXaxis()->SetBinLabel(bin_c,
summary.name.c_str());
1059 for (
const auto& nameHisto : m_histo) {
1061 TH1*
histo = nameHisto.second;
1062 if (
name.find(
"gained") != std::string::npos ||
name.find(
"changed") != std::string::npos) {
1063 if (
name.find(
"frac") != std::string::npos)
1064 histo->GetYaxis()->SetRangeUser(0.0, 1.0);
1066 if (
name.find(
"lost") != std::string::npos) {
1067 if (
name.find(
"frac") != std::string::npos)
1068 histo->GetYaxis()->SetRangeUser(-1.0, 0.0);
1076 char savePath[1000];
1077 sprintf(savePath,
"DQMData/Run %d/HLT/Run summary/EventByEvent/", this->run);
1079 gDirectory->cd(savePath);
1080 gDirectory->Write();
1081 for (
const auto& nameHisto : m_histo)
1082 nameHisto.second->Write(nameHisto.first.c_str());
1093 "Total,Accepted OLD,Accepted NEW,Gained,Lost,|G|/A_N + "
1094 "|L|/AO,sigma(AN)+sigma(AO),Changed,C/(T-AO),sigma(T-AO),trigger\n");
1095 for (
const auto& idSummary : m_triggerSummary) {
1098 "%d,%d,%d,%+.f,%+.f,%.2f%%,%.2f%%,~%.f,~%.2f%%,%.2f%%,%s\n",
1104 (
S.gained(1).v +
S.lost(1).v) * 100.0,
1105 (
S.gained(1).e +
S.lost(1).e) * 100.0,
1107 S.changed(1).v * 100.0,
1108 S.changed(1).e * 100.0,
1121 fprintf(
out_file,
"Total,Gained,Lost,Changed,module\n");
1122 for (
const auto& idSummary : m_moduleSummary) {
1125 "%d,+%.f,-%.f,~%.f,%s\n",
1146 std::vector<std::string> filesCreated;
1148 if (!
json.m_run_events.empty()) {
1149 for (
const auto& runEvents :
json.m_run_events) {
1150 prepareSummaries(runEvents.first, runEvents.second);
1152 filesCreated.push_back(writeHistograms());
1155 filesCreated.push_back(writeCSV_trigger());
1156 filesCreated.push_back(writeCSV_module());
1161 filesCreated.push_back(writeHistograms());
1164 filesCreated.push_back(writeCSV_trigger());
1165 filesCreated.push_back(writeCSV_module());
1169 if (!filesCreated.empty()) {
1170 std::cout <<
"Created the following summary files:" << std::endl;
1178 std::unique_ptr<TFile>
f(TFile::Open(
file.c_str()));
1179 return (
f and not
f->IsZombie());
1187 std::cerr <<
"hltDiff: error: file " <<
file <<
" does not exist, or is not a regular file." << std::endl;
1215 ignore_prescales(
true),
1226 std::shared_ptr<fwlite::ChainEvent> old_events;
1227 std::shared_ptr<fwlite::ChainEvent> new_events;
1230 old_events = std::make_shared<fwlite::ChainEvent>(old_files);
1234 if (new_files.size() == 1 and new_files[0] ==
"-")
1235 new_events = old_events;
1237 new_events = std::make_shared<fwlite::ChainEvent>(new_files);
1244 json.configuration.prescales = ignore_prescales;
1246 json.configuration.o.process = old_process;
1247 json.configuration.o.files = old_files;
1248 json.configuration.o.extractFileBase();
1250 json.configuration.n.process = new_process;
1251 json.configuration.n.files = new_files;
1252 json.configuration.n.extractFileBase();
1255 std::unique_ptr<HLTConfigDataEx> old_config_data;
1256 std::unique_ptr<HLTConfigDataEx> new_config_data;
1257 std::unique_ptr<HLTCommonConfig> common_config;
1263 unsigned int affected = 0;
1264 bool new_run =
true;
1265 std::vector<TriggerDiff> differences;
1269 const unsigned int counter_denominator =
std::max(1,
int(
nEvents / 10));
1270 for (old_events->toBegin(); not old_events->atEnd(); ++(*old_events)) {
1272 if (
counter % (counter_denominator) == 0) {
1274 << 10 *
counter / (counter_denominator) <<
"%)" << std::endl;
1279 if (new_events != old_events and not new_events->to(
id)) {
1281 std::cerr <<
"run " <<
id.run() <<
", lumi " <<
id.luminosityBlock() <<
", event " <<
id.event()
1282 <<
": not found in the 'new' files, skipping." << std::endl;
1292 old_results = old_results_h.
product();
1295 std::cerr <<
"run " <<
id.run() <<
", lumi " <<
id.luminosityBlock() <<
", event " <<
id.event()
1296 <<
": 'old' TriggerResults not found, skipping." << std::endl;
1302 old_summary_h.
getByLabel<
fwlite::Event>(*old_events->event(),
"hltTriggerSummaryAOD",
"", old_process.c_str());
1304 old_summary = old_summary_h.
product();
1310 new_results = new_results_h.
product();
1313 std::cerr <<
"run " <<
id.run() <<
", lumi " <<
id.luminosityBlock() <<
", event " <<
id.event()
1314 <<
": 'new' TriggerResults not found, skipping." << std::endl;
1320 new_summary_h.
getByLabel<
fwlite::Event>(*new_events->event(),
"hltTriggerSummaryAOD",
"", new_process.c_str());
1322 new_summary = new_summary_h.
product();
1327 old_events->fillParameterSetRegistry();
1328 new_events->fillParameterSetRegistry();
1332 if (new_config_data->triggerNames() == old_config_data->triggerNames()) {
1333 old_config = old_config_data.get();
1334 new_config = new_config_data.get();
1336 common_config = std::make_unique<HLTCommonConfig>(*old_config_data, *new_config_data);
1339 std::cout <<
"Warning: old and new TriggerResults come from different HLT menus. Only the common "
1340 << old_config->
size() <<
" triggers are compared.\n"
1344 differences.clear();
1345 differences.resize(old_config->
size());
1348 std::vector<std::string> states_str;
1351 json.vars.state = states_str;
1352 for (
size_t triggerId = 0; triggerId < old_config->
size(); ++triggerId) {
1354 json.vars.trigger_passed_count.push_back(std::pair<int, int>(0, 0));
1357 for (
auto const& it : old_config_data->triggerNames()) {
1360 json.configuration.o.skipped_triggers.push_back(it);
1363 for (
auto const& it : new_config_data->triggerNames()) {
1366 json.configuration.n.skipped_triggers.push_back(it);
1371 bool needs_header =
true;
1372 bool event_affected =
false;
1373 for (
unsigned int p = 0;
p < old_config->
size(); ++
p) {
1380 if (old_state ==
Pass) {
1381 ++differences.at(
p).count;
1383 if (old_state ==
Pass)
1384 ++
json.vars.trigger_passed_count.at(
p).first;
1385 if (new_state ==
Pass)
1386 ++
json.vars.trigger_passed_count.at(
p).second;
1388 bool trigger_affected =
false;
1390 if (old_state ==
Pass and new_state !=
Pass) {
1391 ++differences.at(
p).lost;
1392 trigger_affected =
true;
1393 }
else if (old_state !=
Pass and new_state ==
Pass) {
1394 ++differences.at(
p).gained;
1395 trigger_affected =
true;
1396 }
else if (old_results->
index(old_index) != new_results->
index(new_index)) {
1397 ++differences.at(
p).internal;
1398 trigger_affected =
true;
1402 if (not trigger_affected)
1405 event_affected =
true;
1406 const unsigned int old_moduleIndex = old_results->
index(old_index);
1407 const unsigned int new_moduleIndex = new_results->
index(new_index);
1411 state.
o =
json.eventState(old_state,
1415 state.
n =
json.eventState(new_state,
1422 needs_header =
false;
1423 std::cout <<
"run " <<
id.run() <<
", lumi " <<
id.luminosityBlock() <<
", event " <<
id.event() <<
": "
1429 <<
" old state is ";
1432 <<
" new state is ";
1436 if (
verbose > 1 and old_summary and new_summary) {
1438 unsigned int module =
std::min(old_moduleIndex, new_moduleIndex);
1440 std::cout <<
" old trigger candidates:\n";
1444 std::cout <<
" new trigger candidates:\n";
1456 if (event_affected and
verbose > 2 and old_summary and new_summary) {
1457 std::map<std::string, std::pair<std::string, std::string>>
collections;
1460 for (
auto const& new_collection : new_summary->collectionTags())
1465 std::cout <<
" old trigger candidates:\n";
1467 std::cout <<
" new trigger candidates:\n";
1481 std::cout <<
"There are no common events between the old and new files";
1486 std::cout <<
"Found " <<
counter <<
" matching events, out of which " << affected
1487 <<
" have different HLT results";
1494 bool summaryHeaderPrinted =
false;
1495 for (
size_t p = 0;
p < old_config->
size(); ++
p) {
1496 if (differences.at(
p).total() < 1)
1498 if (!summaryHeaderPrinted)
1499 std::cout << std::setw(12) <<
"Events" << std::setw(12) <<
"Accepted" << std::setw(12) <<
"Gained"
1500 << std::setw(12) <<
"Lost" << std::setw(12) <<
"Other"
1502 <<
"Trigger" << std::endl;
1504 summaryHeaderPrinted =
true;
1516 usage: hltDiff -o|--old-files FILE1.ROOT [FILE2.ROOT ...] [-O|--old-process LABEL[:INSTANCE[:PROCESS]]]\n\
1517 -n|--new-files FILE1.ROOT [FILE2.ROOT ...] [-N|--new-process LABEL[:INSTANCE[:PROCESS]]]\n\
1518 [-m|--max-events MAXEVENTS] [-p|--prescales] [-c|--csv-output] [-j|--json-output]\n\
1519 [-r|--root-output] [-f|--file-check] [-d|--debug] [-q|--quiet] [-v|--verbose]\n\
1520 [-h|--help] [-F|--output-file] FILE_NAME\n\
1522 -o|--old-files FILE1.ROOT [FILE2.ROOT ...]\n\
1523 input file(s) with the old (reference) trigger results\n\
1525 -O|--old-process PROCESS\n\
1526 process name of the collection with the old (reference) trigger results\n\
1527 default: take the 'TriggerResults' from the last process\n\
1529 -n|--new-files FILE1.ROOT [FILE2.ROOT ...]\n\
1530 input file(s) with the new trigger results to be compared with the reference\n\
1531 to read these from a different collection in the same files as\n\
1532 the reference, use '-n -' and specify the collection with -N (see below)\n\
1534 -N|--new-process PROCESS\n\
1535 process name of the collection with the new (reference) trigger results\n\
1536 default: take the 'TriggerResults' from the last process\n\
1538 -m|--max-events MAXEVENTS\n\
1539 compare only the first MAXEVENTS events\n\
1540 default: compare all the events in the original (reference) files\n\
1543 do not ignore differences caused by HLTPrescaler modules\n\
1546 produce comparison results in a CSV format\n\
1549 produce comparison results in a JSON format\n\
1552 produce comparison results as histograms in a ROOT file\n\
1554 -F|--output-file FILE_NAME\n\
1555 combine all RUNs to files with the specified custom name: FILE_NAME.json, FILE_NAME.root\n\
1556 default: a separate output file will be produced for each RUN with names suitable for the DQM GUI\n\
1559 check existence of every old and new file before running the comparison\n\
1560 safer if files are run for the first time, but can cause a substantial delay\n\
1563 display messages about missing events and collectiions\n\
1566 don't display summary printout with the list of affected trigger paths\n\
1568 -v|--verbose LEVEL\n\
1569 set verbosity level:\n\
1570 1: event-by-event comparison results\n\
1571 2: + print the trigger candidates of the affected filters\n\
1572 3: + print all the trigger candidates for the affected events\n\
1576 print this help message, and exit"
1583 const char optstring[] =
"dfo:O:n:N:m:pcjrF:v::hq";
1584 const option longopts[] = {
1585 option{
"debug", no_argument,
nullptr,
'd'},
1586 option{
"file-check", no_argument,
nullptr,
'f'},
1587 option{
"old-files", required_argument,
nullptr,
'o'},
1588 option{
"old-process", required_argument,
nullptr,
'O'},
1589 option{
"new-files", required_argument,
nullptr,
'n'},
1590 option{
"new-process", required_argument,
nullptr,
'N'},
1591 option{
"max-events", required_argument,
nullptr,
'm'},
1592 option{
"prescales", no_argument,
nullptr,
'p'},
1593 option{
"csv-output", optional_argument,
nullptr,
'c'},
1594 option{
"json-output", optional_argument,
nullptr,
'j'},
1595 option{
"root-output", optional_argument,
nullptr,
'r'},
1596 option{
"output-file", optional_argument,
nullptr,
'F'},
1597 option{
"verbose", optional_argument,
nullptr,
'v'},
1598 option{
"help", no_argument,
nullptr,
'h'},
1599 option{
"quiet", no_argument,
nullptr,
'q'},
1607 while ((
c = getopt_long(
argc,
argv, optstring, longopts,
nullptr)) != -1) {
1614 hlt->file_check =
true;
1618 hlt->old_files.emplace_back(optarg);
1619 while (optind <
argc) {
1620 if (
argv[optind][0] ==
'-')
1622 hlt->old_files.emplace_back(
argv[optind]);
1628 hlt->old_process = optarg;
1632 hlt->new_files.emplace_back(optarg);
1633 while (optind <
argc) {
1634 if (
argv[optind][0] ==
'-')
1636 hlt->new_files.emplace_back(
argv[optind]);
1642 hlt->new_process = optarg;
1646 hlt->max_events = atoi(optarg);
1650 hlt->ignore_prescales =
false;
1654 hlt->csv_out =
true;
1658 hlt->json_out =
true;
1662 hlt->root_out =
true;
1666 hlt->output_file = optarg;
1673 }
else if (!optarg &&
nullptr !=
argv[optind] &&
'-' !=
argv[optind][0]) {
1675 const char* tmp_optarg =
argv[optind++];
1696 if (
hlt->old_files.empty()) {
1700 if (
hlt->new_files.empty()) {