Adding a branch to an existing TTree

Hello,

I have a problem when I try to add a branch to an existing TTree. Basically the branch is well added and filled, but the rest of the branches (that already exist previously in the TTree) are settled to zero.
These other branches are not treated/defined at my code (only the branch that I need as a key to include the new data), and I would prefer not to define it, as this is information is quite heavy, and it may be different from one file to another, but I want this to be copied in the new file.

Thank you in advance for your help and best regards,
J.

This is a simplified version of my code:

TFile *fin=TFile::Open("file1.root","READ"); //raw data to be updated with the information from the other file.
TTree *t; fin->GetObject("my_tree",t);

//actual branches at the ttree:
int _time_stamp;

TBranch * _b_time_stamp;  t->SetBranchAddress("TimeStamp"   , &_time_stamp   , &_b_time_stamp  );
//new branch:
float _grid;
TBranch * _b_grid 	 = t ->Branch("grid"		, &_grid	, "grid/F");

//actual branches at the ntuple:
TChain * t2 = new TChain("my_tree2");
t2->Add("file2.root"); //variables.C file
float _grid_2;
int _time_stamp_2;
TBranch * _b2_time_stamp;	t2->SetBranchAddress("time"		, &_time_stamp_2	, &_b2_time_stamp	);
TBranch * _b2_grid;		t2->SetBranchAddress("grid"		, &_grid_2		, &_b2_grid		);

for(int ev=0; ev < t->GetEntries() ; ++ev) {
	t->GetEntry(ev);

	var=set_var(_time_stamp,t2);

	t2->GetEntry(var);

	_grid=_grid_2;
	_b_grid->Fill();

} // End event loop

TFile fout("exit_file.root","UPDATE");
t->Write();
fout.Close();
1 Like

Hi jasot,
if you have access to ROOT v6.10, there is a much simpler way to add a new branch to a tree using TDataFrame:

#include "ROOT/TDataFrame.hxx"
using namespace ROOT::Experimental;

int main() {
  TDataFrame d("my_tree", "file1.root");
  d.Define("newvar", []() { return 42; }) // define a new branch that always contains 42 using a c++ lambda
   .Snapshot("my_tree", "newfile.root"); // save all branches to a new file (also `newvar`)
  return 0;
}

With that said, I don’t understand what your code is supposed to do exactly: do you want to add the _grid branch from the tree in file2.root to the tree in file1.root? Generally speaking you would be better off reading file1 and file2 and writing all the variables you need to another separate file file3.

Hi Enrico,
I’ll try to explain better. My code is supposed to add the grid branch (and some others), from the tree in file2, to the tree in file1. Then I save it in a new file “exit_file.root”.
The thing is that I need to add new branches but using one of the branches of each tree, as a “primary key” variable (not exactly, but close to a left join in MySQL).
So when I define the new branch in my_tree, I need to look for in my_tree2 which entry is the one that I want (this is the function set_var in my code, which returns the entry number in my_tree2 that correspond to the actual entry in my_tree).

I’m trying this code you suggest, but I don’t know how to use this statement, as I need to go entry by entry to assign the corresponding value in the new branch… Can I do d->GetEntry(var) inside this d.Define statement?

Thanks for your quick reply!

J.

I see. With TDataFrame this would look like the following:

#include "ROOT/TDataFrame.hxx"
#include <iostream>
using namespace ROOT::Experimental;

// take a variable of file1, return desired entry of file2
Long64_t someFunctionOf(double var);

int main() {
   // setup variable `grid2` for reading from `my_tree2`
   TFile file2("file2.root");
   TTree *t2 = nullptr;
   file2.GetObject("my_tree2", t2);
   float grid2;
   t2->SetBranchAddress("grid", &grid2);

   // define a lambda that will use a variable of file1 to set the entry of my_tree2, and return the value of "grid"
   auto evalGrid = [t2, &grid2](double var) {
     t2->GetEntry(someFunctionOf(var));
     return grid2;
   };

   // use TDataFrame to read `my_tree`, add a "grid" column to it (defined by the `grid` lambda) and write it to file
   TDataFrame d("my_tree", "file1.root");
   d.Define("grid", evalGrid).Snapshot("my_tree", "newfile.root");
   return 0;
}

With TTree itself I am sure it will work if you create a completely new TTree in a new file and create branches on it with TTree::Branch and associate them to the correct variables of your first and second input trees. I honestly do not know whether what you are doing now (“updating” an existing tree while you are reading it from a file, and then writing it to a different file) is supported – @pcanal or @Axel might now but they are on vacation right now :slight_smile:

Hi Enrico,
When you say that with TTree will work… this is what I do in my example right? But I do not know “a priori” all the branches I will have in the first file, this is the problem.

This is a different question, but I’m not able to try your example, as I don’t know how to set up root 6.10 in Lxplus… I don’t see a version for SLC6 in d-cache…

Thanks for your help!

Well you are not following exactly the procedure I was talking about in my last message…you are calling Fill on the _b_grid branch of the first tree – I am suggesting that a cleaner way would be to create a third, output tree, that clones the original tree and in addition it adds the new ones (like here and here).

ssh to an lxplus7 node (newer OS than lxplus) and follow the instructions here:

ssh jasot@lxplus7.cern.ch
. /cvmfs/sft.cern.ch/lcg/app/releases/ROOT/6.10.02/x86_64-centos7-gcc48-opt/root/bin/thisroot.sh

Hi Enrico,

Finally I could make it cloning the tree as you suggested, (but also including the statement t2->CopyEntries(t)), but it takes a lot of time. Then I’m just copying the root file with a script, and then editing it to attach the new branches.

Thanks!

Hi,
glad that you resolved! For future reference, could you please elaborate a bit more on the solution you found?

Cheers,
Enrico

Sure. This is the final code. It doesnt exactly what I wanted, but it is a solution.

TFile *fin=TFile::Open("file.root","UPDATE"); 
TTree *t = (TTree*)fin->Get("my_tree");

//key branch at the ttree:
int _time_stamp;
TBranch * _b_time_stamp;  t->SetBranchAddress("TimeStamp"   , &_time_stamp   , &_b_time_stamp  );

//new branch:
float _grid;
TBranch * _b_grid 	 = t ->Branch("grid"		, &_grid	, "grid/F");

//new branches in file 2:
TChain * t2 = new TChain("hv_variables");
t2->Add("run.root");

float _grid_2;
int _time_stamp_2;
TBranch * _b2_time_stamp;	t2->SetBranchAddress("time"		, &_time_stamp_2	, &_b2_time_stamp	);
TBranch * _b2_grid;		t2->SetBranchAddress("grid"		, &_grid_2		, &_b2_grid		);

int var=0;
for(int ev=0; ev < t->GetEntries() ; ++ev) {

	t->GetEntry(ev);
        var=set_var(_time_stamp,t2);
	t2->GetEntry(var);

	_grid=_grid_2;
	_b_grid->Fill();

} // End event loop

fin->cd();
t->Write();
fin->Close();

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