Regarding this part of your question, it seems that you would like to have something as convenient as TTree::Draw()
call.
myTree->Draw("myVar", "MCParticles[].PDG == 211 && MCParticles[].momentum.z > 5")
How does string with selection criteria become a TTreeFormula
? As far as I know, TTree
passes arguments to underlying TTreePlayer
, which then runs TTreePlayer::Process
over all events in tree.
Furthermore, TTreePlayer
internally uses an abstract class TSelector
which carries all logic to process events, and specialized version TSelectorDraw
is used by TTree::Draw()
. TTreeFormula
is compiled from the string inside TSelectorDraw::CompileVariables
method.
So far I am afraid that there is no direct and simple way to use TTreeFormula
in an analysis based on simple TTreeReader
loop like
while (myTTreeReader.Next()) {
// do stuff
}
It seems that in order to use TTreeFormula
you have to develop your own class akin to TSelectorDraw
for analysis. There are tutorials h1analysisTreeReader and run__h1analysis to get acquainted with how TSelector
works.
However, I would advise to learn RDataFrame
, which is more modern and simple way of doing things. On the other hand, it might indeed lack convenience of TTreeFormula
and TTree::Draw()
, but similar behavior can be achieved.
In the code I’ve provided in my previous message, the following piece which applies selection
auto dWithSurvived = dFilled.Define(
"survivedParticles",
[](const ROOT::RVec<edm4hep::MCParticleData>& particles) -> ROOT::RVec<edm4hep::MCParticleData>
{
return particles[ROOT::VecOps::Map(particles, applySelectionCriteria)];
},
{"particles"}
);
can use just-in-time compiled strings instead of lambda function with some preparatory work:
double getEnergy(const edm4hep::MCParticleData& particle) {
return particle.energy;
}
void test_rdataframe() {
// ...
auto dWithSurvived = dFilled.Define(
"survivedParticles",
"particles[Map(particles, getEnergy) > 0.5]"
);
// ...
}
I must notice that in my snippet stored class is not split, therefore some way to access class members is needed. If it was stored in a TTree
with members split in branches, I suppose that even more simple code will suffice:
auto dWithSurvived = dFilled.Define(
"survivedParticles.energy",
"particles.energy[particles.energy > 0.5]"
);
To sum up, to use TTreeFormula
outside of TTree::Draw()
you have to set up additional infrastructure to compile expressions, like TSelectorDraw
does, which seems to be a cumbersome task.
On the other hand, RDataFrame
is more convenient in general and allows JIT compiling of expressions out of the box, but may require setting up auxiliary columns or functions for class members access, if the class was written to TTree
without splitting.