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.