57 auto collectFromTPad = [](TPad* pad, std::vector<TObject*>&
objects,
const auto& collectFromTPad) {
61 auto* primitives = pad->GetListOfPrimitives();
62 for (
int i = 0;
i < primitives->GetSize(); ++
i) {
63 auto* primitive = primitives->At(
i);
64 if (
auto* primitivePad =
dynamic_cast<TPad*
>(primitive)) {
65 collectFromTPad(primitivePad,
objects, collectFromTPad);
72 std::vector<TObject*> collectedObjects;
73 collectFromTPad(canvas, collectedObjects, collectFromTPad);
75 return collectedObjects;
85auto matchCollectedToPairs(
const std::vector<TObject*>& targetObjects,
const std::vector<TObject*> otherObjects) -> std::vector<MatchedCollectedObjects>
87 std::vector<MatchedCollectedObjects> matchedObjects;
88 matchedObjects.reserve(std::max(targetObjects.size(), otherObjects.size()));
89 for (
const auto& targetObject : targetObjects) {
90 if (
const auto found_it = std::ranges::find_if(otherObjects, [&targetObject](
TObject* obj) {
return std::string_view(targetObject->GetName()) == std::string_view(obj->GetName()); });
91 found_it != otherObjects.end()) {
92 matchedObjects.emplace_back(targetObject, *found_it);
95 return matchedObjects;
101 throw std::runtime_error(
"Merging target is nullptr");
103 if (
other ==
nullptr) {
104 throw std::runtime_error(
"Object to be merged in is nullptr");
107 throw std::runtime_error(
"Merging target and the other object point to the same address");
117 }
else if (
auto targetCollection =
dynamic_cast<TCollection*
>(
target)) {
119 auto otherCollection =
dynamic_cast<TCollection*
>(
other);
120 if (otherCollection ==
nullptr) {
121 throw std::runtime_error(std::string(
"The target object '") +
target->GetName() +
122 "' is a TCollection, while the other object '" +
other->GetName() +
"' is not.");
125 auto otherIterator = otherCollection->MakeIterator();
126 while (
auto otherObject = otherIterator->Next()) {
127 TObject* targetObject = targetCollection->FindObject(otherObject->GetName());
130 merge(targetObject, otherObject);
133 targetCollection->Add(otherObject->Clone());
136 delete otherIterator;
137 }
else if (
auto targetCanvas =
dynamic_cast<TCanvas*
>(
target)) {
139 auto otherCanvas =
dynamic_cast<TCanvas*
>(
other);
140 if (otherCanvas ==
nullptr) {
141 throw std::runtime_error(std::string(
"The target object '") +
target->GetName() +
142 "' is a TCanvas, while the other object '" +
other->GetName() +
"' is not.");
147 if (targetObjects.size() != otherObjects.size()) {
148 throw std::runtime_error(std::string(
"Trying to merge canvas: ") + targetCanvas->GetName() +
" and canvas " + otherObjects.size() +
"but contents are not the same");
152 if (targetObjects.size() != matched.size()) {
153 throw std::runtime_error(std::string(
"Trying to merge canvas: ") + targetCanvas->GetName() +
" and canvas " + otherObjects.size() +
"but contents are not the same");
156 for (
const auto& [targetObject, otherObject] : matched) {
157 merge(targetObject, otherObject);
161 Long64_t errorCode = 0;
162 TObjArray otherCollection;
163 otherCollection.SetOwner(
false);
164 otherCollection.Add(
other);
166 if (
target->InheritsFrom(TH1::Class())) {
168 auto targetTH1 =
reinterpret_cast<TH1*
>(
target);
169 if (targetTH1->TestBit(TH1::kIsAverage)) {
172 if (
auto otherTH1 =
dynamic_cast<TH1*
>(otherCollection.First())) {
173 errorCode = targetTH1->Add(otherTH1);
177 errorCode = targetTH1->Merge(&otherCollection);
179 }
else if (
target->InheritsFrom(THnBase::Class())) {
181 errorCode =
reinterpret_cast<THnBase*
>(
target)->Merge(&otherCollection);
182 }
else if (
target->InheritsFrom(TTree::Class())) {
183 auto targetTree =
reinterpret_cast<TTree*
>(
target);
184 auto otherTree =
reinterpret_cast<TTree*
>(
other);
187 if (
auto totalSize = targetTreeSize + otherTreeSize; totalSize > 100000000) {
188 LOG(warn) <<
"The tree '" << targetTree->GetName() <<
"' would be larger than 100MB (" << totalSize <<
"B) after merging, skipping to let the system survive";
191 errorCode = targetTree->Merge(&otherCollection);
193 }
else if (
target->InheritsFrom(TGraph::Class())) {
194 errorCode =
reinterpret_cast<TGraph*
>(
target)->Merge(&otherCollection);
195 }
else if (
target->InheritsFrom(TEfficiency::Class())) {
196 errorCode =
reinterpret_cast<TEfficiency*
>(
target)->Merge(&otherCollection);
198 LOG(warn) <<
"Object '" + std::string(
target->GetName()) +
"' with type '" + std::string(
target->ClassName()) +
"' is not one of the mergeable types, skipping";
200 if (errorCode == -1) {
201 LOG(error) <<
"Failed to merge the input object '" + std::string(
other->GetName()) +
"' of type '" + std::string(
other->ClassName())
202 +
" and the target object '" + std::string(
target->GetName()) +
"' of type '" + std::string(
target->ClassName()) +
"'";