Hi,
I’m trying to use TTree::Draw to draw some histograms with cuts instead of looping over all the entries. I’m hoping TTree::Draw will be faster than looping when I have millions of entries.
Here is a minimal ROOT script that demonstrates my problem (the full code can be copied and pasted into a file called “test.C” and run with root test.C with no modifications).
#include "TTree.h"
#include "TH1.h"
#include "TLorentzVector.h"
// A simple function
bool isPxPositive(TLorentzVector lv) { return lv.Px() > 0 ? true : false; }
void test() {
// Create tree and two branches of type TLorentzVector
TTree *tree = new TTree("Tree","Tree");
TLorentzVector vec1, vec2;
tree->Branch("vecA",&vec1);
tree->Branch("vecB",&vec2);
// Fill the tree with some random TLorentzVectors
for (float i=0.0;i<1000.0;i++) {
vec1.SetPtEtaPhiE(sin(i),cos(i),sin(i)*cos(i),sin(i)*sin(i));
vec2.SetPtEtaPhiE(cos(i),cos(i)*cos(i),sin(i),sin(i)*cos(i));
tree->Fill();
}
// The "simple function" works just fine
printf("The PtEtaPhiE L.V. defined by (sin(x),cos(x),sin(x)*cos(x),sin(x)^2) with x = 1000 has Px > 0: %s\n", isPxPositive(vec1) ? "true" : "false");
// This works just fine
tree->Draw("vecA.Px()>>hist0","vecA.Px()>0","goff");
tree->Draw("vecA.M()>>hist1","vecA.M()>0","goff");
// This does not -- I get a "Bad numerical expression", "Variable compilation failed" error
//
// Searching for this error on the forums, people suggest substituting in a string, but I cannot
// do that here for obvious reasons -- this isn't a simple variable I can substitute in; the
// function itself requires the existence of the argument
tree->Draw("vecA.Px()","isPxPositive(vecA)","goff");
tree->Draw("(vecA + vecB).M()","1","goff");
// The following alternative process works, but it requires I loop over the tree
//
// I do this part to mimic getting a tree from a file
TTree *treecopy;
treecopy = tree;
// Define pointers to branches in the tree
TLorentzVector *vec1copy = 0;
TLorentzVector *vec2copy = 0;
treecopy->SetBranchAddress("vecA",&vec1copy);
treecopy->SetBranchAddress("vecB",&vec2copy);
// Define histograms
TH1F *hist2 = new TH1F("hist2","Title",100,0,1);
for (unsigned i=0;i<treecopy->GetEntries();i++) {
// vec1copy and vec2copy get populated with the ith tree entry
treecopy->GetEntry(i);
// I can do whatever I like with the current vec1copy and vec2copy
if (isPxPositive(*vec1copy)) { hist2->Fill(vec1copy->Px()); }
}
}
Essentially, the TTree::Draw function complains if the expression I’m trying to plot or the cut I’m trying to apply is anything but extremely basic, single-line formulae and basic, single-line conditionals on the bare variables.
If you’re wondering why I wrote the “simple function” when I could just apply the cut simply, it’s because in my real code, I have a rather complex set of conditionals that I wrapped inside a function. It’s not reasonable to expect all cuts to have a simple form; there are many variables and calculations at play.
Additionally, I could fill hundreds of branches of type float and int in my tree, corresponding to every possible value I could ever want (for example, instead of having two TLorentzVector branches, I could just have 27 branches, corresponding to pt, eta, phi, energy, mass, rapidity, px, py, and pz for each of particle1, particle2, and particle1 + particle2, so that I don’t have to work with TLorentzVectors and its member functions at all), but this is not an ideal solution.
So unless I can find a way to implement complex expression and complex conditionals in TTree::Draw, I’m stuck either saving hundreds of branches in a simple way, or looping through the events in the tree after its creation.
Thanks in advance for any advice.