# Problem using TTree::Draw with non-simple expressions and cuts

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;
// 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.

Hi,

you can use a “Proxy”.
Here is how you write one

``````// myProxy.C
TH1D *h1 = nullptr;

void myProxy_Begin(TTree*) {
// create here histogram
h1 = new TH1D("h1","h1",100,0,1000);
}

double  myProxy() {
// put here user code
for (auto&& track : *tracks) {
double pt = track.Pt();
h1->Fill(pt);
}
return 0;
}

void myProxy_Terminate() {
// draw the histogram
h1->Draw();
}
``````

in order to run it on a tree (see attached file: it contains a trivial tree called events):

``````root eventsSmall.root
root events->Draw("myProxy.C+")``````

Danilo