forked from AliceO2Group/AliceO2
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMergerAlgorithm.cxx
More file actions
145 lines (130 loc) · 5.41 KB
/
MergerAlgorithm.cxx
File metadata and controls
145 lines (130 loc) · 5.41 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
// All rights not expressly granted are reserved.
//
// This software is distributed under the terms of the GNU General Public
// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
//
// In applying this license CERN does not waive the privileges and immunities
// granted to it by virtue of its status as an Intergovernmental Organization
// or submit itself to any jurisdiction.
/// \file MergerAlgorithm.cxx
/// \brief Implementation of O2 Mergers, v0.1
///
/// \author Piotr Konopka, piotr.jan.konopka@cern.ch
#include "Mergers/MergerAlgorithm.h"
#include "Mergers/MergeInterface.h"
#include "Framework/Logger.h"
#include <TH1.h>
#include <TH2.h>
#include <TH3.h>
#include <THn.h>
#include <TTree.h>
#include <THnSparse.h>
#include <TObjArray.h>
#include <TGraph.h>
#include <TEfficiency.h>
namespace o2::mergers::algorithm
{
size_t estimateTreeSize(TTree* tree)
{
size_t totalSize = 0;
auto branchList = tree->GetListOfBranches();
for (const auto* branch : *branchList) {
totalSize += dynamic_cast<const TBranch*>(branch)->GetTotalSize();
}
return totalSize;
}
void merge(TObject* const target, TObject* const other)
{
if (target == nullptr) {
throw std::runtime_error("Merging target is nullptr");
}
if (other == nullptr) {
throw std::runtime_error("Object to be merged in is nullptr");
}
if (other == target) {
throw std::runtime_error("Merging target and the other object point to the same address");
}
// fixme: should we check if names match?
// We expect that both objects follow the same structure, but we allow to add missing objects to TCollections.
// First we check if an object contains a MergeInterface, as it should overlap default Merge() methods of TObject.
if (auto custom = dynamic_cast<MergeInterface*>(target)) {
custom->merge(dynamic_cast<MergeInterface* const>(other));
} else if (auto targetCollection = dynamic_cast<TCollection*>(target)) {
auto otherCollection = dynamic_cast<TCollection*>(other);
if (otherCollection == nullptr) {
throw std::runtime_error(std::string("The target object '") + target->GetName() +
"' is a TCollection, while the other object '" + other->GetName() + "' is not.");
}
auto otherIterator = otherCollection->MakeIterator();
while (auto otherObject = otherIterator->Next()) {
TObject* targetObject = targetCollection->FindObject(otherObject->GetName());
if (targetObject) {
// That might be another collection or a concrete object to be merged, we walk on the collection recursively.
merge(targetObject, otherObject);
} else {
// We prefer to clone instead of passing the pointer in order to simplify deleting the `other`.
targetCollection->Add(otherObject->Clone());
}
}
delete otherIterator;
} else {
Long64_t errorCode = 0;
TObjArray otherCollection;
otherCollection.SetOwner(false);
otherCollection.Add(other);
if (target->InheritsFrom(TH1::Class())) {
// this includes TH1, TH2, TH3
auto targetTH1 = reinterpret_cast<TH1*>(target);
if (targetTH1->TestBit(TH1::kIsAverage)) {
// Merge() does not support averages, we have to use Add()
// this will break if collection.size != 1
if (auto otherTH1 = dynamic_cast<TH1*>(otherCollection.First())) {
errorCode = targetTH1->Add(otherTH1);
}
} else {
// Add() does not support histograms with labels, thus we resort to Merge() by default
errorCode = targetTH1->Merge(&otherCollection);
}
} else if (target->InheritsFrom(THnBase::Class())) {
// this includes THn and THnSparse
errorCode = reinterpret_cast<THnBase*>(target)->Merge(&otherCollection);
} else if (target->InheritsFrom(TTree::Class())) {
auto targetTree = reinterpret_cast<TTree*>(target);
auto otherTree = reinterpret_cast<TTree*>(other);
auto targetTreeSize = estimateTreeSize(targetTree);
auto otherTreeSize = estimateTreeSize(otherTree);
if (auto totalSize = targetTreeSize + otherTreeSize; totalSize > 100000000) {
LOG(warn) << "The tree '" << targetTree->GetName() << "' would be larger than 100MB (" << totalSize << "B) after merging, skipping to let the system survive";
errorCode = 0;
} else {
errorCode = targetTree->Merge(&otherCollection);
}
} else if (target->InheritsFrom(TGraph::Class())) {
errorCode = reinterpret_cast<TGraph*>(target)->Merge(&otherCollection);
} else if (target->InheritsFrom(TEfficiency::Class())) {
errorCode = reinterpret_cast<TEfficiency*>(target)->Merge(&otherCollection);
} else {
LOG(warn) << "Object '" + std::string(target->GetName()) + "' with type '" + std::string(target->ClassName()) + "' is not one of the mergeable types, skipping";
}
if (errorCode == -1) {
LOG(error) << "Merging object '" + std::string(target->GetName()) + "' of type '" + std::string(target->ClassName()) + "' failed.";
}
}
}
void deleteTCollections(TObject* obj)
{
if (auto c = dynamic_cast<TCollection*>(obj)) {
c->SetOwner(false);
auto iter = c->MakeIterator();
while (auto element = iter->Next()) {
deleteTCollections(element);
}
delete iter;
delete c;
} else {
delete obj;
}
}
} // namespace o2::mergers::algorithm