52 dbgPrint(
const debugLevel_t setLvl = none) : m_currLvl(setLvl) {};
53 inline void operator()(
const debugLevel_t level,
const std::string&
msg)
const {
54 if (level <= m_currLvl)
55 std::cout <<
msg << std::endl;
57 void setLvl(
const debugLevel_t lvl) { m_currLvl = lvl; }
58 debugLevel_t getLvl()
const {
return m_currLvl; }
61 debugLevel_t m_currLvl;
64 static dbgPrint s_dbg;
65 static bool s_checkEquality=
false;
67 std::optional<std::regex> checkRegEx(
const std::string&
re) {
74 std::string test(
"Test String");
75 std::regex_match(test, reNew);
76 }
catch (std::exception& e) {
77 std::cout <<
"ERROR: Invalid RegEx string \"" <<
re <<
"\"." << std::endl;
78 std::cout <<
"See https://en.cppreference.com/w/cpp/regex.html for allowed regular expression syntax" << std::endl;
88 explicit histCollection(TFile* out,
bool skipExisting =
false) : m_out{out}, m_skipExisting(skipExisting) {};
93 void addDirectory(TDirectory* dir,
const std::string& dirName,
const std::string& filename = emptyStr);
94 size_t size() {
return m_data.size(); };
98 void addDirExclusion(
const std::optional<std::regex>& dirEx);
99 void addHistExclusion(
const std::optional<std::regex>& histEx);
101 unsigned size()
const;
104 fileLBMap_t getFileLBMapAndClear() {
106 return std::move(m_fileLBMap);
114 histPerDir_t(
const std::string& nameIn, std::unique_ptr<TObject>&& objIn, TTree* md);
115 histPerDir_t(dqutils::histCollection::histPerDir_t&& other)
116 : name(std::move(other.name)), obj(std::move(other.obj)), metadata(std::move(other.metadata)), mergeMethod(other.mergeMethod) {}
119 std::unique_ptr<TObject> obj;
120 std::array<std::string, 3> metadata{
"unset",
"",
"<default>"};
121 std::clock_t cpuSum = 0;
122 void (*mergeMethod)(TObject*
a,
const TObject* b) =
nullptr;
123 void merge(TObject* other);
126 bool fillMD(TTree* mdTree);
130 std::unordered_map<std::string, histPerDir_t> histos;
131 void writeMD(TDirectory* outDir)
const;
137 std::unordered_map<std::string, histDir_t> m_data;
138 std::optional<std::regex> m_dirExclusion;
139 std::optional<std::regex> m_histExclusion;
140 fileLBMap_t m_fileLBMap;
143 void histCollection::clear() {
148 void histCollection::printTiming() {
149 std::vector<std::pair<std::string, clock_t>> cpuPerHistVec;
150 for (
auto& [
dirname, histDir] : m_data) {
151 for (
auto& [histname, histo] : histDir.histos) {
152 cpuPerHistVec.emplace_back(
dirname +
"/" + histname, histo.cpuSum);
155 auto ordering = [](std::pair<std::string, clock_t>
a, std::pair<std::string, clock_t> b) {
return a.second < b.second; };
156 std::sort(cpuPerHistVec.begin(), cpuPerHistVec.end(), ordering);
157 for (
const auto& [name, time] : cpuPerHistVec) {
158 const double tSec = double(time) / CLOCKS_PER_SEC;
159 std::cout << std::format(
"{:<30} : {:10.3f}", name, tSec) << std::endl;
164 bool histCollection::histPerDir_t::fillMD(TTree * md) {
165 TTreeReader reader(md);
166 TTreeReaderArray<char> i_name(reader,
"Name");
167 TTreeReaderArray<char> i_interval(reader,
"Interval");
168 TTreeReaderArray<char> i_chain(reader,
"TriggerChain");
169 TTreeReaderArray<char> i_merge(reader,
"MergeMethod");
172 while (reader.Next()) {
173 const std::string nameStr(
static_cast<char*
>(i_name.GetAddress()));
174 if (name == nameStr) {
175 metadata = {
static_cast<char*
>(i_interval.GetAddress()),
static_cast<char*
>(i_chain.GetAddress()),
static_cast<char*
>(i_merge.GetAddress())};
183 void histCollection::histPerDir_t::merge(TObject * other) {
185 const std::clock_t cpuStart = std::clock();
186 this->mergeMethod(obj.get(), other);
187 cpuSum += std::clock() - cpuStart;
192 void histCollection::histDir_t::writeMD(TDirectory * out)
const {
195 std::map<std::string, std::array<std::string, 3>> metadatamap;
196 std::unique_ptr<TTree> oldMD((TTree*)out->Get(
"metadata"));
198 TTreeReader reader(oldMD.get());
199 TTreeReaderArray<char> i_name(reader,
"Name");
200 TTreeReaderArray<char> i_interval(reader,
"Interval");
201 TTreeReaderArray<char> i_chain(reader,
"TriggerChain");
202 TTreeReaderArray<char> i_merge(reader,
"MergeMethod");
204 while (reader.Next()) {
205 const std::string name(
static_cast<char*
>(i_name.GetAddress()));
206 metadatamap[name] = {
static_cast<char*
>(i_interval.GetAddress()),
static_cast<char*
>(i_chain.GetAddress()),
static_cast<char*
>(i_merge.GetAddress())};
210 for (
const auto& [key,
h] : histos) {
211 if (
h.metadata[0]!=
"unset")
212 metadatamap[key] =
h.metadata;
215 if (metadatamap.empty())
return;
216 std::string interval, chain,
merge;
218 std::unique_ptr<TTree> mdTree = std::make_unique<TTree>(
"metadata",
"Monitoring Metadata");
219 mdTree->SetDirectory(out);
221 mdTree->Branch(
"Name", (
void*)
nullptr,
"Name/C");
222 mdTree->Branch(
"Interval", interval.data(),
"Interval/C");
223 mdTree->Branch(
"TriggerChain", chain.data(),
"TriggerChain/C");
224 mdTree->Branch(
"MergeMethod",
merge.data(),
"MergeMethod/C");
226 mdTree->SetBranchAddress(
"Name", histname);
228 for (
auto& [key,
h] : metadatamap) {
229 strncpy(histname, key.c_str(), 1023);
235 mdTree->Write(0, TObject::kOverwrite);
238 histCollection::~histCollection() {}
240 void histCollection::addDirExclusion(
const std::optional<std::regex>& dir) {
241 m_dirExclusion = dir;
245 void histCollection::addHistExclusion(
const std::optional<std::regex>& dir) {
246 m_histExclusion = dir;
252 for (
const auto& it : m_data) {
253 s += it.second.histos.size();
259 for (
const auto& it : m_data) {
260 const histDir_t& hd = it.second;
261 std::cout <<
"Dir: " << it.first <<
" has " << hd.histos.size() <<
" histos" << std::endl;
262 for (
const auto& it1 : hd.histos)
263 std::cout <<
"\t" << it1.second.name << std::endl;
268 template <
class HIST>
270 static_cast<HIST*
>(
a)->Add(
static_cast<const HIST*
>(b));
275 TH1* a1 = (
dynamic_cast<TH1*
>(
a));
276 const TH1* b1 =
dynamic_cast<const TH1*
>(b);
278 std::cout <<
"ERROR in weightedAverageTH1: Object not of type TH1" << std::endl;
280 if (b1->GetEntries()==0)
return;
287 TH1* a1 = (
dynamic_cast<TH1*
>(
a));
288 const TH1* b1 = (
dynamic_cast<const TH1*
>(b));
290 std::cout <<
"ERROR in weightedEff: Object not of type TH1" << std::endl;
292 if (b1->GetEntries()==0)
return;
299 TH1* a1 = (
dynamic_cast<TH1*
>(
a));
300 const TH1* b1 =
dynamic_cast<const TH1*
>(b);
302 std::cout <<
"ERROR in mergeRMS: Object not of type TH1" << std::endl;
304 if (b1->GetEntries()==0)
return;
311 TH1* a1 = (
dynamic_cast<TH1*
>(
a));
312 const TH1* b1 =
dynamic_cast<const TH1*
>(b);
314 std::cout <<
"ERROR in RMSpercentDeviation: Object not of type TH1" << std::endl;
316 if (b1->GetEntries()==0)
return;
323 TH1* a1 = (
dynamic_cast<TH1*
>(
a));
324 const TH1* b1 =
dynamic_cast<const TH1*
>(b);
326 std::cout <<
"ERROR in getBinEffPerCent: Object not of type TH1" << std::endl;
328 if (b1->GetEntries()==0)
return;
335 TH1* a1 = (
dynamic_cast<TH1*
>(
a));
336 const TH1* b1 =
dynamic_cast<const TH1*
>(b);
338 std::cout <<
"ERROR in lowerLB: Object not of type TH1" << std::endl;
344 template <
class HIST>
345 void identical(TObject *
a,
const TObject* b) {
346 if (!s_checkEquality)
348 HIST* a1 = (
dynamic_cast<HIST*
>(
a));
349 const HIST* b1 =
dynamic_cast<const HIST*
>(b);
351 std::cout <<
"ERROR in identical: Object not of correct type" << std::endl;
358 void merge_rebinned(TObject *
a,
const TObject* b) {
359 TH1* a1 = (
dynamic_cast<TH1*
>(
a));
360 const TH1* b1 =
dynamic_cast<const TH1*
>(b);
362 std::cout <<
"ERROR, in merge_rebinned: Object not of type TH1";
365 TH1* b2 =
const_cast<TH1*
>(b1);
370 void merge_eventSample(TObject *
a,
const TObject* b) {
371 TH2* a1 = (
dynamic_cast<TH2*
>(
a));
372 const TH2* b1 =
dynamic_cast<const TH2*
>(b);
374 std::cout <<
"ERROR in merge_eventSample: Object not of type TH2" << std::endl;
380 void merge_TEfficency(TObject *
a,
const TObject* b) {
381 TEfficiency* a1 =
dynamic_cast<TEfficiency*
>(
a);
382 const TEfficiency* b1 =
dynamic_cast<const TEfficiency*
>(b);
383 TEfficiency* b2 =
const_cast<TEfficiency*
>(b1);
385 std::cout <<
"ERROR in merge_TEfficiency: Object not of type TEfficiency" << std::endl;
394 void merge_TTree(TObject *
a,
const TObject* b) {
395 TTree* a1 =
dynamic_cast<TTree*
>(
a);
396 const TTree* b1 =
dynamic_cast<const TTree*
>(b);
398 std::cout <<
"ERROR in merge_TTree: Object not of type TTree" << std::endl;
401 TTree* b2 =
const_cast<TTree*
>(b1);
409 : name(nameIn), obj(std::move(objIn)), mergeMethod(
nullptr) {
412 std::cout <<
"ERROR while adding " << nameIn <<
": Histogram pointer is NULL" << std::endl;
420 s_dbg(
VERBOSE,
"No matadata found for " + name +
", use defaults");
422 const std::string& howToMerge = metadata[2];
423 s_dbg(
VERBOSE,
"Name: " + name +
" mergeMethod=" + howToMerge);
425 TH1* th1 =
dynamic_cast<TH1*
>(obj.get());
426 TH2* th2 =
dynamic_cast<TH2*
>(obj.get());
427 TEfficiency* teff =
dynamic_cast<TEfficiency*
>(obj.get());
429 th1->SetDirectory(
nullptr);
430 if (howToMerge ==
"<default>") {
437 else if (howToMerge ==
"weightedAverage" || howToMerge==
"weightedAverage2D")
438 mergeMethod = &weightedAverage;
439 else if (howToMerge ==
"weightedEff")
440 mergeMethod = &weightedEff;
441 else if (howToMerge ==
"mergeRMS")
442 mergeMethod = &mergeRMS;
443 else if (howToMerge ==
"RMSpercentDeviation")
444 mergeMethod = &RMSpercentDeviation;
445 else if (howToMerge ==
"perBinEffPerCent")
446 mergeMethod = &perBinEffPerCent;
447 else if (howToMerge ==
"lowerLB")
448 mergeMethod = &lowerLB;
449 else if (howToMerge ==
"identical")
451 mergeMethod = &identical<TH2>;
453 mergeMethod = &identical<TH1>;
455 else if ((howToMerge ==
"mergeRebinned") || (howToMerge ==
"merge"))
456 mergeMethod = &merge_rebinned;
458 std::cout <<
"ERROR: Unknown merging method (" << howToMerge <<
") for object of type TH1 named " << nameIn << std::endl;
463 teff->SetDirectory(
nullptr);
464 if (howToMerge ==
"<default>")
465 mergeMethod = &merge_TEfficency;
467 std::cout <<
"ERROR: Unknown merging method (" << howToMerge <<
") for object of type TEfficiency named " << nameIn << std::endl;
469 else if (
nullptr !=
dynamic_cast<TTree*
>(obj.get())) {
470 mergeMethod = &merge_TTree;
472 std::cout <<
"ERROR Object " << name <<
" has unkown type" << std::endl;
479 s_dbg(
VERBOSE,
"Working on directory " + dirName);
480 if (m_dirExclusion && !std::regex_search(dirName, *m_dirExclusion)) {
481 s_dbg(
DEBUG,
"Path " + dirName +
" is excluded");
485 for (TObject* oKey : *dir->GetListOfKeys()) {
486 TKey* key =
static_cast<TKey*
>(oKey);
487 const std::string name = key->GetName();
488 const std::string classname = key->GetClassName();
489 if ((classname ==
"TTree") && (name ==
"metadata")) {
493 s_dbg(
VERBOSE,
"Found name " + name +
", classname=" + classname);
495 const std::string newName = dirName.empty() ? name : dirName +
"/" + name;
496 auto itDir = m_data.find(dirName);
498 if (classname.starts_with(
"TH") || classname.starts_with(
"TProfile") || classname.starts_with(
"TEfficiency") || classname ==
"TTree") {
499 if (m_histExclusion && !std::regex_search(name, *m_histExclusion)) {
500 s_dbg(
DEBUG,
"Histogram with name " + name +
" is excluded");
505 if (m_skipExisting) {
507 std::unique_ptr<TObject> existingObj(m_out->Get(newName.c_str()));
512 std::unique_ptr<TTree> md;
513 if (itDir == m_data.end()) {
515 itDir = m_data.emplace(dirName, histDir_t()).first;
516 s_dbg(
VERBOSE,
"Registering new directory " + dirName);
520 auto itH = itDir->second.histos.find(name);
521 if (itH == itDir->second.histos.end()) {
525 md.reset((TTree*)dir->Get(
"metadata"));
528 std::unique_ptr<TObject> obj{key->ReadObj()};
529 TTree* treeObj =
dynamic_cast<TTree*
>(obj.get());
531 TDirectory* outDir = m_out->GetDirectory(dirName.c_str());
533 outDir = m_out->mkdir(dirName.c_str());
535 TDirectory* currentDir = gDirectory;
537 TTree* cloneTree = treeObj->CloneTree();
539 obj.reset(cloneTree);
542 histPerDir_t histo(name, std::move(obj), md.get());
543 itH = itDir->second.histos.emplace(name, std::move(histo)).first;
544 s_dbg(
VERBOSE,
"Cloning histogram " + name +
" in dir " + dirName);
547 std::unique_ptr<TObject> other(key->ReadObj());
549 std::cout <<
"ERROR, got NULL key";
551 itH->second.merge(other.get());
552 s_dbg(
VERBOSE,
"Merging histogram " + name +
" in dir " + dirName);
555 }
else if (classname.starts_with(
"TDirectory")) {
556 std::unique_ptr<TObject> obj(key->ReadObj());
557 TDirectory* subdir =
dynamic_cast<TDirectory*
>(obj.get());
559 if (filename.empty()) {
560 this->addDirectory(subdir, newName, filename);
562 if (!name.starts_with(
"lb_") && !name.starts_with(
"lowStat_LB")) {
563 this->addDirectory(subdir, newName, filename);
565 m_fileLBMap[newName].insert(filename);
570 std::cout <<
"Ignored objects '" << name <<
"' of type " << classname << std::endl;
577 unsigned nWritten = 0;
578 unsigned nIgnored = 0;
580 for (
auto& it : m_data) {
581 const std::string fulldir = it.first;
582 TDirectory* histDir = m_out->GetDirectory(fulldir.c_str());
583 if (histDir ==
nullptr) {
584 histDir = m_out->mkdir(fulldir.c_str());
585 if (histDir ==
nullptr) {
586 std::cout <<
"ERROR, failed to create directory " << fulldir << std::endl;
589 s_dbg(
VERBOSE,
"Created directory " + fulldir +
" in file " + m_out->GetName());
592 m_out->cd(fulldir.c_str());
594 for (
auto& [name, histo] : it.second.histos) {
599 std::cout <<
"NOT writing " << name <<
". Invalid." << std::endl;
603 it.second.writeMD(histDir);
605 std::cout <<
"Wrote " << nWritten <<
" histograms to " << nDirs <<
" directories in output file " << m_out->GetName() << std::endl;
607 std::cout <<
" Omitting " << nIgnored <<
" histograms." << std::endl;
615 makeBranch(
"Name",
"Name/C");
616 makeBranch(
"Interval",
"Interval/C");
617 makeBranch(
"TriggerChain",
"TriggerChain/C");
618 makeBranch(
"MergeMethod",
"MergeMethod/C");
623 m_metadata->Branch(branchName, (
void*)
nullptr, branchstr);
628 const std::string& theMerge) {
629 std::string name = theName;
630 std::string interval = theInterval;
631 std::string chain = theChain;
632 std::string
merge = theMerge;
633 m_metadata->SetBranchAddress(
"Name", name.data());
634 m_metadata->SetBranchAddress(
"Interval", interval.data());
635 m_metadata->SetBranchAddress(
"TriggerChain", chain.data());
636 m_metadata->SetBranchAddress(
"MergeMethod",
merge.data());
648 m_file = TFile::Open(fileName.c_str());
682 DirMap_t::value_type dirmapVal(dirName, dir);
683 dirmap.insert(std::move(dirmapVal));
686 TIter next(dir->GetListOfKeys());
688 while ((key =
dynamic_cast<TKey*
>(next())) != 0) {
690 TObject* obj = key->ReadObj();
691 TDirectory* subdir =
dynamic_cast<TDirectory*
>(obj);
693 std::string subdirName(subdir->GetName());
694 std::string fName(
"");
711 TDirectory* subdir(0);
712 DirMap_t::const_iterator diter;
713 std::string::size_type i = path.find_first_of(
'/');
714 std::string fName(
"");
720 if (i != std::string::npos) {
721 std::string dName(path, 0, i);
722 std::string pName(path, i + 1, std::string::npos);
725 diter = dirmap.find(fName);
726 if (diter != dirmap.end()) {
727 subdir = diter->second;
729 subdir = dir->mkdir(dName.c_str());
730 DirMap_t::value_type dirmapVal(fName, subdir);
731 dirmap.insert(std::move(dirmapVal));
736 return createDir(dirmap, subdir, fName, pName);
741 diter = dirmap.find(fName);
742 if (diter != dirmap.end()) {
743 return diter->second;
746 subdir = dir->mkdir(path.c_str());
747 DirMap_t::value_type dirmapVal(fName, subdir);
748 dirmap.insert(std::move(dirmapVal));
758 std::string::size_type i = path.find_first_of(
'/');
759 if (i != std::string::npos) {
760 std::string dName(path, 0, i);
761 std::string pName(path, i + 1, std::string::npos);
763 key = dir->FindKey(dName.c_str());
765 TDirectory* subDir =
dynamic_cast<TDirectory*
>(key->ReadObj());
775 return dir->FindKey(path.c_str());
781 TTree* md =
dynamic_cast<TTree*
>(dir->Get(
"metadata"));
785 TTreeReader reader(md);
786 TTreeReaderArray<char> i_name(reader,
"Name");
787 TTreeReaderArray<char> i_interval(reader,
"Interval");
788 TTreeReaderArray<char> i_chain(reader,
"TriggerChain");
789 TTreeReaderArray<char> i_merge(reader,
"MergeMethod");
791 while (reader.Next()) {
792 const std::string nameStr(
static_cast<char*
>(i_name.GetAddress()));
793 if (mdMap.find(nameStr) == mdMap.end()) {
794 MetaData md(nameStr,
static_cast<char*
>(i_interval.GetAddress()),
static_cast<char*
>(i_chain.GetAddress()),
static_cast<char*
>(i_merge.GetAddress()));
795 std::map<std::string, MetaData>::value_type mdVal(nameStr, md);
796 mdMap.insert(std::move(mdVal));
804 std::cout <<
"Writing file: " << outFileName << std::endl;
805 std::cout <<
"Start merging [" <<
files.size() <<
"] histogram files" << std::endl;
807 TH1::AddDirectory(
false);
809 std::cout <<
" ========== Using regular expressions for selective merging ========== " << std::endl;
812 std::cout <<
"CPU time measurement activated " << std::endl;
815 const size_t nFiles =
files.size();
821 std::cout <<
"Got exactly one input file. Will copy input -> output" << std::endl;
823 std::cout <<
"regular expressions for selective merging will have no effect!" << std::endl;
826 std::filesystem::path inPath(
files[0]);
827 std::filesystem::path outPath(outFileName);
828 std::filesystem::copy_file(inPath, outPath, std::filesystem::copy_options::overwrite_existing);
832 std::unique_ptr<TFile> outfile(TFile::Open(outFileName.c_str(),
"RECREATE", outFileName.c_str(),
m_fileCompressionLevel));
833 if (outfile.get() == 0) {
834 std::cout <<
" ERROR, cound not open output file " << outFileName << std::endl;
837 std::cout <<
"Opened/created output file " << outFileName << std::endl;
844 std::unique_ptr<TFile> in1(TFile::Open(
files[0].c_str()));
846 std::cout <<
"ERROR, could not open input file " <<
files[0] << std::endl;
849 std::cout <<
"Working on file 1/" << nFiles <<
": " <<
files[0] << std::endl;
850 std::string runDir, runDirFwd;
851 const std::regex runDirPattern(
"run_[0-9]*");
852 TIter next(in1->GetListOfKeys());
854 while ((key = (TKey*)next())) {
855 const char* name = key->GetName();
856 if (std::regex_match(name, runDirPattern)) {
857 if (runDir.size() > 0) {
858 std::cout <<
"ERROR More than one run_XXX directory found! Ignoring " << name << std::endl;
863 if (runDir.empty()) {
864 std::cout <<
"No run-directory found, start with '/'" << std::endl;
869 std::cout <<
"Found run directory " << runDir << std::endl;
874 TDirectory* dir(
dynamic_cast<TDirectory*
>(in1->GetDirectory(runDir.c_str())));
876 std::cout <<
"ERROR, can't access directory " << runDir;
885 for (
size_t i = 1; i <
files.size(); ++i) {
886 std::cout <<
"Working on file " << 1+i <<
"/" << nFiles <<
": " <<
files[i] << std::endl;
887 std::unique_ptr<TFile> in(TFile::Open(
files[i].c_str()));
889 std::cout <<
"ERROR, could not open input file " <<
files[i] << std::endl;
892 TDirectory* dir(
dynamic_cast<TDirectory*
>(in->GetDirectory(runDir.c_str())));
894 std::cout <<
"ERROR, could not cast to directory" << std::endl;
900 std::cout <<
"Accumulated a total of " << hc.
size() <<
" histograms." << std::endl;
902 std::cout <<
"Start writing output ..." << std::endl;
906 std::cout <<
"CPU time for histogram merging: (regular histograms)" << std::endl;
910 auto newlbmap = hc.getFileLBMapAndClear();
913 for (
auto& [lbname, newfileset] : newlbmap) {
914 auto& fileset = lbmap[lbname];
915 fileset.merge(newfileset);
918 if (!lbmap.empty() && fillLBDirs) {
919 std::cout <<
"Start merging lb_nnn and lowStat_LB directories (" << lbmap.size() <<
" in total)" << std::endl;
927 std::vector<std::pair<std::string, std::vector<std::string>>> lbToFiles;
928 for (
const auto& [
lb,fileSet] : lbmap) {
929 if (fileSet.size() > 0)
930 lbToFiles.emplace_back(
lb,std::vector<std::string>(fileSet.begin(),fileSet.end()));
934 std::sort(lbToFiles.begin(), lbToFiles.end(),
935 [](
const decltype(lbToFiles)::value_type&
a,
const decltype(lbToFiles)::value_type& b) { return a.second[0] < b.second[0]; });
938 std::unique_ptr<TFile> in;
939 for (
const auto& [dir, filenames] : lbToFiles) {
940 std::cout <<
"Merging/copying directory " << dir <<
" from " << filenames.size() <<
" input file(s) (" << ++counter <<
"/" << lbToFiles.size() <<
")"
942 for (
const std::string& fName : filenames) {
943 if (!in || strcmp(in->GetName(), fName.c_str()) != 0) {
944 in.reset(TFile::Open(fName.c_str()));
945 s_dbg(
DEBUG,
"Opening input file " + fName);
947 s_dbg(
DEBUG,
"Input file " + fName +
" already open");
951 std::cout <<
"ERROR, could not open input file " << fName << std::endl;
954 TDirectory* tDir = (
dynamic_cast<TDirectory*
>(in->Get(dir.c_str())));
956 std::cout <<
"ERROR, failed to get directory " << dir <<
" from file " << fName << std::endl;
963 std::cout <<
"CPU time for histogram merging: (lumiblock-histograms)" << std::endl;
974 typedef std::vector<std::string> FileList_t;
976 const unsigned int nFilesAtOnce = 50;
981 std::cout <<
"ERROR Failed ot read list of input files" << std::endl;
987 if (allFiles.size() <= nFilesAtOnce) {
988 return mergeFiles(outFileName, allFiles, fileLBMap,
true);
991 FileList_t procFiles, tmpIntermediateFiles;
993 FileList_t::const_iterator filesEnd = allFiles.end();
994 FileList_t::const_iterator fi = allFiles.begin();
996 unsigned int counter = 0;
997 std::string tmpInputFile(
"");
998 std::string tmpOutputFile(
"");
1001 while (fi != filesEnd) {
1003 procFiles.push_back(*fi);
1006 if (counter % nFilesAtOnce == 0 || fi == filesEnd) {
1007 std::ostringstream nameStream;
1008 nameStream <<
"tmp_merge_" << counter <<
".root";
1009 tmpOutputFile = nameStream.str();
1010 tmpIntermediateFiles.push_back(tmpOutputFile);
1011 int stat=
mergeFiles(tmpOutputFile, procFiles, fileLBMap,
false);
1012 if (stat)
return stat;
1017 int stat=
mergeFiles(outFileName, tmpIntermediateFiles,fileLBMap,
true);
1018 if (stat)
return stat;
1020 for (
const auto& tmpFile : tmpIntermediateFiles) {
1023 std::cerr<<
"MonitoringFile::mergeFiles: tmpFile "<<tmpFile<<
" could not be removed\n";
1031 std::cerr <<
"MonitoringFile::printStatistics(): "
1032 <<
"No input file is open\n";
1040 DirMap_t::const_iterator idirend = indirmap.end();
1041 for (DirMap_t::const_iterator idir = indirmap.begin(); idir != idirend; ++idir) {
1042 std::string idirName = idir->first;
1044 GatherStatistics stat_shift(idirName);
1045 GatherStatistics stat_all(idirName);
1050 std::cout.setf(std::ios_base::left, std::ios_base::adjustfield);
1051 std::cout.width(80);
1052 std::cout << idirName <<
" ";
1054 std::cout.setf(std::ios_base::right, std::ios_base::adjustfield);
1055 std::cout <<
" shift: ";
1057 std::cout << stat_shift.m_nHist1D <<
" ";
1059 std::cout << stat_shift.m_nHist1DBins <<
" ";
1061 std::cout << stat_shift.m_nHist2D <<
" ";
1063 std::cout << stat_shift.m_nHist2DBins <<
" ";
1065 std::cout << stat_shift.m_nGraph <<
" ";
1067 std::cout << stat_shift.m_nGraphPoints <<
" ";
1069 std::cout <<
" all: ";
1070 std::cout << stat_all.m_nHist1D <<
" ";
1072 std::cout << stat_all.m_nHist1DBins <<
" ";
1074 std::cout << stat_all.m_nHist2D <<
" ";
1076 std::cout << stat_all.m_nHist2DBins <<
" ";
1078 std::cout << stat_all.m_nGraph <<
" ";
1080 std::cout << stat_all.m_nGraphPoints <<
"\n";
1082 std::cout << std::flush;
1092 std::cerr <<
"MonitoringFile::copyHistograms(): "
1093 <<
"No input file is open\n";
1101 if (dirName !=
"all") {
1104 std::cerr <<
"MonitoringFile::copyHistograms(): "
1105 <<
"Directory \'" << dirName <<
"\' not found in input file\n";
1109 TDirectory* fromDir =
dynamic_cast<TDirectory*
>(dkey->ReadObj());
1111 DirMap_t::value_type dirmapVal(dirName, fromDir);
1112 indirmap.insert(std::move(dirmapVal));
1114 std::cout <<
"Building list of all TDirectories in file...\n" << std::flush;
1118 DirMap_t::const_iterator idirend = indirmap.end();
1119 for (DirMap_t::const_iterator idir = indirmap.begin(); idir != idirend; ++idir) {
1121 std::string idirName = idir->first;
1122 std::cout <<
"Checking " << idirName <<
"\n" << std::flush;
1129 reducedmap.insert(*idir);
1132 std::unique_ptr<TFile> outfile(TFile::Open(outFileName.c_str(),
"RECREATE", outFileName.c_str(),
m_fileCompressionLevel));
1133 if (outfile.get() == 0) {
1134 std::cerr <<
"MonitoringFile::copyHistograms(): "
1135 <<
"Output file not opened\n";
1139 idirend = reducedmap.end();
1140 for (DirMap_t::const_iterator idir = reducedmap.begin(); idir != idirend; ++idir) {
1142 std::string idirName = idir->first;
1143 std::cout <<
"Processing " << idirName <<
"\n" << std::flush;
1145 TDirectory* toDir =
createDir(outdirmap, outfile.get(), emptyStr, idirName);
1147 std::cerr <<
"MonitoringFile::copyHistograms(): "
1148 <<
"Directory \'" << idirName <<
"\' not created in output file\n";
1152 CopyHistogram copyFcn(toDir, idirName);
1163 const std::string& hcfg_lowStat,
const std::string& hcfg_medStat) {
1166 std::cout <<
"\nUsing han configurations:\n"
1167 <<
" entire run: " << hcfg <<
"\n"
1168 <<
" low stat interval: " << hcfg_lowStat <<
"\n"
1169 <<
" medium stat interval: " << hcfg_medStat <<
"\n\n"
1172 TFile* infile = TFile::Open(input.c_str());
1174 std::cerr <<
"MonitoringFile::getHanResults(): "
1175 <<
"Cannot open input file \"" << input <<
"\"\n";
1179 std::vector<std::string> run_dirs;
1180 std::vector<std::string> lowStat_dirs;
1181 std::vector<std::string> medStat_dirs;
1183 TIter next_run(infile->GetListOfKeys());
1185 while ((key_run =
dynamic_cast<TKey*
>(next_run())) != 0) {
1186 TObject* obj_run = key_run->ReadObj();
1187 TDirectory* tdir_run =
dynamic_cast<TDirectory*
>(obj_run);
1188 if (tdir_run != 0) {
1189 std::string tdir_run_name(tdir_run->GetName());
1190 if (tdir_run_name.find(
"run") != std::string::npos) {
1191 run_dirs.push_back(tdir_run_name);
1192 TIter next_minutes(tdir_run->GetListOfKeys());
1193 TKey* key_minutes(0);
1194 while ((key_minutes =
dynamic_cast<TKey*
>(next_minutes())) != 0) {
1195 TObject* obj_minutes = key_minutes->ReadObj();
1196 TDirectory* tdir_minutes =
dynamic_cast<TDirectory*
>(obj_minutes);
1197 if (tdir_minutes != 0) {
1198 std::string tdir_minutes_name(tdir_minutes->GetName());
1199 if (tdir_minutes_name.find(
"lowStat") != std::string::npos) {
1200 lowStat_dirs.push_back(tdir_run_name +
'/' + tdir_minutes_name);
1201 }
else if (tdir_minutes_name.find(
"medStat") != std::string::npos) {
1202 medStat_dirs.push_back(tdir_run_name +
'/' + tdir_minutes_name);
1216 std::string fileList =
" ";
1217 std::vector<std::string>::const_iterator dirs_end;
1218 std::vector<std::string>::const_iterator dir;
1220 dirs_end = run_dirs.end();
1221 for (dir = run_dirs.begin(); dir != dirs_end; ++dir) {
1222 const std::string& tdir_run_name = *dir;
1223 std::string han_output_run = hanResultsDir +
'/' + tdir_run_name +
"_han.root";
1224 std::cout <<
"Calling han( " << hcfg <<
", " << input <<
", " << tdir_run_name <<
", " << han_output_run <<
" ):\n" << std::flush;
1225 han.Analyze(hcfg, input, han_output_run, tdir_run_name);
1227 fileList += han_output_run +
" " + tdir_run_name +
"\n";
1230 dirs_end = lowStat_dirs.end();
1231 for (dir = lowStat_dirs.begin(); dir != dirs_end; ++dir) {
1232 const std::string& tdir_minutes_path = *dir;
1234 std::string tdir_minutes_underscore = tdir_minutes_path;
1235 std::string::size_type tdir_minutes_i = tdir_minutes_underscore.find(
'/');
1236 tdir_minutes_underscore.replace(tdir_minutes_i, 1,
"_");
1238 std::string han_output_lowStat = hanResultsDir +
'/' + tdir_minutes_underscore +
"_han.root";
1239 std::cout <<
"Running han, writing to " << han_output_lowStat <<
":\n" << std::flush;
1240 han.Analyze(hcfg_lowStat, input, han_output_lowStat, tdir_minutes_path);
1242 std::string subdirname(tdir_minutes_path, tdir_minutes_i + 1, std::string::npos);
1243 std::string
dirname(tdir_minutes_path, 0, tdir_minutes_i);
1244 fileList += han_output_lowStat +
" " + subdirname +
" " +
dirname +
" " + subdirname +
"\n";
1247 dirs_end = medStat_dirs.end();
1248 for (dir = medStat_dirs.begin(); dir != dirs_end; ++dir) {
1249 const std::string& tdir_minutes_path = *dir;
1251 std::string tdir_minutes_underscore = tdir_minutes_path;
1252 std::string::size_type tdir_minutes_i = tdir_minutes_underscore.find(
'/');
1253 tdir_minutes_underscore.replace(tdir_minutes_i, 1,
"_");
1255 std::string han_output_medStat = hanResultsDir +
'/' + tdir_minutes_underscore +
"_han.root";
1256 std::cout <<
"Running han, writing to " << han_output_medStat <<
":\n" << std::flush;
1257 han.Analyze(hcfg_medStat, input, han_output_medStat, tdir_minutes_path);
1259 std::string subdirname(tdir_minutes_path, tdir_minutes_i + 1, std::string::npos);
1260 std::string
dirname(tdir_minutes_path, 0, tdir_minutes_i);
1261 fileList += han_output_medStat +
" " + subdirname +
" " +
dirname +
" " + subdirname +
"\n";
1269 std::cerr <<
"MonitoringFile::printHanConfig(): "
1270 <<
"No input file is open\n";
1278 std::string indent, indent_p, indent_c;
1279 std::string idirName_p;
1280 DirMap_t::const_iterator idirend = indirmap.end();
1281 for (DirMap_t::const_iterator idir = indirmap.begin(); idir != idirend; ++idir) {
1282 std::string idirName = idir->first;
1283 std::string::size_type shortNameIndex = idirName.rfind(
'/');
1284 std::string shortName = idirName.substr(shortNameIndex + 1, std::string::npos);
1286 std::string::size_type fsIndex = idirName.find(
'/');
1287 std::string shortPath;
1288 if (fsIndex != shortNameIndex)
1289 shortPath = idirName.substr(fsIndex + 1, shortNameIndex);
1291 shortPath = idirName.substr(fsIndex + 1, std::string::npos);
1293 std::cout << idirName <<
"\n";
1294 std::cout << shortPath <<
", " << shortName <<
"\n";
1333 std::string space = leadingSpace;
1334 std::string::size_type i = pathName.find_first_of(
'/');
1335 if (i != std::string::npos) {
1336 std::string subPath(pathName, i + 1, std::string::npos);
1344 int length = (name1.size() < name2.size()) ? name1.size() : name2.size();
1354 return (name1.substr(0,
count));
1362 m_metadata =
new TTree(
"metadata",
"Monitoring Metadata");
1363 m_metadata->SetDirectory(0);
1364 m_metadata->Branch(
"Name", (
void*)
nullptr,
"Name/C");
1365 m_metadata->Branch(
"Interval", (
void*)
nullptr,
"Interval/C");
1366 m_metadata->Branch(
"TriggerChain", (
void*)
nullptr,
"TriggerChain/C");
1367 m_metadata->Branch(
"MergeMethod", (
void*)
nullptr,
"MergeMethod/C");
1372 m_metadata->SetDirectory(m_target);
1373 m_metadata->Write();
1379 hist->SetDirectory(m_target);
1399 std::string name(md.name);
1400 std::string interval(md.interval);
1401 std::string chain(md.chain);
1402 std::string
merge(md.merge);
1403 m_metadata->SetBranchAddress(
"Name", name.data());
1404 m_metadata->SetBranchAddress(
"Interval", interval.data());
1405 m_metadata->SetBranchAddress(
"TriggerChain", chain.data());
1406 m_metadata->SetBranchAddress(
"MergeMethod",
merge.data());
1412 hist->SetDirectory(m_target);
1437 : m_dirName(dirName), m_nHist1D(0), m_nHist1DBins(0), m_nGraph(0), m_nGraphPoints(0), m_nHist2D(0), m_nHist2DBins(0) {}
1440 TH2* hist2d =
dynamic_cast<TH2*
>(hist);
1443 m_nHist2DBins += (hist2d->GetNbinsX() * hist2d->GetNbinsY());
1447 m_nHist1DBins += hist->GetNbinsX();
1453 m_nGraphPoints += graph->GetMaxSize();
1460 TH1* h_total = eff->GetCopyPassedHisto();
1461 TH2* h_total2D =
dynamic_cast<TH2*
>(h_total);
1463 if (h_total2D != 0) {
1464 m_nEfficiencyBins += (h_total2D->GetNbinsX() * h_total2D->GetNbinsY());
1467 m_nEfficiencyBins += h_total->GetNbinsX();
1475 m_names.push_back(std::string(hist->GetName()));
1480 m_names.push_back(std::string(graph->GetName()));
1485 m_names.push_back(std::string(eff->GetName()));
1501 TKey* mdKey = dir->FindKey(
"metadata");
1506 TTree* md =
dynamic_cast<TTree*
>(mdKey->ReadObj());
1511 int nEntries = int(md->GetEntries());
1516 }
catch (
const std::exception& e) {
1517 std::cerr <<
"Exception: \"" << e.what() <<
"\" in directory \"" << dir->GetName() <<
"\"\n" << std::flush;
1528 TIter next(dir->GetListOfKeys());
1530 while ((key =
dynamic_cast<TKey*
>(next())) != 0) {
1531 TObject* obj = key->ReadObj();
1535 if ((
h =
dynamic_cast<TH1*
>(obj))) {
1537 }
else if ((g =
dynamic_cast<TGraph*
>(obj))) {
1539 }
else if ((e =
dynamic_cast<TEfficiency*
>(obj))) {
1548 TKey* mdKey = dir->FindKey(
"metadata");
1553 TTree* md =
dynamic_cast<TTree*
>(mdKey->ReadObj());
1560 TTreeReader reader(md);
1561 TTreeReaderArray<char> i_name(reader,
"Name");
1562 TTreeReaderArray<char> i_interval(reader,
"Interval");
1563 TTreeReaderArray<char> i_chain(reader,
"TriggerChain");
1564 TTreeReaderArray<char> i_merge(reader,
"MergeMethod");
1566 while (reader.Next()) {
1567 const std::string nameStr(
static_cast<char*
>(i_name.GetAddress()));
1569 i_key = dir->FindKey(
static_cast<char*
>(i_name.GetAddress()));
1571 std::cerr <<
"MonitoringFile::loopOnHistogramsInMetadata(): "
1572 <<
"No \'" << nameStr <<
"\' object found\n";
1575 MetaData md(nameStr,
static_cast<char*
>(i_interval.GetAddress()),
static_cast<char*
>(i_chain.GetAddress()),
static_cast<char*
>(i_merge.GetAddress()));
1576 TObject* obj = i_key->ReadObj();
1577 TH1*
h =
dynamic_cast<TH1*
>(obj);
1579 fcn.executeMD(
h, md);
1581 TGraph* g =
dynamic_cast<TGraph*
>(obj);
1583 fcn.executeMD(g, md);
1595 using namespace std;
1599 ifstream listfile(listFileName.c_str());
1601 cerr <<
"MonitoringFile::setListFromFile(): "
1602 <<
"cannot read from file: " << listFileName <<
"\n";
1609 while (getline(listfile, line)) {
1610 istringstream linestream(line);
1611 while (linestream.get(c)) {
1618 linestream.putback(c);
1619 linestream >> filename;
1621 cerr <<
"MonitoringFile::setListFromFile(): "
1622 <<
"badly formatted line: " << line <<
"\n";
1626 filelist.push_back(filename);
1636 std::cout <<
"Running mergeLBintervals on " << inFilename << std::endl;
1638 std::unique_ptr<TFile> f(TFile::Open(inFilename.c_str(),
"UPDATE"));
1640 std::cout <<
"ERROR, could not open file " << inFilename <<
" for update" << std::endl;
1643 std::string runDirName;
1644 const std::regex runDirPattern(
"run_[0-9]*");
1645 TIter next(f->GetListOfKeys());
1647 while ((key = (TKey*)next())) {
1648 const char* name = key->GetName();
1649 if (std::regex_match(name, runDirPattern)) {
1650 if (runDirName.size() > 0) {
1651 std::cout <<
"ERROR More than one run_XXX directory found! Ignoring " << name << std::endl;
1658 TDirectory* runDir = f->GetDirectory(runDirName.c_str());
1661 if (s_dbg.getLvl() ==
VERBOSE) {
1662 std::cout <<
"LB directory mapping:" << std::endl;
1663 for (
const auto& i1 : mapping) {
1664 std::cout << i1.first;
1665 for (
const auto& i2 : i1.second) {
1666 std::cout <<
"\t" << i2 << std::endl;
1671 for (
const auto& [outDir, inDIrs] : mapping) {
1673 if (stat)
return stat;
1677 f.reset(TFile::Open(inFilename.c_str(),
"UPDATE"));
1678 runDir = f->GetDirectory(runDirName.c_str());
1680 std::cout <<
"merging lowStat_LB dirs into run-dir" << std::endl;
1681 std::vector<std::string> lowStatDirs;
1682 for (TObject* oKey : *runDir->GetListOfKeys()) {
1683 TKey* key =
static_cast<TKey*
>(oKey);
1684 const std::string name = key->GetName();
1685 const std::string classname = key->GetClassName();
1686 if (classname.starts_with(
"TDirectory") and name.starts_with(
"lowStat_LB")) {
1687 lowStatDirs.push_back(runDirName +
"/" + name);
1688 s_dbg(
VERBOSE,
"Found input: " + runDirName +
"/" + name);
1700 std::map<std::string, std::vector<std::string>> ranges;
1703 const std::string runDirName = runDir->GetName();
1704 for (TObject* oKey : *runDir->GetListOfKeys()) {
1705 TKey* key =
static_cast<TKey*
>(oKey);
1706 const std::string name = key->GetName();
1707 const std::string classname = key->GetClassName();
1708 if (!classname.starts_with(
"TDirectory"))
1710 if (name.starts_with(
"lb_")) {
1711 unsigned lumiBlock = 0;
1713 lumiBlock = std::stol(name.substr(3));
1714 }
catch (std::invalid_argument& e) {
1715 std::cout <<
"ERROR, unexpected directory name " << name <<
". Can't parse lb number" << std::endl;
1716 std::cout << e.what() << std::endl;
1720 const unsigned lbBase = lumiBlock - (((int64_t)lumiBlock - 1) % 20);
1721 const std::string lbString = runDirName +
"/lowStat_LB" + std::to_string(lbBase) +
"-" + std::to_string(lbBase + 19);
1722 ranges[lbString].push_back(runDirName +
"/" + name);
1730 TDirectory* outDir =
file->GetDirectory(outputDirName.c_str());
1732 outDir =
file->mkdir(outputDirName.c_str());
1735 std::cout <<
"ERROR, can't obtain nor create directory " << outputDirName <<
" in file " <<
file->GetName() << std::endl;
1743 for (
const std::string& inDirName : inputDirNames) {
1744 TDirectory* inDir =
file->GetDirectory(inDirName.c_str());
1747 if (hc.
size() == 0) {
1748 std::cout <<
"mergeLB_processLBinterval: No new objects found for " << outputDirName << std::endl;
1756 std::unique_ptr<TObject> obj(f->Get(HistoName));
1765 return s_dbg.getLvl();
1782 std::string path = dir->GetPath();
1783 if (path.find(
':') != std::string::npos)
1784 path = path.substr(path.rfind(
':') + 1);