TFormula vs. TTreeFormula

In the example code below, I try to plot f(x) = |1/(1+ix)|^2 in four different ways. The first three work, but the fourth doesn’t.

I guess the reason is that 1 and 2 use the “new” TFormula, while 3 and 4 use TTreeFormula which relies on the older version ROOT::v5::TFormula. Is that right? If so, are there any plans to update TTreeFormula? It’s not urgent, but it would be convenient if method 4 also worked.

I’m using v6.22.06.

Thanks!

TTree* xTree;
TH1F* xHist;

TTree* makeXTree(){
  if (xTree) delete xTree;
  xTree = new TTree("xTree","xTree");
  double xVar = 0.0;
  xTree->Branch("xVar",&xVar,"xVar/D");
  for (int i = 0; i < 100000; i++){
    xVar = gRandom->Uniform(0.0,10.0);
    xTree->Fill();
  }
  return xTree;
}

complex<double> oneOverOnePlusIX(double x){
  complex<double> onePlusIX(1.0,x);
  return complex<double>(1.0,0.0)/onePlusIX;
}

double normOneOverOnePlusIX(double x){
  return norm(oneOverOnePlusIX(x));
}

void plotNormOneOverOnePlusIX_works1(){
  if (xHist) delete xHist;
  xHist = new TH1F("xHist","xHist",100,0.0,10.0);
  TFormula rootFormula("tempFormula","normOneOverOnePlusIX(x)");
  for (int iBin = 1; iBin <= 100; iBin++){
    double x = xHist->GetBinCenter(iBin);
    xHist->SetBinContent(iBin,rootFormula.Eval(x));
  }
  xHist->Draw("hist");
} 

void plotNormOneOverOnePlusIX_works2(){
  if (xHist) delete xHist;
  xHist = new TH1F("xHist","xHist",100,0.0,10.0);
  TFormula rootFormula("tempFormula","norm(oneOverOnePlusIX(x))");
  for (int iBin = 1; iBin <= 100; iBin++){
    double x = xHist->GetBinCenter(iBin);
    xHist->SetBinContent(iBin,rootFormula.Eval(x));
  }
  xHist->Draw("hist");
} 

void plotNormOneOverOnePlusIX_works3(){
  if (xHist) delete xHist;
  xTree = makeXTree();
  xTree->Project("xHistFromTree(100,0.0,10.0)","xVar","normOneOverOnePlusIX(xVar)");
  xHist = (TH1F*) gDirectory->FindObject("xHistFromTree"); xHist->SetDirectory(0);
  xHist->Draw("hist");
}

void plotNormOneOverOnePlusIX_fails4(){
  if (xHist) delete xHist;
  xTree = makeXTree();
  xTree->Project("xHistFromTree(100,0.0,10.0)","xVar","norm(oneOverOnePlusIX(xVar))");
  xHist = (TH1F*) gDirectory->FindObject("xHistFromTree"); xHist->SetDirectory(0);
  xHist->Draw("hist");
}

What is the error message?

When I load the example macro and run plotNormOneOverOnePlusIX_fails4(), I get:

Error in TTreeFormula::Compile: TFormula can only call interpreted and compiled functions that return a numerical type: “oneOverOnePlusIX(xVar)”
Info in TSelectorDraw::AbortProcess: Variable compilation failed: {xVar,norm(oneOverOnePlusIX(xVar))}

I am not sure the move from v5 TFormula to the new TFormula would be enough to lift this kind of restriction.

Either way, we are currently not planning any development for TTreeFormula (besides bug fixes).

The alternative is to use RDataFrame instead of TTree::Draw/Project.

Thanks – I will check out RDataFrame, too.

Is it strange that “norm(oneOverOnePlusIX(x))” works as an argument to TFormula, like in plotNormOneOverOnePlusIX_works2(), but doesn’t work within TTree::Draw, like in plotNormOneOverOnePlusIX_fails4()? It seems so close to working.

@Axel According to your official statements, the “TTree::Draw” interface (and related) is NOT going to disappear any time soon. So, I also vote for upgrading the internally used “TFormula” interface to the newest available one.

That’s very much non-trivial - it’s a sizable amount of work, as TTreeFormula understands even more non-C++ syntax that we’d have to bring into TFormula (which understands mostly C++). We had discussed this in the past, and the outcome is as described by Philippe and others: we recommend to use RDataFrame, which fixes TTreeFormula limitations, comes with a scalable programming model (a HUGE issue with TTree::Draw - causing whole analyses to be written in TTree::Draw()!) and is about a gazillion times faster than TTreeFormula.

And yet we’re not going to remove TTreeFormula! :slight_smile:

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