The Jet Collection
Contents
The Jet Collection¶
We’ll start with the Jet collection, one of the most commonly used collections in ATLAS. Below we’ll look at:
Getting jet kinematic properties like \(p_T\) and \(\eta\).
Getting the constituents that went into building the jet.
Getting the attributes associated with the jet.
The data model used in ATLAS’ xAOD is defined by the C++ objects. func_adl
translates the python requests into C++ - so it needs to know about this data model. The func_adl_servicex_xaodr21
package contains that information. For example, when we access a jet’s \(p_T\) with j.pt()
, the func_adl
system accesses meta-data in the func_adl_servicex_xaodr21
to understand how to make the call, and that its return type is double
. With few exceptions, that is how one accesses all methods on the xAOD objects.
The first thing to do is import what we need in our environment. This will be the case at the top of every chapter, but we show it for completness.
The datasets. See the DataSet chapter for more information.
Various utilities for plotting and array manipulation
Some helpers for accessing attributes below (
cpp_float, cpp_vfloat
)
from config import ds_zee as ds
from config import ds_jz2_exot15
import matplotlib.pyplot as plt
import awkward as ak
import numpy as np
from func_adl_servicex_xaodr21 import cpp_float, cpp_vfloat
Here we return an array of all the jet \(p_T\)’s above 30 GeV. The first SelectMany
transforms the event e
into a list of jets with the e.Jets()
. In this case it returns the default jet collection, properly calibrated and with overlaps removed (see the next chapter on calibration for more information). The SelectMany
returns this as a flattened array of jets.
from servicex import ignore_cache
with ignore_cache():
jets = (ds
.SelectMany(lambda e: e.Jets())
.Where(lambda j: (j.pt() / 1000) > 30)
.Select(lambda j: j.pt() / 1000.0)
.AsAwkwardArray('JetPt')
.value())
plt.hist(jets.JetPt, bins=100, range=(0, 100))
plt.xlabel('Jet $p_T$ [GeV]')
plt.ylabel('Number of jets')
_ = plt.title('Jet $p_T$ distribution for $Z\\rightarrow ee$ events')
Jet Constituents¶
Jets are composed of TopoClusters
in ATLAS, and unfortunately, they are often skimmed away. They are not present, for example, in DAOD_PHYS
, which is the skim being used here for most examples. To demonstrate their use we’ll pull from a R21 EXOT15 skim that contains them. Since each jet has an array of topo clusters, and we are just interested in all the TopoClusters
, we use two SelectMany
calls to flatten both arrays.
topo_clusters = (ds_jz2_exot15
.SelectMany(lambda e: e.Jets())
.SelectMany(lambda j: j.getConstituents())
.Select(lambda tc: tc.pt())
.AsAwkwardArray('JetClusterPt')
.value()
)
plt.hist(topo_clusters.JetClusterPt/1000.0, bins=100, range=(0, 20))
plt.xlabel('Jet Cluster $p_T$ [GeV]')
plt.ylabel('Number of jets')
_ = plt.title('Jet Cluster $p_T$ distribution for jets in $Z\\rightarrow ee$ events')
Jet Moments¶
Attributes are called moments by the ATLAS Jet/ETMiss group. They are extra information that has been added into the jet object. The Run 2 Moments Page lists all the moments. To access them you’ll need to know the return type explicitly, and parameterize your call to getAttribute
appropriately.
Here we grab the EMFrac
moment, which is the EM Fraction of the jet. It is a single float for each jet. We specify the type with the cpp_float
in the getAttribute[cpp_float]('EMFrac')
call. This is translated into C++ that looks something like j->getAttribute<float>("EMFrac")
.
moments = (ds
.SelectMany(lambda e: e.Jets())
.Where(lambda j: (j.pt() / 1000) > 30)
.Select(lambda j: j.getAttribute[cpp_float]('EMFrac'))
.AsAwkwardArray('emfrac')
.value())
plt.hist(moments.emfrac, bins=100, range=(0, 1.1))
plt.xlabel('EM Fraction')
plt.ylabel('Number of jets')
_ = plt.title('EM Fraction of jets in JZ3 events')
More complex objects can come back as well. For example, vectors of floats (std::vector<float>
). Here is a sample with the sum track \(p_T\) when track \(p_T > 500\) MeV.
sum_pt = (ds
.SelectMany(lambda e: e.Jets("AntiKt4EMPFlowJets"))
.Where(lambda j: (j.pt() / 1000) > 31)
.SelectMany(lambda j: j.getAttribute[cpp_vfloat]('SumPtTrkPt500'))
.AsAwkwardArray('sum_pt')
.value())
plt.hist(sum_pt.sum_pt/1000.0, bins=100, range=(0, 4))
plt.xlabel('Sum track $p_T$ [GeV]')
plt.ylabel('Number of jets')
plt.yscale('log')
_ = plt.title('Sum Track $p_T$ for tracks over 500 MeV in JZ3 events')
As with everything else in the ATLAS data model, even if they are reconstructed and associated with the jet, they can be stripped out with slimming - so just because they are declared on the Run 2 Moments page, it doesn’t mean they actually exist in the data file you are looking at.
This describes the basics of how to access jets in the ATLAS xAOD. The next chapter will continue discussing jets, focusing on how calibrations are handled by the func_adl
backend.
The Data Model¶
The data model when this documentation was last built was:
from func_adl_servicex_xaodr21.xAOD.jet_v1 import Jet_v1
help(Jet_v1)
Help on class Jet_v1 in module func_adl_servicex_xaodr21.xAOD.jet_v1:
class Jet_v1(builtins.object)
| A class
|
| Methods defined here:
|
| btagging(self) -> 'func_adl_servicex_xaodr21.xAOD.btagging_v1.BTagging_v1'
| A method
|
| btaggingLink(self) -> 'func_adl_servicex_xaodr21.elementlink_datavector_xaod_btagging_v1__.ElementLink_DataVector_xAOD_BTagging_v1__'
| A method
|
| clearDecorations(self) -> 'bool'
| A method
|
| constituentLinks(self) -> 'func_adl_servicex_xaodr21.vector_elementlink_datavector_xaod_iparticle___.vector_ElementLink_DataVector_xAOD_IParticle___'
| A method
|
| e(self) -> 'float'
| A method
|
| eta(self) -> 'float'
| A method
|
| getConstituents(self) -> 'func_adl_servicex_xaodr21.xAOD.jetconstituentvector.JetConstituentVector'
| A method
|
| getSizeParameter(self) -> 'float'
| A method
|
| hasNonConstStore(self) -> 'bool'
| A method
|
| hasStore(self) -> 'bool'
| A method
|
| index(self) -> 'int'
| A method
|
| m(self) -> 'float'
| A method
|
| numConstituents(self) -> 'int'
| A method
|
| p4(self) -> 'func_adl_servicex_xaodr21.tlorentzvector.TLorentzVector'
| A method
|
| phi(self) -> 'float'
| A method
|
| pt(self) -> 'float'
| A method
|
| px(self) -> 'float'
| A method
|
| py(self) -> 'float'
| A method
|
| pz(self) -> 'float'
| A method
|
| rapidity(self) -> 'float'
| A method
|
| rawConstituent(self, i: 'int') -> 'func_adl_servicex_xaodr21.xAOD.iparticle.IParticle'
| A method
|
| usingPrivateStore(self) -> 'bool'
| A method
|
| usingStandaloneStore(self) -> 'bool'
| A method
|
| ----------------------------------------------------------------------
| Readonly properties defined here:
|
| auxdataConst
| A method
|
| getAttribute
| A method
|
| isAvailable
| A method
|
| ----------------------------------------------------------------------
| Data descriptors defined here:
|
| __dict__
| dictionary for instance variables (if defined)
|
| __weakref__
| list of weak references to the object (if defined)
from func_adl_servicex_xaodr21.xAOD.jetconstituent import JetConstituent
help(JetConstituent)
Help on class JetConstituent in module func_adl_servicex_xaodr21.xAOD.jetconstituent:
class JetConstituent(builtins.object)
| A class
|
| Methods defined here:
|
| e(self) -> 'float'
| A method
|
| eta(self) -> 'float'
| A method
|
| isSpacelike(self) -> 'bool'
| A method
|
| isTimelike(self) -> 'bool'
| A method
|
| m(self) -> 'float'
| A method
|
| phi(self) -> 'float'
| A method
|
| pt(self) -> 'float'
| A method
|
| rapidity(self) -> 'float'
| A method
|
| rawConstituent(self) -> 'func_adl_servicex_xaodr21.xAOD.iparticle.IParticle'
| A method
|
| ----------------------------------------------------------------------
| Data descriptors defined here:
|
| __dict__
| dictionary for instance variables (if defined)
|
| __weakref__
| list of weak references to the object (if defined)
Further Information¶
The
xAOD::Jet_v1
C++ header file with all the inline documentation.The
xAOD::JetConstituent
C++ header File with all the inline documentation.The Jet ET-Miss Recommendation Pages for R21 on the ATLAS TWiki