I have a number of input root files, each contain two trees with exactly the same number of events.
I would like to merge all root files in one root file, but I do not want to use hadd !
I also want to create a new branch and fill it and make the two trees friends in the output file
auto MCfile = new TFile(MCRootFileName.c_str(), "recreate");
vector<TTree*> NewTree;
for (auto &it : DSID) {
NewTree.push_back(new TTree(it.first.c_str(), ""));
}
for (auto it : NewTree) {
auto &ListRootFiles = FullMCSampleName[string(it->GetName())];
Create_template(it, ListRootFiles, MCfile);
cout << " N " << it->GetEntries() << endl;
//MCfile->cd();
///it->Write();
}
void Create_template(TTree* out_tree, vector<string> &Files,TFile *MCfile) {
TList *list1 = new TList();
TList *list2 = new TList();
MCfile->cd();
TTree *t1 = new TTree("T1", "");
TTree *t2 = new TTree("T", "");
for (auto &f_name : Files) {
auto input_file = new TFile(f_name.c_str());
auto input_tree1 = dynamic_cast<TTree*> (input_file->Get("nominal"));
auto input_tree2 = dynamic_cast<TTree*> (input_file->Get("SystematicWeights"));
list1->Add(input_tree1);
list2->Add(input_tree2);
}
MCfile->cd();
t1 = TTree::MergeTrees(list1);
t2 = TTree::MergeTrees(list2);
float x;
out_tree->Branch("x", &x, "x/F");
t1->AddFriend(t2);
out_tree = (TTree*) t1->CloneTree(0);
for (int iEvent = 0;; ++iEvent) {
Long64_t ientry = t1->LoadTree(iEvent);
if (ientry < 0) {
break;
}
x = 10;
t1->GetEntry(iEvent);
out_tree->Fill();
}
MCfile->cd();
//out_tree->SetName(out_tree->GetName());
out_tree->Write();
cout << out_tree->GetEntries() << endl;
}
The second tree information and the new bracnch are not stored
I tried to work around the problem , but but partially I succeed!
I would be glad if you can help me to solve the problem,
Hi,
before I try to answer, I think I am missing a couple of elements:
why don’t you want to use hadd?
what do you mean exactly with “[I wanto to] make the two trees friends in the output file”? (files do not encode that kind of information as far as I know, users make trees friends of each other in their application)
Note that when you set out_tree = t1->CloneTree(0) you are setting the out_tree variable to point to a completely new TTree (the one returned by CloneTree) so your Branch and AddFriend calls are effectively ignored.
Unrelated, but dynamic cast is an overkill in Create_template, static_cast would be enough.
Finally, if you have access to ROOT v6.12, TDataFrame offers an high-level interface to solve this kind of problems. For one tree, merging of trees in multiple files, adding one more branch "x" and writing everything to a new root file is done like this (modulo typos):
#include <ROOT/TDataFrame.hxx>
using namespace ROOT::Experimental; // TDataFrame lives in here
int main() {
TDataFrame d("nominal", Files); // Files is a vector<string> of filenames
// create (define) a new branch that always takes the value 10, like in your snippet
auto dwithx = d.Define("x", "10");
// write (snapshot) everything to a new file (all branches in the input files plus all new branches)
dwithx.Snapshot("newtree", "newfile.root");
return 0;
}
// also possible as a one-liner:
// d.Define("x", "10").Snapshot("newtree", "newfile.root");
Cheers,
Enrico
in principle I can use hadd, but the code is very complicated and I need to process the input trees: modify, add, delete branchs before I merge them
each file contains 2 trees, and those are not saved as friends, however, the I would like to make the new trees friends such that I can access their branchs easily. According to root reference guide it is possible (see AddFriend) https://root.cern.ch/root/html518/TTree.html#TTree:MergeTrees
Anyway, I was able to solve the problem and store the friendship information. Here is the prototype of the code
void Create_template(string treename, const vector<string> &Files, TFile *MCfile) {
TList *list1 = new TList();
TList *list2 = new TList();
MCfile->cd();
TTree *t1 = new TTree("T1", "");
TTree *t2 = new TTree("T2", "");
string nominal = ("nominal_" + treename).c_str();
string systematic = ("systematic_" + treename).c_str();
string NN_tree = ("NN_" + treename).c_str();
for (auto &f_name : Files) {
auto input_file = new TFile(f_name.c_str());
auto input_tree1 = dynamic_cast<TTree*> (input_file->Get("nominal"));
auto input_tree2 = dynamic_cast<TTree*> (input_file->Get("SystematicWeights"));
//input_tree1->AddFriend(input_tree2);
list1->Add(input_tree1);
list2->Add(input_tree2);
}
MCfile->cd();
t1 = TTree::MergeTrees(list1);
t2 = TTree::MergeTrees(list2);
float NN;
auto out_tree = new TTree(NN_tree.c_str(), "");
out_tree->Branch("NN", &NN, "NN/F");
for (int iEvent = 0;; ++iEvent) {
Long64_t ientry = t1->LoadTree(iEvent);
if (ientry < 0) {
break;
}
t1->GetEntry(iEvent);
NN = 10.
out_tree->Fill();
}
MCfile->cd();
t1->SetName(nominal.c_str());
t2->SetName(systematic.c_str());
t1->Write();
t2->Write();
out_tree->AddFriend(t1);
out_tree->AddFriend(t2);
out_tree->Write(NN_tree.c_str());
}
Hi mhoroub,
note that the documentation that you linked is for ROOT v5.18 (!!). Up-to-date documentation for ROOT versions that are currently supported is accessible e.g. from here.
As far as I know, if a TTree is friend of another TTree then it can access its branches, and calling GetEntry on the first tree will also get the entry for the friend tree. I am not aware of any extra information that is written to file in case two trees that are friends are written to file. Each should be written as a separate tree (but I might be wrong here, feel free to point out if there is extra information that is stored to file for friend trees).
Hi Enrico,
I am aware of the new root versions (I am using 6.12/06).
the friendship information is stored in the file. Here is the test code
auto f = new TFile("OutPut/nominal_trilepton.root");
auto t = (TTree*) f->Get("NN_ttWZH");
TList* l = t->GetListOfFriends();
cout<<l->At(0)->GetName()<<endl;;
t->Draw("Jet1_pt");