TEntryList and SetEntryList on chain not registering

Hi there,

I’m having some issue with a TTreeEntryList, that when setting the chain to the new list, it still registers and loops as if it was the original one.

For example

    chain->Draw(">>entrylist","ph_pt>30000","entrylistarray");
    TEntryList *elist = (TEntryList*)gDirectory->FindObject("entrylist");
    int listEntries=elist->GetN();
    int chainEntries=chain->GetEntries();
    chain->SetEntryList(elist,"ne");
    std::cout<<"list entries = "<<listEntries<<std::endl;
    std::cout<<"chain entries = "<< chainEntries << std::endl;
    copyRootTree(*chain, out_file, opts.tree);

where copyRootTree is a separate function that acts on a tree calling functions such as GetListOfLeaves and other chain/tree type methods.

I would have though chain->SetEntryList(elist,"ne"); would have been enough to make sure the new event list is looped on instead of the old one, however the output looks something like this:

new list entries = 3207
old chain entries = 3324
events processed: 0 (0% of 3324)
events processed: 1000 (30% of 3324)
events processed: 2000 (60% of 3324)

Any ideas on this?

Thanks!
Josh

Hi Experts,

Any thoughts on this?

Cheers,
Josh

Let’s ask @pcanal ! Philippe, would you know what’s happening?

Not all the ways to the loop are (can be) affected by the TEntryList. So how do you loop over the entries?

Cheers,
Philippe.

Hi Philippe,

This is what I suspected, but I hoped I was doing some stupid mistake.
We do the typical tree.GetEntries to loop. But also things like tree.GetListOfLeaves which get used quite a bit.
I was hoping to avoid rewriting a whole class just to account for the case where someone wants to add a TCut selection.

Is there anyway to force the new selection to propagate to a ttree with the ability to use all methods?

Cheers,
Josh

Hi,

You can ‘simply’ update your existing code to read:

auto filteredEntry = tree->GetEntryNumber( entrynumber ); // If no entry list, this will return 'entrynumber'
auto localEntry = tree->LoadTree( filteredEntry );

Cheers,
Philippe.

Is there some way to do this without creating an entry list? Ideally we could define the cut using the same kind of expressions we pass to TTree::Draw and then check whether entries pass the cut in the loop.

The issue is that in this method, we loop over all the data files twice: once to define the entry list and again to read the entries we actually want.

You may be looking for TTree::CopyTree

We’re often running over a chain of many files, so I’m not sure whether this is what we want. Where does the copy of the tree go? Will it try to load the whole chain into memory?

@pcanal, what we’re really looking for (which doesn’t exist, that I know of) is something like this

TCompiledCut cut(some_tcut_string);
int entries = tchain->GetEntries();
for (int entry = 0; entry < entries; entry++) {
  tchain->GetEntry(entry);
  if (!cut(tchain)) continue;
  // do things
}

i.e. we want a way to test one entry to see if it passes the cut, preferably one which doesn’t load the whole chain into memory or require us to loop over the chain twice.

This is spelt TTreeFormula :slight_smile: See TTreePlayer::CopyTree (https://root.cern.ch/doc/master/TTreePlayer_8cxx_source.html#l00186) for an example on how to use it.

Cheers,
Philippe.

PS. Alternatively, you may be interested in the ‘replacement’ for TTree::Draw : TDataFrame.

Thanks!

We don’t want to use a TDataFrame for this. But it looks like the following should work:

// this function is defined somewhere
bool pass(TTreeFormula* cut) {
  if (!cut) return true;
  cut->UpdateFormulaLeaves();
  Int_t ndata = cut->GetNdata();
  for(Int_t current = 0; current < ndata; current++) {
    if (cut->EvalInstance(current) == 0) return false;
  }
  return true;
}

// and then we define the cut
TTreeFormula* cut = new TTreeFormula("Selection", selection, chain);

// and in the event loop, call
if (!pass(cut)) continue;

@pcanal, there’s a lot of other stuff going on in the code you pointed to, but I think this is all we need, correct?

1 Like

This looks fine. Note that UpdateFormulaLeaves needs to be called ‘only’ at the file boundary of a TChain (hence the somewhat complex test surrounding it in the original code); doing it ‘too often’ would hurt the result but will be slower.

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