ATLAS Offline Software
Loading...
Searching...
No Matches
MonitoringFile.cxx File Reference
#include "DataQualityUtils/MonitoringFile.h"
#include <TDirectory.h>
#include <TEfficiency.h>
#include <TFile.h>
#include <TGraph.h>
#include <TH1.h>
#include <TH2.h>
#include <TIterator.h>
#include <TKey.h>
#include <TObject.h>
#include <TROOT.h>
#include <TSystem.h>
#include <TTree.h>
#include <cmath>
#include <cstdio>
#include <ctime>
#include <exception>
#include <filesystem>
#include <format>
#include <fstream>
#include <iostream>
#include <map>
#include <memory>
#include <set>
#include <sstream>
#include <vector>
#include "DataQualityInterfaces/HanApp.h"
#include "DataQualityInterfaces/HanUtils.h"
#include "TTreeReader.h"
#include "TTreeReaderArray.h"

Go to the source code of this file.

Functions

 ClassImp (dqutils::MonitoringFile) namespace dqutils

Variables

 ATLAS_NO_CHECK_FILE_THREAD_SAFETY

Function Documentation

◆ ClassImp()

Definition at line 41 of file MonitoringFile.cxx.

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

Variable Documentation

◆ ATLAS_NO_CHECK_FILE_THREAD_SAFETY

ATLAS_NO_CHECK_FILE_THREAD_SAFETY

Definition at line 39 of file MonitoringFile.cxx.