This example shows processing of a TTree-based dataset with horizontal concatenations (friends) and event matching (based on TTreeIndex). In case the current event being processed does not match one (or more) of the friend datasets, one can use the FilterAvailable and DefaultValueFor functionalities to act upon the situation.
#include <iostream>
#include <numeric>
struct Dataset {
constexpr static auto fMainFile{"df037_TTreeEventMatching_C_main.root"};
constexpr static auto fAuxFile1{"df037_TTreeEventMatching_C_aux_1.root"};
constexpr static auto fAuxFile2{"df037_TTreeEventMatching_C_aux_2.root"};
constexpr static auto fMainTreeName{"events"};
constexpr static auto fAuxTreeName1{"auxdata_1"};
constexpr static auto fAuxTreeName2{"auxdata_2"};
Dataset()
{
{
TFile
f(fMainFile,
"RECREATE");
TTree mainTree(fMainTreeName, fMainTreeName);
int idx;
mainTree.Branch("idx", &idx, "idx/I");
mainTree.Branch(
"x", &
x,
"x/I");
idx = 1;
mainTree.Fill();
idx = 2;
mainTree.Fill();
idx = 3;
mainTree.Fill();
mainTree.Write();
}
{
TFile
f(fAuxFile1,
"RECREATE");
TTree auxTree(fAuxTreeName1, fAuxTreeName1);
int idx;
auxTree.Branch("idx", &idx, "idx/I");
auxTree.Branch(
"y", &
y,
"y/I");
idx = 1;
auxTree.Fill();
idx = 2;
auxTree.Fill();
auxTree.Write();
}
{
TFile
f(fAuxFile2,
"RECREATE");
TTree auxTree(fAuxTreeName2, fAuxTreeName2);
int z;
int idx;
auxTree.Branch("idx", &idx, "idx/I");
auxTree.Branch("z", &z, "z/I");
idx = 1;
z = 6;
auxTree.Fill();
idx = 3;
z = 7;
auxTree.Fill();
auxTree.Write();
}
}
~Dataset()
{
std::remove(fMainFile);
std::remove(fAuxFile1);
std::remove(fAuxFile2);
}
};
void df037_TTreeEventMatching()
{
Dataset dataset{};
TChain mainChain{dataset.fMainTreeName};
mainChain.
Add(dataset.fMainFile);
TChain auxChain1(dataset.fAuxTreeName1);
auxChain1.Add(dataset.fAuxFile1);
auxChain1.BuildIndex("idx");
TChain auxChain2(dataset.fAuxTreeName2);
auxChain2.Add(dataset.fAuxFile2);
auxChain2.BuildIndex("idx");
const std::string auxTree1ColIdx = std::string(dataset.fAuxTreeName1) + ".idx";
const std::string auxTree1ColY = std::string(dataset.fAuxTreeName1) + ".y";
const std::string auxTree2ColIdx = std::string(dataset.fAuxTreeName2) + ".idx";
const std::string auxTree2ColZ = std::string(dataset.fAuxTreeName2) + ".z";
constexpr static auto defaultValue = std::numeric_limits<int>::min();
auto display1 = df.DefaultValueFor(auxTree1ColIdx, defaultValue)
.DefaultValueFor(auxTree1ColY, defaultValue)
.DefaultValueFor(auxTree2ColIdx, defaultValue)
.DefaultValueFor(auxTree2ColZ, defaultValue)
{"idx", auxTree1ColIdx, auxTree2ColIdx, "x", auxTree1ColY, auxTree2ColZ});
auto display2 = df.DefaultValueFor(auxTree2ColIdx, defaultValue)
.DefaultValueFor(auxTree2ColZ, defaultValue)
.FilterAvailable(auxTree1ColY)
{"idx", auxTree1ColIdx, auxTree2ColIdx, "x", auxTree1ColY, auxTree2ColZ});
std::cout << "Example 1: provide default values for all columns\n";
display1->Print();
std::cout << "Example 2: skip the entry only when the first auxiliary tree does not match\n";
display2->Print();
std::cout << "Example 3: keep entries from the main tree for which there is no match in the auxiliary tree\n";
display3->Print();
}
ROOT's RDataFrame offers a modern, high-level interface for analysis of data stored in TTree ,...
A chain is a collection of files containing TTree objects.
TFriendElement * AddFriend(const char *chainname, const char *dummy="") override
Add a TFriendElement to the list of friends of this chain.
virtual Int_t Add(TChain *chain)
Add all files referenced by the passed chain to this chain.
Example 1: provide default values for all columns
+-----+-----+---------------+---------------+---+-------------+-------------+
| Row | idx | auxdata_1.idx | auxdata_2.idx | x | auxdata_1.y | auxdata_2.z |
+-----+-----+---------------+---------------+---+-------------+-------------+
| 0 | 1 | 1 | 1 | 1 | 4 | 6 |
+-----+-----+---------------+---------------+---+-------------+-------------+
| 1 | 2 | 2 | -2147483648 | 2 | 5 | -2147483648 |
+-----+-----+---------------+---------------+---+-------------+-------------+
| 2 | 3 | -2147483648 | 3 | 3 | -2147483648 | 7 |
+-----+-----+---------------+---------------+---+-------------+-------------+
Example 2: skip the entry only when the first auxiliary tree does not match
+-----+-----+---------------+---------------+---+-------------+-------------+
| Row | idx | auxdata_1.idx | auxdata_2.idx | x | auxdata_1.y | auxdata_2.z |
+-----+-----+---------------+---------------+---+-------------+-------------+
| 0 | 1 | 1 | 1 | 1 | 4 | 6 |
+-----+-----+---------------+---------------+---+-------------+-------------+
| 1 | 2 | 2 | -2147483648 | 2 | 5 | -2147483648 |
+-----+-----+---------------+---------------+---+-------------+-------------+
Example 3: keep entries from the main tree for which there is no match in the auxiliary tree
+-----+-----+---+
| Row | idx | x |
+-----+-----+---+
| 2 | 3 | 3 |
+-----+-----+---+