37 #include "TTreeReader.h"
42 #define CHECK(pred, msg) \
44 std::cout << msg << std::endl; \
48 #define CHECK_EQUAL(v1, v2, msg) \
49 CHECK((v1) == (v2), msg << "(" << (v1) << " vs " << (v2) << ") ")
51 #define CHECK_STR_EQUAL(s1, s2, msg) \
52 CHECK(strcmp((s1), (s2)) == 0, msg << " (" << (s1) << " vs " << (s2) << ") ")
67 bool dump_data_on_failure =
false,
68 bool skip_unsupported_branches =
false)
70 std::cout <<
"Comparing ROOT files " << file1 <<
" and " << file2
73 std::cout <<
"* Opening the files..." << std::endl;
75 if (
files.first.IsZombie()) {
76 std::cout <<
" - Could not open file " << file1 <<
"!" << std::endl;
78 }
else if (
files.second.IsZombie()) {
79 std::cout <<
" - Could not open file " << file2 <<
"!" << std::endl;
83 std::cout <<
"* Extracting file keys..." << std::endl;
87 const auto loadKeys = [](
const TFile&
file, std::vector<TKey*>&
target) {
88 const int keyCount = file.GetNkeys();
90 TIter keyIter{file.GetListOfKeys()};
91 for (
int i = 0;
i < keyCount; ++
i) {
92 target.emplace_back(dynamic_cast<TKey*>(keyIter()));
97 loadKeys(
files.first, fileKeys.first);
98 loadKeys(
files.second, fileKeys.second);
101 std::cout <<
"* Selecting the latest key cycle..." << std::endl;
102 std::vector<HomogeneousPair<TKey*>> keyPairs;
106 using KeyMetadata = std::pair<short, TKey*>;
107 using FileMetadata = std::map<std::string, KeyMetadata>;
111 const auto findLatestCycle
112 = [](
const std::vector<TKey*>& keys, FileMetadata&
target) {
114 for (
const auto key : keys) {
117 const short newCycle{key->GetCycle()};
120 auto latestCycleIter =
target.find(keyName);
121 if (latestCycleIter !=
target.end()) {
123 auto& latestCycleMetadata = latestCycleIter->second;
124 if (newCycle > latestCycleMetadata.first) {
125 latestCycleMetadata = {newCycle, key};
130 target.emplace(keyName, KeyMetadata{newCycle, key});
136 std::cout <<
" - Finding the latest cycle for each file..." << std::endl;
137 findLatestCycle(fileKeys.first, metadata.first);
138 findLatestCycle(fileKeys.second, metadata.second);
142 std::cout <<
" - Grouping per-file latest keys..." << std::endl;
146 const auto f1KeyCount = metadata.first.size();
147 const auto f2KeyCount = metadata.second.size();
149 f1KeyCount, f2KeyCount,
" o Number of keys does not match");
150 keyPairs.reserve(f1KeyCount);
153 for (
auto f1MetadataIter = metadata.first.cbegin(),
154 f2MetadataIter = metadata.second.cbegin();
155 f1MetadataIter != metadata.first.cend();
156 ++f1MetadataIter, ++f2MetadataIter) {
158 const auto& f1KeyName = f1MetadataIter->first;
159 const auto& f2KeyName = f2MetadataIter->first;
160 CHECK_EQUAL(f1KeyName, f2KeyName,
" o Key names do not match");
163 keyPairs.emplace_back(f1MetadataIter->second.second,
164 f2MetadataIter->second.second);
169 std::cout <<
"* Comparing key metadata..." << std::endl;
170 for (
const auto& keyPair : keyPairs) {
171 const auto& key1 = keyPair.first;
172 const auto& key2 = keyPair.second;
175 key2->GetClassName(),
176 " - Class name does not match!");
178 key1->GetTitle(), key2->GetTitle(),
" - Title does not match!");
181 " - Key version does not match!");
186 std::cout <<
"* Extracting TTrees..." << std::endl;
187 std::vector<HomogeneousPair<TTree*>> treePairs;
188 for (
const auto& keyPair : keyPairs) {
189 TObject* obj1 = keyPair.first->ReadObj();
190 TObject* obj2 = keyPair.second->ReadObj();
194 " - Object type does not match!");
196 obj1->ClassName(),
"TTree",
" - Non-TTree input is not supported!");
198 treePairs.emplace_back(dynamic_cast<TTree*>(obj1),
199 dynamic_cast<TTree*>(obj2));
202 std::cout <<
"* Comparing the trees..." << std::endl;
203 for (
const auto& treePair : treePairs) {
204 const auto& tree1 = treePair.first;
205 const auto& tree2 = treePair.second;
207 std::cout <<
" - Comparing tree " << tree1->GetName() <<
"..."
210 std::cout <<
" o Comparing tree-wide metadata..." << std::endl;
211 const std::size_t t1EntryCount = tree1->GetEntries();
213 const std::size_t t2EntryCount = tree2->GetEntries();
216 " ~ Number of entries does not match!");
219 if (t1EntryCount == 0) {
220 std::cout <<
" o Skipping empty tree!" << std::endl;
224 std::cout <<
" o Preparing for tree readout..." << std::endl;
225 TTreeReader t1Reader(tree1);
226 TTreeReader t2Reader(tree2);
228 t1Reader, t2Reader, t1EntryCount};
230 std::cout <<
" o Comparing branch metadata..." << std::endl;
231 std::vector<HomogeneousPair<TBranch*>> branchPairs;
234 const int t1BranchCount = tree1->GetNbranches();
235 const int t2BranchCount = tree2->GetNbranches();
238 " ~ Number of branches does not match!");
239 branchPairs.reserve(t1BranchCount);
242 TIter t1BranchIter{tree1->GetListOfBranches()};
243 TIter t2BranchIter{tree2->GetListOfBranches()};
244 for (
int i = 0;
i < t1BranchCount; ++
i) {
245 branchPairs.emplace_back(dynamic_cast<TBranch*>(t1BranchIter()),
246 dynamic_cast<TBranch*>(t2BranchIter()));
250 std::cout <<
" o Setting up branch-specific processing..." << std::endl;
251 std::vector<BranchComparisonHarness> branchComparisonHarnesses;
252 branchComparisonHarnesses.reserve(branchPairs.size());
253 for (
const auto& branchPair : branchPairs) {
254 const auto& branch1 = branchPair.first;
255 const auto& branch2 = branchPair.second;
257 std::cout <<
" ~ Checking branch metadata..." << std::endl;
259 EDataType b1DataType;
262 EDataType b2DataType;
265 b1ClassName = branch1->GetClassName();
266 b2ClassName = branch2->GetClassName();
268 b1ClassName, b2ClassName,
" + Class name does not match!");
269 branch1->GetExpectedType(unused, b1DataType);
270 branch2->GetExpectedType(unused, b2DataType);
272 b1DataType, b2DataType,
" + Raw data type does not match!");
273 const int b1LeafCount = branch1->GetNleaves();
274 const int b2LeafCount = branch2->GetNleaves();
277 " + Number of leaves does not match!");
281 " + Branches with several leaves are not supported!");
282 b1BranchName = branch1->GetName();
283 b2BranchName = branch2->GetName();
286 " + Branch name does not match!");
289 std::cout <<
" ~ Building comparison harness for branch "
290 << b1BranchName <<
"..." << std::endl;
293 treeMetadata, b1BranchName, b1DataType, b1ClassName);
294 branchComparisonHarnesses.emplace_back(
std::move(branchHarness));
298 std::cout <<
" + Unsupported branch type! "
299 <<
"(eDataType: " << b1DataType <<
", ClassName: \""
300 << b1ClassName <<
"\")" << std::endl;
301 if (skip_unsupported_branches) {
309 std::cout <<
" o Reading event data..." << std::endl;
310 for (std::size_t
i = 0;
i < t1EntryCount; ++
i) {
316 for (
auto& branchHarness : branchComparisonHarnesses) {
317 branchHarness.loadCurrentEvent();
321 std::cout <<
" o Sorting the first tree..." << std::endl;
323 std::cout <<
" ~ Defining event comparison operator..." << std::endl;
325 = [&branchComparisonHarnesses](std::size_t
i,
327 for (
auto& branchHarness : branchComparisonHarnesses) {
328 const auto order = branchHarness.sortHarness.first.first(i,
j);
329 if (order != Ordering::EQUAL) {
return order; }
331 return Ordering::EQUAL;
334 std::cout <<
" ~ Defining event swapping operator..." << std::endl;
336 = [&branchComparisonHarnesses](std::size_t
i, std::size_t
j) {
337 for (
auto& branchHarness : branchComparisonHarnesses) {
338 branchHarness.sortHarness.first.second(i,
j);
342 std::cout <<
" ~ Running quicksort on the tree..." << std::endl;
343 quickSort(0, t1EntryCount - 1, t1CompareEvents, t1SwapEvents);
346 std::cout <<
" o Sorting the second tree..." << std::endl;
348 std::cout <<
" ~ Defining event comparison operator..." << std::endl;
350 = [&branchComparisonHarnesses](std::size_t
i,
352 for (
auto& branchHarness : branchComparisonHarnesses) {
353 const auto order = branchHarness.sortHarness.second.first(i,
j);
354 if (order != Ordering::EQUAL) {
return order; }
356 return Ordering::EQUAL;
359 std::cout <<
" ~ Defining event swapping operator..." << std::endl;
361 = [&branchComparisonHarnesses](std::size_t
i, std::size_t
j) {
362 for (
auto& branchHarness : branchComparisonHarnesses) {
363 branchHarness.sortHarness.second.second(i,
j);
367 std::cout <<
" ~ Running quicksort on the tree..." << std::endl;
368 quickSort(0, t1EntryCount - 1, t2CompareEvents, t2SwapEvents);
371 std::cout <<
" o Checking that both trees are now equal..." << std::endl;
372 for (
auto& branchHarness : branchComparisonHarnesses) {
373 std::cout <<
" ~ Comparing branch " << branchHarness.branchName
374 <<
"..." << std::endl;
375 if (!branchHarness.eventDataEqual()) {
376 std::cout <<
" + Branch contents do not match!" << std::endl;
377 if (dump_data_on_failure) {
378 std::cout <<
" + Dumping branch contents:" << std::endl;
379 branchHarness.dumpEventData();
386 std::cout <<
"* Input files are equal, event order aside!" << std::endl;