Merge trees, MakeFriends and create a new branch in one go!

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,

Cheers
Muhammad

Hi,
before I try to answer, I think I am missing a couple of elements:

  1. why don’t you want to use hadd?
  2. 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

Hi Enrico,

  1. 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
  2. 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).

Anyway, glad you managed!
Cheers,
Enrico

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");   

note that branch Jet1_pt exists in a friend tree

Cheers

I see, good to know!

Cheers,
Enrico

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.