One question everyone will have is: how do I know what
information/variables are actually stored in my xAOD for each
container type? You can be sure for “particles” (inheriting from
IParticle
) you will have things like pt, eta, and phi. But what
other variables are associated to the different containers? We’ll try
to answer that question…
In order to “retrieve” the information stored in the xAOD containers
we need to know the container type and the container key name. We will
use a handy script called checkxAOD.py
. If you have an xAOD file,
say xAOD.pool.root
and want to know the containers and associated
key names do the following:
checkxAOD.py xAOD.pool.root
Note: You need to replace the fake
xAOD.pool.root
with the full path to an xAOD sample, for example$ALRB_TutorialData//mc21_13p6TeV.601229.PhPy8EG_A14_ttbar_hdamp258p75_SingleLep.deriv.DAOD_PHYS.e8357_s3802_r13508_p5057/DAOD_PHYS.28625583._000007.pool.root.1
.Alternatively you can make a symbolic link using
ln -s $ALRB_TutorialData//mc21_13p6TeV.601229.PhPy8EG_A14_ttbar_hdamp258p75_SingleLep.deriv.DAOD_PHYS.e8357_s3802_r13508_p5057/DAOD_PHYS.28625583._000007.pool.root.1 xAOD.pool.root
.
The last column will show you the xAOD container names and types. When
you are retrieving information you usually need to know the container
type (for example xAOD::CaloCluster
) and the key name for the
particular instance of that container you are interested in (for
example "egammaClusters"
). In your analysis you can ignore the
Aux
containers (for Auxiliary store), these hold some
behind-the-scenes magic. You can also “mostly” ignore the versions
like _v1
. Most information in the xAOD is stored and retrieved via
the Auxiliary store. The user doesn’t need to worry about this
Auxiliary store, and only retrieves the interface from the event store
(e.g. TEvent
for ROOT standalone analysis). So now you should know the
container type and key name. If you use the wrong key name the code
will compile, but it will fail at run-time.
Now to know what variables are associated to this container, the trick I use at the moment (again maybe something official will come along…) is to use interactive ROOT. So back into your Analysis Release shell (with ROOT automatically setup), you can simply do this:
root -l xAOD.pool.root
root [1] CollectionTree->Print("egammaClusters*")
You will get a printout of all variables you can access from that container (aka collection). Note that the variable name you will use in your code is the one that comes after the “.”, so for example you might see:
egammaClusters.rawEta : vector<float>
So in your analysis code (after setting up the TEvent and interface
magic), you can access this variable from the xAOD::CaloCluster
object
by calling rawEta
.
If you try to request a variable associated to a particular xAOD
object that does not exist the code will fail at compile-time,
complaining the xAOD object has no member named 'whatever'
. This
will mean either that the variable does not exist at all or that it
needs to be accessed in a different way, e.g. to access a cluster
moment, you would do something like:
#include <xAODCaloEvent/CaloClusterContainer.h>
...
const xAOD::CaloClusterContainer* cls = nullptr;
ANA_CHECK (evtStore()->retrieve ( cls, "egammaClusters" ));
for (const xAOD::CaloCluster* cl : *cls) {
double moment = 0.0;
cl->retrieveMoment( xAOD::CaloCluster::PHICALOFRAME, moment );
}
Add to the CMake file:
LINK_LIBRARIES [...] xAODCaloEvent
And this would retrieve the FIRST_PHI
variable from the input file.
To access variables associated to objects in your analysis code there are often special accessor functions available to help. These are associated to the objects of the containers. At the moment the best place to find these accessors is by browsing the code. All of the xAOD EDM classes live in atlasoff/Event/xAOD, and the naming should be obvious to find the object type you are interested in. Alternatively you can access the variables directly without using the accessors, but this is slow as it depends on string comparisons.
Here is one example that might clarify these points (you don’t have to
copy and paste this anywhere, it’s just a qualitative
description). Let’s say you have a pointer to an xAOD::Muon
object for
a particular event, called (*muon_itr)
(we’ll actually do this later
on in complete detail), and now we want to access the ptcone20
isolation variable for this muon.
To access the variable with the help of the muon accessor you can do:
// your variable that will be filled after calling the isolation function
float muPtCone20 = 0.;
// second arg is an enum defined in xAODPrimitives/IsolationType.h
(*muon_itr)->isolation(muPtCone20, xAOD::Iso::ptcone20);
Alternatively you can access that same variable by defining an accessor:
SG::AuxElement::ConstAccessor<float> ptcone20("ptcone20");
and then calling it later
float muPtCone20 = ptcone20(**muon_itr);
For convenience there’s an alternative:
(*muon_itr)->auxdata< float >("ptcone20");
but note that this is slower and should be avoided in production code.
For the muons you can find the complete list of accessors in the xAOD Muon class (version 1)
Most of our data is organized into containers of objects of a specific
type, jets, muons, electrons, etc. As a simple exercise, let’s
retrieve the jet container "AntiKt4EMPFlowJets"
and print the pt for
each jet.
First, let’s add the jet xAOD EDM package to MyAnalysis/CMakeLists.txt
:
LINK_LIBRARIES [...] xAODJet
where [...]
is any other package dependencies you may already have included
(you may have already added this earlier in the tutorial).
Now let’s add the relevant code to MyxAODAnalysis.cxx
:
#include <xAODJet/JetContainer.h>
...
execute () {
...
// get jet container of interest
const xAOD::JetContainer* jets = nullptr;
ANA_CHECK (evtStore()->retrieve (jets, "AntiKt4EMPFlowJets"));
ANA_MSG_INFO ("execute(): number of jets = " << jets->size());
// loop over the jets in the container
for (const xAOD::Jet *jet : *jets) {
ANA_MSG_INFO ("execute(): jet pt = " << (jet->pt() * 0.001) << " GeV"); // just to print out something
} // end for loop over jets
...
}
...
If you are not sure of the container type and/or container name see above. Note that we are taking advantage here of C++11 for loops to simplify our code.
You are liable to see two ways to do the above code, both in the tutorial and in ATLAS in general. The other way to do it is using the C++11 keyword
auto
:for (auto jet : *jets) [...]
Which one is better is a matter of debate, but both methods work and do exactly the same. Using
auto
is somewhat more compact, but using the exact type is more explicit in what you are doing and can avoid certain kinds of mistakes.
Now compile and run the code and check for the new print-out. Note that there is a lot of print-out, so you may want to disable it once you are done with this part of the exercise.
InDetTrackParticle
collection.