Object arguments to class methods in TTree::Draw

Hi,

This is something that seems so simple that it’s just a trivial mistake. Any pointers/help appreciated. I am working primarily in ROOT 5.14 due to my collaboration’s software, but the same thing seems to happen in 5.16 too.

I have a TTree, which has branches that hold TLorentzVector and booleans. The branches are created like this:

  m_recoTree = new TTree("RecoTree","data parameters");
  m_RecoElec1Vec = new TLorentzVector;
  m_RecoElec2Vec = new TLorentzVector;
  m_RecoZVec = new TLorentzVector;

  m_b_RecoElec1Vec   = m_recoTree->Branch("RecoElec1Vec.", "TLorentzVector", &m_RecoElec1Vec, 32000, 0); // I have also tried 99 as the final argument
  m_b_MatchedElec1L1 = m_recoTree->Branch("MatchedElec1L1", &m_MatchedElec1L1, "MatchedElec1L1/O");
  m_b_MatchedElec1L2 = m_recoTree->Branch("MatchedElec1L2", &m_MatchedElec1L2, "MatchedElec1L2/O");
  m_b_MatchedElec1EF = m_recoTree->Branch("MatchedElec1EF", &m_MatchedElec1EF, "MatchedElec1EF/O");
  m_b_RecoElec2Vec   = m_recoTree->Branch("RecoElec2Vec.", "TLorentzVector", &m_RecoElec2Vec, 32000, 0);
  m_b_MatchedElec2L1 = m_recoTree->Branch("MatchedElec2L1", &m_MatchedElec2L1, "MatchedElec2L1/O");
  m_b_MatchedElec2L2 = m_recoTree->Branch("MatchedElec2L2", &m_MatchedElec2L2, "MatchedElec2L2/O");
  m_b_MatchedElec2EF = m_recoTree->Branch("MatchedElec2EF", &m_MatchedElec2EF, "MatchedElec2EF/O");
  m_b_RecoZVec   = m_recoTree->Branch("RecoZVec.", "TLorentzVector", &m_RecoZVec, 32000, 0);

So far so simple, and the tree appears to fill OK. I can, for example, draw the Pt() or M() of the TLorentzVectors in one line of an interactive ROOT session. What doesn’t work for me is TLorentzVector::DeltaR(TLorentzVector&):

[flowerdew@beta run]$ root -l output.Efficiency.root
root [0]
Attaching file output.Efficiency.root as _file0...
root [1] RecoTree->Draw("RecoElec1Vec.Pt()") // This is OK
<TCanvas::MakeDefCanvas>: created default TCanvas with name c1
root [2] RecoTree->Draw("RecoElec1Vec.DeltaR(RecoElec2Vec.)")
Error: Symbol RecoElec2Vec is not defined in current scope  (tmpfile):1:
Error: Failed to evaluate RecoElec2Vec.
*** Interpreter error recovered ***
Error: class,struct,union or type (unknown) not defined  (tmpfile):1:
Error: Symbol RecoElec2Vec is not defined in current scope  (tmpfile):1:
Error: Failed to evaluate RecoElec2Vec.
*** Interpreter error recovered ***
Error: class,struct,union or type (unknown) not defined  (tmpfile):1:

 *** Break *** segmentation violation
## Stack trace is output to screen here

The seg fault seems to occur in TVector3::PseudoRapidity () (as given by the stack trace), which doesn’t seem to fit with the error “Symbol RecoElec2Vec is not defined in current scope”.

If I call ‘gSystem->Load(“libPhysics.so”)’ before plotting, the same error occurs, and ommitting the ‘.’ after RecoElec2Vec makes no difference either. If I access the TRef for the branch, I get a different, and no less confusing error:

root [1] RecoTree->Draw("RecoElec1Vec.DeltaR(((TLorentzVector*)(RecoElec2Vec@.GetObject())))")
Error: Symbol TLorentzVector is not defined in current scope  (tmpfile):1:
Syntax Error: TLorentzVector* (tmpfile):1:
*** Interpreter error recovered ***
Error: class,struct,union or type (unknown) not defined  (tmpfile):1:
Error: Symbol TLorentzVector is not defined in current scope  (tmpfile):1:
Syntax Error: TLorentzVector* (tmpfile):1:
*** Interpreter error recovered ***
Error: class,struct,union or type (unknown) not defined  (tmpfile):1:
Error in <TTreeFormula::DefinedVariable>: Can not call '' with a class
Error in <TTreeFormula::Compile>:  Bad numerical expression : "RecoElec1Vec.DeltaR(((TLorentzVector*)(RecoElec2Vec@.GetObject())))"
*** Interpreter error recovered ***
root [2]

What am I doing wrong here?

Thanks,
Mike Flowerdew

Hi,

You currently can not pass a ‘branch variable dependent’ to a member function call directly via TTree::Draw (i.e. your case).

For this kind of calls, you should consider using the MakeProxy method instead. I.e create a file myfunc.C:double myfunc() { return RecoElec1Vec.DeltaR(((TLorentzVector*)(RecoElec2Vec@.GetObject()))); } and use RecoTree->Draw("myfunc.C+");

Cheers,
Philippe

PS. Note that unlike the regular TTreeDraw, this method does not automatically loop over the element of an array within one TTree Entry.

Hi, and thanks,

I see now. The line as written in myfunc() doesn’t work (it was based on my garbled understanding of string parsing in TTree::Draw), but this does:

double myfunc() {
  return fabs(RecoElec1Vec->DeltaPhi(*RecoElec2Vec.obj.GetPtr()));
}

Incidentally, it seems quite hard to find information on classes like TObjProxy. In the end, I found the class definition in root.cern.ch/root/html/ClassIndex.html

Additionally, while operator->() is defined for the proxy, I can’t seem to dereference it directly (ie normally I would “expect” RecoElec2Vec to act like a TLorentzVector, because RecoElec2Vec itself “acts” like a TLorentzVector). Is this possible? Will it perhaps be implemented at some point?

Cheers,
Mike

Hi,

TObjProxy is an internal class which in the best of world should be transparent to the user :slight_smile:. In addition, the actual class used it not a TObjProxy but generated code you can find in the header file generated (which often used and/or inherit from TObjProxy).

The functional documentation is at root.cern.ch/root/html/TTree.htm … :MakeProxy.

[quote]Additionally, while operator->() is defined for the proxy, I can’t seem to dereference it directly (ie normally I would “expect” RecoElec2Vec to act like a TLorentzVector, because RecoElec2Vec itself “acts” like a TLorentzVector). Is this possible? Will it perhaps be implemented at some point?[/quote]Indeed, only operator-> is currently implemented. I will look into adding operator*.

Thanks for the suggestion :slight_smile:
Philippe.