ATLAS Offline Software
Loading...
Searching...
No Matches
MonitoringFile.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
6
7#include <TDirectory.h>
8#include <TEfficiency.h>
9#include <TFile.h>
10#include <TGraph.h>
11#include <TH1.h>
12#include <TH2.h>
13#include <TIterator.h>
14#include <TKey.h>
15#include <TObject.h>
16#include <TROOT.h>
17#include <TSystem.h>
18#include <TTree.h>
19
20#include <cmath>
21#include <cstdio>
22#include <ctime>
23#include <exception>
24#include <filesystem>
25#include <format>
26#include <fstream>
27#include <iostream>
28#include <map>
29#include <memory>
30#include <set>
31#include <sstream>
32#include <vector>
33
36#include "TTreeReader.h"
37#include "TTreeReaderArray.h"
38
40
41namespace{
42 const std::string emptyStr;
43}
44
46
47namespace dqutils {
48
49 class dbgPrint {
50
51 public:
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;
56 }
57 void setLvl(const debugLevel_t lvl) { m_currLvl = lvl; }
58 debugLevel_t getLvl() const { return m_currLvl; }
59
60 private:
61 debugLevel_t m_currLvl;
62 };
63
64 static dbgPrint s_dbg;
65 static bool s_checkEquality=false;
66
67 std::optional<std::regex> checkRegEx(const std::string& re) {
68 if (re.empty())
69 return std::nullopt;
70
71 std::regex reNew(re);
72 try {
73 // this should fail if there are any problems with 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;
79 return std::nullopt;
80 }
81 return reNew;
82 }
83
84 // Internally used data-structures:
85
86 class histCollection {
87 public:
88 explicit histCollection(TFile* out, bool skipExisting = false) : m_out{out}, m_skipExisting(skipExisting) {};
89 histCollection() = delete;
90
92
93 void addDirectory(TDirectory* dir, const std::string& dirName, const std::string& filename = emptyStr);
94 size_t size() { return m_data.size(); };
95 void print();
96 void write(); // Destructive method, will delete internal data after writing
97
98 void addDirExclusion(const std::optional<std::regex>& dirEx);
99 void addHistExclusion(const std::optional<std::regex>& histEx);
100
101 unsigned size() const;
102 void clear();
103
104 fileLBMap_t getFileLBMapAndClear() {
105 m_data.clear();
106 return std::move(m_fileLBMap);
107 }
108
109 void printTiming();
110
111 private:
112 class histPerDir_t {
113 public:
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) {}
117
118 std::string name;
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);
124
125 private:
126 bool fillMD(TTree* mdTree);
127 };
128
129 struct histDir_t {
130 std::unordered_map<std::string, histPerDir_t> histos;
131 void writeMD(TDirectory* outDir) const;
132 };
133
134 private:
135 TFile* m_out;
136 bool m_skipExisting;
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;
141 };
142
143 void histCollection::clear() {
144 m_data.clear();
145 m_fileLBMap.clear();
146 }
147
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);
153 }
154 }
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;
160 }
161 return;
162 }
163
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");
170
171 bool found = false;
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())};
176 found = true;
177 break;
178 }
179 }
180 return found;
181 }
182
183 void histCollection::histPerDir_t::merge(TObject * other) {
184 if (obj && other) {
185 const std::clock_t cpuStart = std::clock();
186 this->mergeMethod(obj.get(), other);
187 cpuSum += std::clock() - cpuStart;
188 }
189 return;
190 }
191
192 void histCollection::histDir_t::writeMD(TDirectory * out) const {
193
194 // Check if there is already a metadata-tree. Merge content if necessary
195 std::map<std::string, std::array<std::string, 3>> metadatamap;
196 std::unique_ptr<TTree> oldMD((TTree*)out->Get("metadata"));
197 if (oldMD) {
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");
203
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())};
207 }
208 }
209
210 for (const auto& [key, h] : histos) {
211 if (h.metadata[0]!="unset") //Ignore dummy-metadata (eg HLTMon use-case)
212 metadatamap[key] = h.metadata;
213 }
214
215 if (metadatamap.empty()) return; //Do not write empty metadata tree
216 std::string interval, chain, merge;
217 char histname[1024]; // FIXME, no idea why this works only in this old-fashioned way
218 std::unique_ptr<TTree> mdTree = std::make_unique<TTree>("metadata", "Monitoring Metadata");
219 mdTree->SetDirectory(out);
220
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");
225
226 mdTree->SetBranchAddress("Name", histname);
227
228 for (auto& [key, h] : metadatamap) {
229 strncpy(histname, key.c_str(), 1023);
230 interval = h[0];
231 chain = h[1];
232 merge = h[2];
233 mdTree->Fill();
234 }
235 mdTree->Write(0, TObject::kOverwrite);
236 }
237
238 histCollection::~histCollection() {}
239
240 void histCollection::addDirExclusion(const std::optional<std::regex>& dir) {
241 m_dirExclusion = dir;
242 return;
243 }
244
245 void histCollection::addHistExclusion(const std::optional<std::regex>& dir) {
246 m_histExclusion = dir;
247 return;
248 }
249
250 unsigned histCollection::size() const {
251 unsigned s = 0;
252 for (const auto& it : m_data) {
253 s += it.second.histos.size();
254 }
255 return s;
256 }
257
258 void histCollection::print() {
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;
264 }
265 return;
266 }
267
268 template <class HIST>
269 void defaultMerge(TObject * a, const TObject* b) {
270 static_cast<HIST*>(a)->Add(static_cast<const HIST*>(b));
271 return;
272 }
273
274 void weightedAverage ATLAS_NOT_THREAD_SAFE(TObject * a, const TObject* b) {
275 TH1* a1 = (dynamic_cast<TH1*>(a));
276 const TH1* b1 = dynamic_cast<const TH1*>(b);
277 if (!b1 || !a1)
278 std::cout << "ERROR in weightedAverageTH1: Object not of type TH1" << std::endl;
279 else {
280 if (b1->GetEntries()==0) return;
282 }
283 return;
284 }
285
286 void weightedEff ATLAS_NOT_THREAD_SAFE(TObject * a, const TObject* b) {
287 TH1* a1 = (dynamic_cast<TH1*>(a));
288 const TH1* b1 = (dynamic_cast<const TH1*>(b));
289 if (!b1 || !a1)
290 std::cout << "ERROR in weightedEff: Object not of type TH1" << std::endl;
291 else {
292 if (b1->GetEntries()==0) return;
294 }
295 return;
296 }
297
298 void mergeRMS ATLAS_NOT_THREAD_SAFE(TObject * a, const TObject* b) {
299 TH1* a1 = (dynamic_cast<TH1*>(a));
300 const TH1* b1 = dynamic_cast<const TH1*>(b);
301 if (!b1 || !a1)
302 std::cout << "ERROR in mergeRMS: Object not of type TH1" << std::endl;
303 else {
304 if (b1->GetEntries()==0) return;
306 }
307 return;
308 }
309
310 void RMSpercentDeviation ATLAS_NOT_THREAD_SAFE(TObject * a, const TObject* b) {
311 TH1* a1 = (dynamic_cast<TH1*>(a));
312 const TH1* b1 = dynamic_cast<const TH1*>(b);
313 if (!b1 || !a1)
314 std::cout << "ERROR in RMSpercentDeviation: Object not of type TH1" << std::endl;
315 else {
316 if (b1->GetEntries()==0) return;
318 }
319 return;
320 }
321
322 void perBinEffPerCent ATLAS_NOT_THREAD_SAFE(TObject * a, const TObject* b) {
323 TH1* a1 = (dynamic_cast<TH1*>(a));
324 const TH1* b1 = dynamic_cast<const TH1*>(b);
325 if (!b1 || !a1)
326 std::cout << "ERROR in getBinEffPerCent: Object not of type TH1" << std::endl;
327 else {
328 if (b1->GetEntries()==0) return;
330 }
331 return;
332 }
333
334 void lowerLB ATLAS_NOT_THREAD_SAFE(TObject * a, const TObject* b) {
335 TH1* a1 = (dynamic_cast<TH1*>(a));
336 const TH1* b1 = dynamic_cast<const TH1*>(b);
337 if (!b1 || !a1)
338 std::cout << "ERROR in lowerLB: Object not of type TH1" << std::endl;
339 else
341 return;
342 }
343
344 template <class HIST>
345 void identical(TObject * a, const TObject* b) {
346 if (!s_checkEquality)
347 return; //quasi null-operation
348 HIST* a1 = (dynamic_cast<HIST*>(a));
349 const HIST* b1 = dynamic_cast<const HIST*>(b);
350 if (!b1 || !a1){
351 std::cout << "ERROR in identical: Object not of correct type" << std::endl;
352 return;
353 }
355 return;
356 }
357
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);
361 if (!a1 || !b1) {
362 std::cout << "ERROR, in merge_rebinned: Object not of type TH1";
363 return;
364 }
365 TH1* b2 = const_cast<TH1*>(b1);
367 return;
368 }
369
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);
373 if (!a1 || !b1) {
374 std::cout << "ERROR in merge_eventSample: Object not of type TH2" << std::endl;
375 return;
376 }
378 }
379
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);
384 if (!a1 || !b1) {
385 std::cout << "ERROR in merge_TEfficiency: Object not of type TEfficiency" << std::endl;
386 return;
387 }
388 TList listE;
389 listE.Add(b2);
390 a1->Merge(&listE);
391 listE.Clear();
392 }
393
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);
397 if (!a1 || !b1) {
398 std::cout << "ERROR in merge_TTree: Object not of type TTree" << std::endl;
399 return;
400 }
401 TTree* b2 = const_cast<TTree*>(b1);
402 TList listT;
403 listT.Add(b2);
404 a1->Merge(&listT);
405 listT.Clear();
406 }
407
408 histCollection::histPerDir_t::histPerDir_t(const std::string& nameIn, std::unique_ptr<TObject>&& objIn, TTree* mdTree)
409 : name(nameIn), obj(std::move(objIn)), mergeMethod(nullptr) {
410 // Some sanity checks:
411 if (!obj) {
412 std::cout << "ERROR while adding " << nameIn << ": Histogram pointer is NULL" << std::endl;
413 return;
414 }
415
416 if (mdTree) {
417 fillMD(mdTree);
418 }
419 else {
420 s_dbg(VERBOSE,"No matadata found for " + name +", use defaults");
421 }
422 const std::string& howToMerge = metadata[2];
423 s_dbg(VERBOSE, "Name: " + name + " mergeMethod=" + howToMerge);
424
425 TH1* th1 = dynamic_cast<TH1*>(obj.get());
426 TH2* th2 = dynamic_cast<TH2*>(obj.get());
427 TEfficiency* teff = dynamic_cast<TEfficiency*>(obj.get());
428 if (th1) {
429 th1->SetDirectory(nullptr); // Get ownership of this hist
430 if (howToMerge == "<default>") {
431 if (th2) {
432 mergeMethod = &defaultMerge<TH2>;
433 } else { //TH1 case
434 mergeMethod = &defaultMerge<TH1>;
435 }
436 }
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")
450 if (th2) {
451 mergeMethod = &identical<TH2>;
452 } else { //TH1 case
453 mergeMethod = &identical<TH1>;
454 }
455 else if ((howToMerge == "mergeRebinned") || (howToMerge == "merge"))
456 mergeMethod = &merge_rebinned;
457 else {
458 std::cout << "ERROR: Unknown merging method (" << howToMerge << ") for object of type TH1 named " << nameIn << std::endl;
459 obj.reset(nullptr);
460 }
461 } // end if TH1
462 else if (teff) {
463 teff->SetDirectory(nullptr);
464 if (howToMerge == "<default>")
465 mergeMethod = &merge_TEfficency;
466 else
467 std::cout << "ERROR: Unknown merging method (" << howToMerge << ") for object of type TEfficiency named " << nameIn << std::endl;
468 } // end if TEfficiency
469 else if (nullptr != dynamic_cast<TTree*>(obj.get())) {
470 mergeMethod = &merge_TTree;
471 } else {
472 std::cout << "ERROR Object " << name << " has unkown type" << std::endl;
473 obj.reset(nullptr);
474 }
475 }
476
477 void histCollection::addDirectory(TDirectory * dir, const std::string& dirName, const std::string& filename) {
478
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");
482 return;
483 }
484
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")) {
490 continue;
491 }
492
493 s_dbg(VERBOSE, "Found name " + name + ", classname=" + classname);
494
495 const std::string newName = dirName.empty() ? name : dirName + "/" + name;
496 auto itDir = m_data.find(dirName);
497
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");
501 continue;
502 }
503
504 // arrive here if we have at least one histogram in this directory
505 if (m_skipExisting) {
506 // Check if this object exists already in the output-file
507 std::unique_ptr<TObject> existingObj(m_out->Get(newName.c_str()));
508 if (existingObj)
509 continue;
510 }
511
512 std::unique_ptr<TTree> md;
513 if (itDir == m_data.end()) {
514 // Have not seen this dirName yet
515 itDir = m_data.emplace(dirName, histDir_t()).first;
516 s_dbg(VERBOSE, "Registering new directory " + dirName);
517 }
518
519 // Check if we already have this histogram in the list
520 auto itH = itDir->second.histos.find(name);
521 if (itH == itDir->second.histos.end()) {
522 // New histogram (or Tree):
523 if (!md) {
524 // Metadata tree not yet read in this directory
525 md.reset((TTree*)dir->Get("metadata"));
526 }
527
528 std::unique_ptr<TObject> obj{key->ReadObj()};
529 TTree* treeObj = dynamic_cast<TTree*>(obj.get());
530 if (treeObj) {
531 TDirectory* outDir = m_out->GetDirectory(dirName.c_str());
532 if (!outDir)
533 outDir = m_out->mkdir(dirName.c_str());
534 // TTree need special treatment ...
535 TDirectory* currentDir = gDirectory;
536 outDir->cd();
537 TTree* cloneTree = treeObj->CloneTree();
538 // this disconnects parent tree
539 obj.reset(cloneTree);
540 currentDir->cd();
541 }
542 histPerDir_t histo(name, std::move(obj), md.get());
543 itH = itDir->second.histos.emplace(name, std::move(histo)).first; //Take owernship of object here!
544 s_dbg(VERBOSE, "Cloning histogram " + name + " in dir " + dirName);
545 } else {
546 // Histogram already known .. merge it
547 std::unique_ptr<TObject> other(key->ReadObj());
548 if (!other) {
549 std::cout << "ERROR, got NULL key";
550 } else {
551 itH->second.merge(other.get()); // Release object in this case
552 s_dbg(VERBOSE, "Merging histogram " + name + " in dir " + dirName);
553 }
554 }
555 } else if (classname.starts_with("TDirectory")) {
556 std::unique_ptr<TObject> obj(key->ReadObj());
557 TDirectory* subdir = dynamic_cast<TDirectory*>(obj.get());
558 if (subdir) {
559 if (filename.empty()) {
560 this->addDirectory(subdir, newName, filename);
561 } else {
562 if (!name.starts_with("lb_") && !name.starts_with("lowStat_LB")) {
563 this->addDirectory(subdir, newName, filename);
564 } else {
565 m_fileLBMap[newName].insert(filename);
566 }
567 }
568 }
569 } else {
570 std::cout << "Ignored objects '" << name << "' of type " << classname << std::endl;
571 }
572 }
573 return;
574 }
575
576 void histCollection::write() {
577 unsigned nWritten = 0;
578 unsigned nIgnored = 0;
579 unsigned nDirs = 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) { // Create the directory if it doesn't exist yet
584 histDir = m_out->mkdir(fulldir.c_str());
585 if (histDir == nullptr) {
586 std::cout << "ERROR, failed to create directory " << fulldir << std::endl;
587 break;
588 } else {
589 s_dbg(VERBOSE, "Created directory " + fulldir + " in file " + m_out->GetName());
590 }
591 }
592 m_out->cd(fulldir.c_str());
593 ++nDirs;
594 for (auto& [name, histo] : it.second.histos) {
595 if (histo.obj) {
596 histo.obj->Write();
597 ++nWritten;
598 } else {
599 std::cout << "NOT writing " << name << ". Invalid." << std::endl;
600 ++nIgnored;
601 }
602 } // End loop over histograms in one directory
603 it.second.writeMD(histDir);
604 } // End loop over directories;
605 std::cout << "Wrote " << nWritten << " histograms to " << nDirs << " directories in output file " << m_out->GetName() << std::endl;
606 if (nIgnored)
607 std::cout << " Omitting " << nIgnored << " histograms." << std::endl;
608 }
609
610 // *********************************************************************
611 // Public Methods
612 // *********************************************************************
613
614 MonitoringFile::OutputMetadata::OutputMetadata(TTree * metadata) : m_metadata(metadata) {
615 makeBranch("Name", "Name/C");
616 makeBranch("Interval", "Interval/C");
617 makeBranch("TriggerChain", "TriggerChain/C");
618 makeBranch("MergeMethod", "MergeMethod/C");
619 }
620
621 void MonitoringFile::OutputMetadata::makeBranch(const char* branchName, const char* branchstr) {
622 if (!m_metadata->GetBranch(branchName)) {
623 m_metadata->Branch(branchName, (void*)nullptr, branchstr);
624 }
625 }
626
627 void MonitoringFile::OutputMetadata::fill(const std::string& theName, const std::string& theInterval, const std::string& theChain,
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());
637 m_metadata->Fill();
638 }
639
642 m_doTiming = false;
644 }
645
646 bool MonitoringFile::setFile(const std::string& fileName) {
647 clearData();
648 m_file = TFile::Open(fileName.c_str());
649 if (m_file != 0)
650 return true;
651 return false;
652 }
653
654 MonitoringFile::MonitoringFile(const std::string& fileName) : m_file(0) {
656 m_doTiming = false;
658 MonitoringFile::setFile(fileName);
659 }
660
662 dqi::DisableMustClean disabled;
663
664 delete m_file;
665 }
666
667 bool MonitoringFile::setHistogramRegEx(const std::string& re) {
668 m_mergeMatchHistoRE = checkRegEx(re);
669 return m_mergeMatchHistoRE.has_value();
670 }
671
672 bool MonitoringFile::setDirectoryRegEx(const std::string& re) {
673 m_mergeMatchDirRE = checkRegEx(re);
674 return m_mergeMatchDirRE.has_value();
675 }
676
677 void MonitoringFile::getAllDirs(DirMap_t & dirmap, TDirectory * dir, const std::string& dirName) {
678 if (dir == 0)
679 return;
680
681 if (dirName != "") {
682 DirMap_t::value_type dirmapVal(dirName, dir);
683 dirmap.insert(std::move(dirmapVal));
684 }
685
686 TIter next(dir->GetListOfKeys());
687 TKey* key;
688 while ((key = dynamic_cast<TKey*>(next())) != 0) {
689 // don't delete TDirectories
690 TObject* obj = key->ReadObj();
691 TDirectory* subdir = dynamic_cast<TDirectory*>(obj);
692 if (subdir != 0) {
693 std::string subdirName(subdir->GetName());
694 std::string fName("");
695 if (dirName != "") {
696 fName += dirName;
697 fName += '/';
698 }
699 fName += subdirName;
700 getAllDirs(dirmap, subdir, fName);
701 } else {
702 delete obj;
703 }
704 }
705 }
706
707 TDirectory* MonitoringFile::createDir(DirMap_t & dirmap, TDirectory * dir, const std::string& parent, const std::string& path) {
708 if (dir == 0)
709 return 0;
710
711 TDirectory* subdir(0);
712 DirMap_t::const_iterator diter;
713 std::string::size_type i = path.find_first_of('/');
714 std::string fName("");
715 if (parent != "") {
716 fName += parent;
717 fName += '/';
718 }
719
720 if (i != std::string::npos) {
721 std::string dName(path, 0, i);
722 std::string pName(path, i + 1, std::string::npos);
723 fName += dName;
724 if (dName != "") {
725 diter = dirmap.find(fName);
726 if (diter != dirmap.end()) {
727 subdir = diter->second;
728 } else {
729 subdir = dir->mkdir(dName.c_str());
730 DirMap_t::value_type dirmapVal(fName, subdir);
731 dirmap.insert(std::move(dirmapVal));
732 }
733 } else {
734 subdir = dir;
735 }
736 return createDir(dirmap, subdir, fName, pName);
737 }
738
739 fName += path;
740
741 diter = dirmap.find(fName);
742 if (diter != dirmap.end()) {
743 return diter->second;
744 }
745
746 subdir = dir->mkdir(path.c_str());
747 DirMap_t::value_type dirmapVal(fName, subdir);
748 dirmap.insert(std::move(dirmapVal));
749 return subdir;
750 }
751
752 TKey* MonitoringFile::getObjKey(TDirectory * dir, const std::string& path) {
753 if (dir == 0)
754 return 0;
755
756 TKey* key(0);
757
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);
762 if (dName != "") {
763 key = dir->FindKey(dName.c_str());
764 if (key != 0) {
765 TDirectory* subDir = dynamic_cast<TDirectory*>(key->ReadObj());
766 if (subDir) {
767 return getObjKey(subDir, pName);
768 } // else fall through
769 }
770 return 0;
771 }
772 return getObjKey(dir, pName);
773 }
774
775 return dir->FindKey(path.c_str());
776 }
777
778 void MonitoringFile::fillMetaDataMap(std::map<std::string, dqutils::MonitoringFile::MetaData> & mdMap, TDirectory * dir) {
779 if (dir == 0)
780 return;
781 TTree* md = dynamic_cast<TTree*>(dir->Get("metadata"));
782 if (md == 0)
783 return;
784
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");
790
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));
797 }
798 }
799
800 delete md;
801 }
802
803 int MonitoringFile::mergeFiles(const std::string & outFileName, const std::vector<std::string>& files, fileLBMap_t& lbmap, bool fillLBDirs) {
804 std::cout << "Writing file: " << outFileName << std::endl;
805 std::cout << "Start merging [" << files.size() << "] histogram files" << std::endl;
806 dqi::DisableMustClean disabled;
807 TH1::AddDirectory(false);
808 if (m_mergeMatchDirRE.has_value() || m_mergeMatchHistoRE.has_value()) {
809 std::cout << " ========== Using regular expressions for selective merging ========== " << std::endl;
810 }
811 if (m_doTiming) {
812 std::cout << "CPU time measurement activated " << std::endl;
813 }
814
815 const size_t nFiles = files.size();
816
817 if (nFiles < 1)
818 return -1;
819
820 if (nFiles == 1) {
821 std::cout << "Got exactly one input file. Will copy input -> output" << std::endl;
822 if (m_mergeMatchDirRE.has_value() || m_mergeMatchHistoRE.has_value()) {
823 std::cout << "regular expressions for selective merging will have no effect!" << std::endl;
824 }
825
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);
829 return 0;
830 }
831
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;
835 return -1;
836 }
837 std::cout << "Opened/created output file " << outFileName << std::endl;
838
839 histCollection hc(outfile.get());
840 hc.addDirExclusion(m_mergeMatchDirRE);
841 hc.addHistExclusion(m_mergeMatchHistoRE);
842
843 // Open first input file, mostly to get the run-directory
844 std::unique_ptr<TFile> in1(TFile::Open(files[0].c_str()));
845 if (!in1) {
846 std::cout << "ERROR, could not open input file " << files[0] << std::endl;
847 return -1;
848 }
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());
853 TKey* key;
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;
859 } else
860 runDir = name;
861 }
862 }
863 if (runDir.empty()) {
864 std::cout << "No run-directory found, start with '/'" << std::endl;
865 runDir="/";
866 runDirFwd="";
867 }
868 else {
869 std::cout << "Found run directory " << runDir << std::endl;
870 runDirFwd=runDir;
871 }
872
873
874 TDirectory* dir(dynamic_cast<TDirectory*>(in1->GetDirectory(runDir.c_str())));
875 if (!dir) {
876 std::cout << "ERROR, can't access directory " << runDir;
877 return -1;
878 }
879
880 hc.addDirectory(dir, runDirFwd, files[0]);
881
882 // Close first input file
883 in1.reset(nullptr);
884
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()));
888 if (!in) {
889 std::cout << "ERROR, could not open input file " << files[i] << std::endl;
890 return -1;
891 }
892 TDirectory* dir(dynamic_cast<TDirectory*>(in->GetDirectory(runDir.c_str())));
893 if (not dir){
894 std::cout << "ERROR, could not cast to directory" << std::endl;
895 return -1;
896 }
897 hc.addDirectory(dir, runDirFwd, files[i]);
898 }
899
900 std::cout << "Accumulated a total of " << hc.size() << " histograms." << std::endl;
901
902 std::cout << "Start writing output ..." << std::endl;
903 hc.write();
904
905 if (m_doTiming) {
906 std::cout << "CPU time for histogram merging: (regular histograms)" << std::endl;
907 hc.printTiming();
908 }
909
910 auto newlbmap = hc.getFileLBMapAndClear();
911
912 // Update file-to-lbdir map pass as argument with the new map from these files
913 for (auto& [lbname, newfileset] : newlbmap) {
914 auto& fileset = lbmap[lbname];
915 fileset.merge(newfileset);
916 }
917
918 if (!lbmap.empty() && fillLBDirs) {
919 std::cout << "Start merging lb_nnn and lowStat_LB directories (" << lbmap.size() << " in total)" << std::endl;
920
921 histCollection hclb(outfile.get());
922 hclb.addDirExclusion(m_mergeMatchDirRE);
923 hclb.addHistExclusion(m_mergeMatchHistoRE);
924
925 // Sort lb/file list by file-name to avoid re-oping the same files:
926 // Copy map to vector<pair> ...
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()));
931 }
932
933 //..and sort the vector
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]; });
936
937 size_t counter = 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() << ")"
941 << std::endl;
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);
946 } else {
947 s_dbg(DEBUG, "Input file " + fName + " already open");
948 }
949
950 if (!in) {
951 std::cout << "ERROR, could not open input file " << fName << std::endl;
952 return -1;
953 }
954 TDirectory* tDir = (dynamic_cast<TDirectory*>(in->Get(dir.c_str())));
955 if (!tDir) {
956 std::cout << "ERROR, failed to get directory " << dir << " from file " << fName << std::endl;
957 } else {
958 hclb.addDirectory(tDir, dir);
959 }
960 } // end loop over filenames
961 hclb.write();
962 if (m_doTiming) {
963 std::cout << "CPU time for histogram merging: (lumiblock-histograms)" << std::endl;
964 hclb.printTiming();
965 }
966 hclb.clear();
967 } // end loop over lbmap
968 in.reset(nullptr);
969 }
970 return 0;
971 }
972
973 int MonitoringFile::mergeFiles(const std::string& outFileName, const std::string& listFileName) {
974 typedef std::vector<std::string> FileList_t;
975
976 const unsigned int nFilesAtOnce = 50;
977
978 FileList_t allFiles;
979 bool success = setListFromFile(allFiles, listFileName);
980 if (!success) {
981 std::cout << "ERROR Failed ot read list of input files" << std::endl;
982 return -1;
983 }
984
985
986 fileLBMap_t fileLBMap;
987 if (allFiles.size() <= nFilesAtOnce) {
988 return mergeFiles(outFileName, allFiles, fileLBMap, true);
989 }
990
991 FileList_t procFiles, tmpIntermediateFiles;
992
993 FileList_t::const_iterator filesEnd = allFiles.end();
994 FileList_t::const_iterator fi = allFiles.begin();
995
996 unsigned int counter = 0;
997 std::string tmpInputFile("");
998 std::string tmpOutputFile("");
999
1000 // new logic: merge intermediately, then merge intermediate files
1001 while (fi != filesEnd) {
1002
1003 procFiles.push_back(*fi);
1004 ++counter;
1005 ++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;
1013 procFiles.clear();
1014 }
1015 }
1016
1017 int stat=mergeFiles(outFileName, tmpIntermediateFiles,fileLBMap,true);
1018 if (stat) return stat;
1019
1020 for (const auto& tmpFile : tmpIntermediateFiles) {
1021 auto rc = std::remove(tmpFile.c_str());
1022 if (rc!=0){
1023 std::cerr<<"MonitoringFile::mergeFiles: tmpFile "<<tmpFile<<" could not be removed\n";
1024 }
1025 }
1026 return 0;
1027 }
1028
1030 if (m_file == 0) {
1031 std::cerr << "MonitoringFile::printStatistics(): "
1032 << "No input file is open\n";
1033 return;
1034 }
1035
1036 DirMap_t indirmap;
1037
1038 getAllDirs(indirmap, m_file, "");
1039
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;
1043
1044 GatherStatistics stat_shift(idirName);
1045 GatherStatistics stat_all(idirName);
1046
1047 loopOnHistogramsInMetadata(stat_shift, idir->second);
1048 loopOnHistograms(stat_all, idir->second);
1049
1050 std::cout.setf(std::ios_base::left, std::ios_base::adjustfield);
1051 std::cout.width(80);
1052 std::cout << idirName << " ";
1053
1054 std::cout.setf(std::ios_base::right, std::ios_base::adjustfield);
1055 std::cout << " shift: ";
1056 std::cout.width(3);
1057 std::cout << stat_shift.m_nHist1D << " ";
1058 std::cout.width(5);
1059 std::cout << stat_shift.m_nHist1DBins << " ";
1060 std::cout.width(3);
1061 std::cout << stat_shift.m_nHist2D << " ";
1062 std::cout.width(7);
1063 std::cout << stat_shift.m_nHist2DBins << " ";
1064 std::cout.width(3);
1065 std::cout << stat_shift.m_nGraph << " ";
1066 std::cout.width(5);
1067 std::cout << stat_shift.m_nGraphPoints << " ";
1068
1069 std::cout << " all: ";
1070 std::cout << stat_all.m_nHist1D << " ";
1071 std::cout.width(5);
1072 std::cout << stat_all.m_nHist1DBins << " ";
1073 std::cout.width(3);
1074 std::cout << stat_all.m_nHist2D << " ";
1075 std::cout.width(7);
1076 std::cout << stat_all.m_nHist2DBins << " ";
1077 std::cout.width(3);
1078 std::cout << stat_all.m_nGraph << " ";
1079 std::cout.width(5);
1080 std::cout << stat_all.m_nGraphPoints << "\n";
1081
1082 std::cout << std::flush;
1083 }
1084 }
1085
1086 bool MonitoringFile::copyHistograms(const std::string& outFileName, const std::string& dirName) {
1087 dqi::DisableMustClean disabled;
1088 // bool useRecursiveDelete = gROOT->MustClean();
1089 // gROOT->SetMustClean(false);
1090
1091 if (m_file == 0) {
1092 std::cerr << "MonitoringFile::copyHistograms(): "
1093 << "No input file is open\n";
1094 return false;
1095 }
1096
1097 DirMap_t indirmap;
1098 DirMap_t reducedmap;
1099 DirMap_t outdirmap;
1100
1101 if (dirName != "all") {
1102 TKey* dkey = getObjKey(m_file, dirName);
1103 if (dkey == 0) {
1104 std::cerr << "MonitoringFile::copyHistograms(): "
1105 << "Directory \'" << dirName << "\' not found in input file\n";
1106 return false;
1107 }
1108
1109 TDirectory* fromDir = dynamic_cast<TDirectory*>(dkey->ReadObj());
1110
1111 DirMap_t::value_type dirmapVal(dirName, fromDir);
1112 indirmap.insert(std::move(dirmapVal));
1113 } else {
1114 std::cout << "Building list of all TDirectories in file...\n" << std::flush;
1115 getAllDirs(indirmap, m_file, "");
1116 }
1117
1118 DirMap_t::const_iterator idirend = indirmap.end();
1119 for (DirMap_t::const_iterator idir = indirmap.begin(); idir != idirend; ++idir) {
1120
1121 std::string idirName = idir->first;
1122 std::cout << "Checking " << idirName << "\n" << std::flush;
1123
1124
1125 if (!dirHasHistogramsInMetadata(idir->second)) {
1126 continue;
1127 }
1128
1129 reducedmap.insert(*idir);
1130 }
1131
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";
1136 return false;
1137 }
1138
1139 idirend = reducedmap.end();
1140 for (DirMap_t::const_iterator idir = reducedmap.begin(); idir != idirend; ++idir) {
1141
1142 std::string idirName = idir->first;
1143 std::cout << "Processing " << idirName << "\n" << std::flush;
1144
1145 TDirectory* toDir = createDir(outdirmap, outfile.get(), emptyStr, idirName);
1146 if (toDir == 0) {
1147 std::cerr << "MonitoringFile::copyHistograms(): "
1148 << "Directory \'" << idirName << "\' not created in output file\n";
1149 return false;
1150 }
1151
1152 CopyHistogram copyFcn(toDir, idirName);
1153
1154 loopOnHistogramsInMetadata(copyFcn, idir->second);
1155 }
1156
1157 outfile->Write();
1158 // gROOT->SetMustClean(useRecursiveDelete);
1159 return true;
1160 }
1161
1162 std::string MonitoringFile::getHanResults(const std::string& hanResultsDir, const std::string& input, const std::string& hcfg,
1163 const std::string& hcfg_lowStat, const std::string& hcfg_medStat) {
1164 // DisableMustClean disabled;
1165
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"
1170 << std::flush;
1171
1172 TFile* infile = TFile::Open(input.c_str());
1173 if (infile == 0) {
1174 std::cerr << "MonitoringFile::getHanResults(): "
1175 << "Cannot open input file \"" << input << "\"\n";
1176 return "";
1177 }
1178
1179 std::vector<std::string> run_dirs;
1180 std::vector<std::string> lowStat_dirs;
1181 std::vector<std::string> medStat_dirs;
1182
1183 TIter next_run(infile->GetListOfKeys());
1184 TKey* key_run(0);
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);
1203 }
1204 }
1205 delete obj_minutes;
1206 }
1207 }
1208 }
1209 delete obj_run;
1210 }
1211
1212 delete infile;
1213
1215
1216 std::string fileList = " ";
1217 std::vector<std::string>::const_iterator dirs_end;
1218 std::vector<std::string>::const_iterator dir;
1219
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);
1226 std::cout << "\n";
1227 fileList += han_output_run + " " + tdir_run_name + "\n";
1228 }
1229
1230 dirs_end = lowStat_dirs.end();
1231 for (dir = lowStat_dirs.begin(); dir != dirs_end; ++dir) {
1232 const std::string& tdir_minutes_path = *dir;
1233
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, "_");
1237
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);
1241 std::cout << "\n";
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";
1245 }
1246
1247 dirs_end = medStat_dirs.end();
1248 for (dir = medStat_dirs.begin(); dir != dirs_end; ++dir) {
1249 const std::string& tdir_minutes_path = *dir;
1250
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, "_");
1254
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);
1258 std::cout << "\n";
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";
1262 }
1263
1264 return fileList;
1265 }
1266
1268 if (m_file == 0) {
1269 std::cerr << "MonitoringFile::printHanConfig(): "
1270 << "No input file is open\n";
1271 return;
1272 }
1273
1274 DirMap_t indirmap;
1275
1276 getAllDirs(indirmap, m_file, "");
1277
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);
1285
1286 std::string::size_type fsIndex = idirName.find('/');
1287 std::string shortPath;
1288 if (fsIndex != shortNameIndex)
1289 shortPath = idirName.substr(fsIndex + 1, shortNameIndex);
1290 else
1291 shortPath = idirName.substr(fsIndex + 1, std::string::npos);
1292
1293 std::cout << idirName << "\n";
1294 std::cout << shortPath << ", " << shortName << "\n";
1295 /*
1296 indent = getIndentation(idirName,"");
1297 if(int(indent.size())==in_p){
1298 std::cout << indent << "} \n";
1299 std::cout << indent << "dir " << shortName << " { \n";
1300 std::cout << indent << " output " << idirName << "\n";
1301 std::cout << indent << " hist all_in_dir { \n " << indent << " } \n";
1302 }
1303 else if (int(indent.size()) > in_p){
1304 std::cout << indent << "dir " << shortName << " { \n";
1305 std::cout << indent << " output " << idirName << "\n";
1306 std::cout << indent << " hist all_in_dir { \n " << indent << " } \n";
1307 }
1308 else{
1309 //find common part + number of common '/'
1310 std::string common = FindCommon(idirName,idirName_p);
1311 indent_c = getIndentation(common,"");
1312 int counter = (indent_p.size() - indent_c.size())/2;
1313 for (int i = counter; i>0; i--){
1314 std::string temp = indent_c;
1315 for (int j = 0; j< i; j++){
1316 temp+=" ";
1317 }
1318 std::cout << temp << "} \n" ;
1319 }
1320 std::cout << indent << "} \n";
1321 std::cout << indent << "dir " << shortName << " { \n";
1322 std::cout << indent << " output " << idirName << "\n";
1323 std::cout << indent << " hist all_in_dir { \n " << indent << " } \n";
1324 }
1325 indent_p = indent;
1326 in_p = indent_p.size();
1327 idirName_p = idirName;
1328 */
1329 }
1330 }
1331
1332 std::string MonitoringFile::getIndentation(const std::string& pathName, const std::string& leadingSpace) {
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);
1337 space += " ";
1338 return getIndentation(subPath, space);
1339 }
1340 return space;
1341 }
1342
1343 std::string MonitoringFile::FindCommon(const std::string& name1, const std::string& name2) const {
1344 int length = (name1.size() < name2.size()) ? name1.size() : name2.size();
1345 bool found = true;
1346 int count = 0;
1347 while (found == true && count < length) {
1348 if (name1[count] == name2[count]) {
1349 count++;
1350 } else {
1351 found = false;
1352 }
1353 }
1354 return (name1.substr(0, count));
1355 }
1356
1357 // *********************************************************************
1358 // Protected Methods
1359 // *********************************************************************
1360
1361 MonitoringFile::CopyHistogram::CopyHistogram(TDirectory * target, const std::string& dirName) : m_target(target), m_dirName(dirName), m_metadata(0) {
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");
1368 }
1369
1371 m_target->cd();
1372 m_metadata->SetDirectory(m_target);
1373 m_metadata->Write();
1374 delete m_metadata;
1375 }
1376
1378 m_target->cd();
1379 hist->SetDirectory(m_target);
1380 hist->Write();
1381
1382 return true;
1383 }
1384
1385 bool MonitoringFile::CopyHistogram::execute(TGraph * graph) {
1386 m_target->cd();
1387 graph->Write();
1388
1389 return true;
1390 }
1391
1392 bool MonitoringFile::CopyHistogram::execute(TEfficiency * eff) {
1393 m_target->cd();
1394 eff->Write();
1395 return true;
1396 }
1397
1398 void MonitoringFile::CopyHistogram::fillMD(const MetaData& md) {
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());
1407 m_metadata->Fill();
1408 }
1409
1410 bool MonitoringFile::CopyHistogram::executeMD(TH1 * hist, const MetaData& md) {
1411 m_target->cd();
1412 hist->SetDirectory(m_target);
1413 hist->Write();
1414
1415 fillMD(md);
1416
1417 return true;
1418 }
1419
1420 bool MonitoringFile::CopyHistogram::executeMD(TGraph * graph, const MetaData& md) {
1421 m_target->cd();
1422 graph->Write();
1423
1424 fillMD(md);
1425
1426 return true;
1427 }
1428
1429 bool MonitoringFile::CopyHistogram::executeMD(TEfficiency * eff, const MetaData& md) {
1430 m_target->cd();
1431 eff->Write();
1432 fillMD(md);
1433 return true;
1434 }
1435
1436 MonitoringFile::GatherStatistics::GatherStatistics(const std::string& dirName)
1437 : m_dirName(dirName), m_nHist1D(0), m_nHist1DBins(0), m_nGraph(0), m_nGraphPoints(0), m_nHist2D(0), m_nHist2DBins(0) {}
1438
1440 TH2* hist2d = dynamic_cast<TH2*>(hist);
1441 if (hist2d != 0) {
1442 ++m_nHist2D;
1443 m_nHist2DBins += (hist2d->GetNbinsX() * hist2d->GetNbinsY());
1444 return true;
1445 }
1446 ++m_nHist1D;
1447 m_nHist1DBins += hist->GetNbinsX();
1448 return true;
1449 }
1450
1451 bool MonitoringFile::GatherStatistics::execute(TGraph * graph) {
1452 ++m_nGraph;
1453 m_nGraphPoints += graph->GetMaxSize();
1454 return true;
1455 }
1456
1457 bool MonitoringFile::GatherStatistics::execute(TEfficiency * eff) {
1458 ++m_nEfficiency;
1459
1460 TH1* h_total = eff->GetCopyPassedHisto();
1461 TH2* h_total2D = dynamic_cast<TH2*>(h_total);
1462
1463 if (h_total2D != 0) {
1464 m_nEfficiencyBins += (h_total2D->GetNbinsX() * h_total2D->GetNbinsY());
1465 return true;
1466 } else {
1467 m_nEfficiencyBins += h_total->GetNbinsX();
1468 return true;
1469 }
1470 }
1471
1473
1474 bool MonitoringFile::GatherNames::execute(TH1 * hist) {
1475 m_names.push_back(std::string(hist->GetName()));
1476 return true;
1477 }
1478
1479 bool MonitoringFile::GatherNames::execute(TGraph * graph) {
1480 m_names.push_back(std::string(graph->GetName()));
1481 return true;
1482 }
1483
1484 bool MonitoringFile::GatherNames::execute(TEfficiency * eff) {
1485 m_names.push_back(std::string(eff->GetName()));
1486 return true;
1487 }
1488
1490 dqi::DisableMustClean disabled;
1491
1492 delete m_file;
1493 m_file = 0;
1495 m_doTiming = false;
1496 }
1497
1498 bool MonitoringFile::dirHasHistogramsInMetadata(TDirectory * dir) {
1499 dir->cd();
1500
1501 TKey* mdKey = dir->FindKey("metadata");
1502 if (mdKey == 0) {
1503 return false;
1504 }
1505
1506 TTree* md = dynamic_cast<TTree*>(mdKey->ReadObj());
1507 if (md == 0) {
1508 return false;
1509 }
1510
1511 int nEntries = int(md->GetEntries());
1512
1513 if (nEntries > 0) {
1514 try {
1515 md->GetEntry(0);
1516 } catch (const std::exception& e) {
1517 std::cerr << "Exception: \"" << e.what() << "\" in directory \"" << dir->GetName() << "\"\n" << std::flush;
1518 return false;
1519 }
1520
1521 return true;
1522 }
1523
1524 return false;
1525 }
1526
1527 void MonitoringFile::loopOnHistograms(HistogramOperation & fcn, TDirectory * dir) {
1528 TIter next(dir->GetListOfKeys());
1529 TKey* key;
1530 while ((key = dynamic_cast<TKey*>(next())) != 0) {
1531 TObject* obj = key->ReadObj();
1532 TH1* h(0);
1533 TGraph* g(0);
1534 TEfficiency* e(0);
1535 if ((h = dynamic_cast<TH1*>(obj))) {
1536 fcn.execute(h);
1537 } else if ((g = dynamic_cast<TGraph*>(obj))) {
1538 fcn.execute(g);
1539 } else if ((e = dynamic_cast<TEfficiency*>(obj))) {
1540 fcn.execute(e);
1541 }
1542 delete obj;
1543 }
1544 }
1545
1546 bool MonitoringFile::loopOnHistogramsInMetadata(HistogramOperation & fcn, TDirectory * dir) {
1547 dir->cd();
1548 TKey* mdKey = dir->FindKey("metadata");
1549 if (mdKey == 0) {
1550 return false;
1551 }
1552
1553 TTree* md = dynamic_cast<TTree*>(mdKey->ReadObj());
1554 if (md == 0) {
1555 return false;
1556 }
1557
1558 TKey* i_key;
1559
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");
1565
1566 while (reader.Next()) {
1567 const std::string nameStr(static_cast<char*>(i_name.GetAddress()));
1568 dir->cd();
1569 i_key = dir->FindKey(static_cast<char*>(i_name.GetAddress()));
1570 if (i_key == 0) {
1571 std::cerr << "MonitoringFile::loopOnHistogramsInMetadata(): "
1572 << "No \'" << nameStr << "\' object found\n";
1573 return false;
1574 }
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);
1578 if (h != 0) {
1579 fcn.executeMD(h, md);
1580 } else {
1581 TGraph* g = dynamic_cast<TGraph*>(obj);
1582 if (g != 0) {
1583 fcn.executeMD(g, md);
1584 }
1585 }
1586 delete obj;
1587 }
1588
1589 delete md;
1590
1591 return true;
1592 }
1593
1594 bool MonitoringFile::setListFromFile(std::vector<std::string> & filelist, const std::string& listFileName) {
1595 using namespace std;
1596
1597 filelist.clear();
1598
1599 ifstream listfile(listFileName.c_str());
1600 if (!listfile) {
1601 cerr << "MonitoringFile::setListFromFile(): "
1602 << "cannot read from file: " << listFileName << "\n";
1603 return false;
1604 }
1605
1606 string line;
1607 char c;
1608 string filename;
1609 while (getline(listfile, line)) {
1610 istringstream linestream(line);
1611 while (linestream.get(c)) {
1612 if (!isspace(c)) {
1613 // ignore comments
1614 if (c == '#') {
1615 break;
1616 }
1617
1618 linestream.putback(c);
1619 linestream >> filename;
1620 if (!linestream) {
1621 cerr << "MonitoringFile::setListFromFile(): "
1622 << "badly formatted line: " << line << "\n";
1623 break;
1624 }
1625
1626 filelist.push_back(filename);
1627 }
1628 }
1629 }
1630
1631 return true;
1632 }
1633
1634 int MonitoringFile::mergeLBintervals(const std::string& inFilename) {
1635
1636 std::cout << "Running mergeLBintervals on " << inFilename << std::endl;
1637
1638 std::unique_ptr<TFile> f(TFile::Open(inFilename.c_str(), "UPDATE"));
1639 if (!f) {
1640 std::cout << "ERROR, could not open file " << inFilename << " for update" << std::endl;
1641 return -1;
1642 }
1643 std::string runDirName;
1644 const std::regex runDirPattern("run_[0-9]*");
1645 TIter next(f->GetListOfKeys());
1646 TKey* key;
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;
1652 } else
1653 runDirName = name;
1654 }
1655 break;
1656 }
1657
1658 TDirectory* runDir = f->GetDirectory(runDirName.c_str());
1659 const auto mapping = buildLBToIntervalMap(runDir);
1660
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;
1667 }
1668 }
1669 }
1670
1671 for (const auto& [outDir, inDIrs] : mapping) {
1672 int stat=mergeLB_processLBinterval(f.get(), inDIrs, outDir);
1673 if (stat) return stat;
1674 }
1675
1676 f->Close();
1677 f.reset(TFile::Open(inFilename.c_str(), "UPDATE"));
1678 runDir = f->GetDirectory(runDirName.c_str());
1679
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);
1689 }
1690 }
1691
1692 int stat=mergeLB_processLBinterval(f.get(), lowStatDirs, runDirName);
1693
1694 f->Close();
1695 return stat;
1696 }
1697
1698 std::map<std::string, std::vector<std::string>> MonitoringFile::buildLBToIntervalMap(TDirectory * runDir) {
1699
1700 std::map<std::string, std::vector<std::string>> ranges;
1701
1702 // No recusion here, everything we care out is run_NNNNN/lb_nnnn (and run_NNNNN/lowStat_nn-mm)
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"))
1709 continue;
1710 if (name.starts_with("lb_")) {
1711 unsigned lumiBlock = 0;
1712 try {
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;
1717 continue;
1718 }
1719 // Copied from Control/AthenaMonitoringKernel/src/HistogramFiller/OfflineHistogramProvider.h
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);
1723 } // end if lb_NNNN dir
1724 } // end loop over directories under run_NNNNN
1725 return ranges;
1726 }
1727
1728 int MonitoringFile::mergeLB_processLBinterval(TFile * file, const std::vector<std::string>& inputDirNames, const std::string& outputDirName) {
1729
1730 TDirectory* outDir = file->GetDirectory(outputDirName.c_str());
1731 if (!outDir) {
1732 outDir = file->mkdir(outputDirName.c_str());
1733 }
1734 if (!outDir) {
1735 std::cout << "ERROR, can't obtain nor create directory " << outputDirName << " in file " << file->GetName() << std::endl;
1736 return -1;
1737 }
1738
1739 histCollection hc(file, true);
1740 hc.addDirExclusion(m_mergeMatchDirRE);
1741 hc.addHistExclusion(m_mergeMatchHistoRE);
1742
1743 for (const std::string& inDirName : inputDirNames) {
1744 TDirectory* inDir = file->GetDirectory(inDirName.c_str());
1745 hc.addDirectory(inDir, outputDirName);
1746 }
1747 if (hc.size() == 0) {
1748 std::cout << "mergeLB_processLBinterval: No new objects found for " << outputDirName << std::endl;
1749 } else {
1750 hc.write();
1751 }
1752 return 0;
1753 }
1754
1755 bool MonitoringFile::CheckHistogram(TFile * f, const char* HistoName) {
1756 std::unique_ptr<TObject> obj(f->Get(HistoName));
1757 if (!obj.get()) {
1758 // std::cerr<<"No such histogram \""<< HistoName << "\"\n";
1759 return false;
1760 } else
1761 return true;
1762 }
1763
1765 return s_dbg.getLvl();
1766 }
1767 void MonitoringFile::setDebugLevel(int level) {
1768 s_dbg.setLvl((debugLevel_t)(level));
1769 }
1771 m_doTiming = true;
1772 }
1773
1774
1775 void MonitoringFile::setCheckEquality(bool value) {dqutils::s_checkEquality=value;}
1776 std::atomic<int> MonitoringFile::m_fileCompressionLevel = 1;
1777 bool MonitoringFile::m_doTiming = false;
1778 std::unordered_map<std::string, std::clock_t> MonitoringFile::m_cpuPerHistogram;
1779
1780 std::string MonitoringFile::getPath(TDirectory * dir) {
1781
1782 std::string path = dir->GetPath();
1783 if (path.find(':') != std::string::npos)
1784 path = path.substr(path.rfind(':') + 1);
1785
1786 return path;
1787 }
1788
1789} // namespace dqutils
const boost::regex re(r_e)
double length(const pvec &v)
static Double_t a
static Double_t rc
void defaultMerge(TObject *a, const TObject *b)
ClassImp(dqutils::MonitoringFile) namespace dqutils
void operator()(T1)
size_t size() const
Number of registered mappings.
void clear()
Empty the pool.
void print(char *figname, TCanvas *c1)
#define ATLAS_NOT_THREAD_SAFE
getNoisyStrip() Find noisy strips from hitmaps and write out into xml/db formats
#define ATLAS_NO_CHECK_FILE_THREAD_SAFETY
Header file for AthHistogramAlgorithm.
void fillMD(const MetaData &md)
virtual bool executeMD(TH1 *hist, const MetaData &md)
CopyHistogram(TDirectory *target, const std::string &dirName)
virtual bool execute(TH1 *hist)
GatherStatistics(const std::string &dirName)
virtual void fill(const std::string &name, const std::string &interval, const std::string &chain, const std::string &merge)
void makeBranch(const char *branchName, const char *branchstr)
static std::string getIndentation(const std::string &pathName, const std::string &leadingSpace="")
static void merge_identical(TH1 &a, const TH1 &b)
static void merge_weightedAverage(TH1 &a, const TH1 &b)
static void setDebugLevel(int level)
static bool loopOnHistogramsInMetadata(HistogramOperation &fcn, TDirectory *dir)
virtual bool copyHistograms(const std::string &outFileName, const std::string &dirName="all")
Copy the indicated set of histograms to an output file.
static void setCheckEquality(bool value)
bool setDirectoryRegEx(const std::string &re)
std::map< std::string, std::vector< std::string > > buildLBToIntervalMap(TDirectory *runDir)
virtual std::string FindCommon(const std::string &name1, const std::string &name2) const
static void merge_RMS(TH1 &a, const TH1 &b)
bool setHistogramRegEx(const std::string &re)
static bool setListFromFile(std::vector< std::string > &filelist, const std::string &listFileName)
static void merge_eventSample(TH2 &a, const TH2 &b)
static void getAllDirs(DirMap_t &dirmap, TDirectory *dir, const std::string &dirName)
int mergeLB_processLBinterval(TFile *file, const std::vector< std::string > &inputDirNames, const std::string &outputDirName)
static TKey * getObjKey(TDirectory *dir, const std::string &path)
static void merge_RMSpercentDeviation(TH1 &a, const TH1 &b)
std::optional< std::regex > m_mergeMatchDirRE
static bool dirHasHistogramsInMetadata(TDirectory *dir)
int mergeLBintervals(const std::string &inFilename)
static void fillMetaDataMap(std::map< std::string, dqutils::MonitoringFile::MetaData > &mdMap, TDirectory *dir)
static TDirectory * createDir(DirMap_t &dirmap, TDirectory *dir, const std::string &parent, const std::string &path)
static void merge_lowerLB(TH1 &a, const TH1 &b)
virtual bool setFile(const std::string &fileName)
Clears all previous data and opens the file with the given name for analysis, returning a boolean ind...
virtual void printStatistics()
static bool CheckHistogram(TFile *f, const char *HistoName)
static int getDebugLevel()
static std::string getHanResults(const std::string &hanResultsDir, const std::string &input, const std::string &hcfg, const std::string &hcfg_min10, const std::string &hcfg_min30)
int mergeFiles(const std::string &outFileName, const std::vector< std::string > &files, fileLBMap_t &lbMap, bool fillLBDirs=true)
virtual void printHanConfig()
static std::atomic< int > m_fileCompressionLevel
static std::unordered_map< std::string, std::clock_t > m_cpuPerHistogram
static void merge_weightedEff(TH1 &a, const TH1 &b)
static void merge_perBinEffPerCent(TH1 &a, const TH1 &b)
std::map< std::string, TDirectory * > DirMap_t
static void loopOnHistograms(HistogramOperation &fcn, TDirectory *dir)
virtual void clearData()
static void merge_Rebinned(TH1 &a, TH1 &b)
static std::string getPath(TDirectory *dir)
std::optional< std::regex > m_mergeMatchHistoRE
histPerDir_t(const std::string &nameIn, TObject *objIn, TTree *md, bool dbg=false)
void addDirectory(TDirectory *dir, const std::string &dirName)
void write(TFile *out)
STL class.
int lb
Definition globals.cxx:23
std::vector< std::string > files
file names and file pointers
Definition hcg.cxx:52
int count(std::string s, const std::string &regx)
count how many occurances of a regx are in a string
Definition hcg.cxx:148
std::map< std::string, std::set< std::string > > fileLBMap_t
Definition han.py:1
Definition merge.py:1
STL namespace.
DataModel_detail::iterator< DVL > remove(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end, const T &value)
Specialization of remove for DataVector/List.
void sort(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of sort for DataVector/List.
#define DEBUG
Definition page_access.h:11
MsgStream & msg
Definition testRead.cxx:32
TFile * file
std::string dirname(std::string name)
Definition utils.cxx:200