Applying a cut when filling a TTree

Hello ROOTers,

I wrote a program that fills a ROOT TTree with the events from a Monte Carlo simulation. Assume the tree contains the following variables:Short_t n Float_t x[n] Float_t y[n] I’m not interested in the whole tree, but only in a small subset of events. The events are identified by some condition on the tree variables, e.g.sqrt(x)<=1./ywhich however is user-defined, i.e. known only at run time. I’d like to be able to fill the tree only with the events, or parts of events, that fulfil the user-defined condition.

Ideally I’d like to do something like // assign tree branches to variables n, x, y n = 3; x[0] = 1.0; x[1] = 1.0; x[2] = 1.0; y[0] = 10.0; y[1] = 0.1; y[2] = 0.01; TString condition; std::cin >> condition; tree->Fill(condition);and that would fill the tree with the following event:n=2 x[0]=1.0 y[0]=0.1 x[1]=1.0 y[1]=0.01Or, if this is impossible, I could fill the tree only if any of the array items satisfies the relevant condition.

Is there any way to realize that? Perhaps I could fill a temporary tree and copy over only the relevant bits, but I’m not sure how to do that.

Cheers,
Davide

I partially solved this by using a “buffer” tree.// define tree and tree branches here TTree *bufferTree = tree->CloneTree();When I want to add a row, I add it to bufferTree:bufferTree->Fill();From time to time, I copy the relevant events over to tree' and I resetbufferTree’:TTree *tempTree = bufferTree->CopyTree(condition); tree->CopyEntries(tempTree); delete tempTree; bufferTree->Reset();At the end of the simulation, I only write `tree’ to the output file.

This works, but it seems unnecessarily cumbersome. One could avoid creating a temporary tree if TTree::CopyEntries allowed to specify some selection, like TTree::CopyTree does.

Hi,

I am interested on this too. I think it would have been very helpful to have the possibility of introducing a cut as an argument of the TTree::Fill() function, so that the tree gets filled only if the condition is satisfied. Another way of doing this could be adding:

[code] //**************************************
TTree c_tree(“ctree”,“ctree”);
c_tree.Branch(“a”, &a);
c_tree.Branch(“b”, &b);

c_tree.Fill();

TTreeFormula form("tform", cut, &c_tree);

auto value = form.EvalInstance(i_entry);
//**************************************

 if (value)
   tree.Fill();
   [/code]

before filling the tree. However this means that one would have to make the branches all over again, normally tens of them, so probably the solution above is better.

I tried to obtain c_tree as a clone of tree, but it seems that the branches of the clone are not linked to the variables a and b but some version of them inside tree, so that everytime I do c_tree.Fill() I fill with the wrong number.

Cheers.

The upcoming TDataFrame interface might be a good direction for this kind of applications (See its snaphot feature in particular)

Hi, assuming you have your tree in a file on disk, since v6.10 you can solve your problem with TDataFrame, as pcanal suggested. The following code is not tested but should work about fine for branches containing a single float:

ROOT::Experimental::TDataFrame d("myTree", "file.root"); // instantiate TDF
d.Filter("sqrt(x) <= 1./y") // only consider events that fulfill this condition
 .Snapshot("skimmedTree", "output.root", {"n", "x", "y"}); // write to disk

For more complicated filter expressions you can use c++11 lambdas (or normal c++ functions). Here is a filter applied to branches x and y containing arrays of floats:

using arr_view_f = std::array_view<Float_t>;
auto myCut = [](const arr_view_f& x, const arr_view_f& y, int n) {
   /* your logic goes here, e.g. */
  auto xysum = 0;
  for(auto i = 0; i < n; ++i) xysum += x[i] + y[i];
  return xysum > 0;
}; 
d.Filter(myCut, {"x", "y", "n"}).Snapshot(/*as before*/);

Try:
rooteventselector --help