The Muon Collection
Contents
The Muon Collection¶
Muons are single-track particles. They can be reconstructed from hits in the tracking, calorimeter, and, of course, the muons chambers. Like electrons, there are several versions of the same muons that one can access (Tight
, Medium
, etc.).
import matplotlib.pyplot as plt
from config import ds_zmumu as ds
from helpers import match_objects
import awkward as ak
import numpy as np
import asyncio
from func_adl_servicex_xaodr21 import calib_tools
The default muon we fetch is the so-called Medium
muon with NonIso
isolation. Unfortunately, the MC we are working with for this demo contains very few muons!
muons = (ds
.Select(lambda e: e.Muons())
.Select(lambda muons: [m for m in muons if m.pt() > 30000.0])
.Select(lambda muons: {
'pt': [m.pt() / 1000.0 for m in muons],
'eta': [m.eta() for m in muons],
'phi': [m.phi() for m in muons],
})
.AsAwkwardArray()
.value())
plt.hist(ak.flatten(muons.pt), bins=100, range=(0, 100))
plt.xlabel('Muon $p_T$ [GeV]')
plt.ylabel('Number of muons')
_ = plt.title('Muon $p_T$ distribution for $Z\\rightarrow ee$ events')
Muon Types¶
Muons come in several different flavors. In this sample with very few muons, we can look at the different \(\eta\) distributions for what muons are there. As with the electrons we need to run three different queries (and we use the async keyword to run them in parallel):
import logging
# logging.basicConfig(level=logging.DEBUG)
# logging.getLogger("func_adl_xAOD.common.local_dataset").setLevel(level=logging.DEBUG)
# from servicex import ignore_cache
# with ignore_cache():
muon_working_points = ['Loose', 'Medium','Tight']
muons_async = [
(calib_tools.query_update(ds, muon_working_point=wp)
.SelectMany(lambda e: [mu.eta() for mu in e.Muons()])
.AsAwkwardArray('eta')
.value_async())
for wp in muon_working_points
]
muons_wp = await asyncio.gather(*muons_async)
for idx, wp in list(enumerate(muon_working_points)):
plt.hist(muons_wp[idx].eta, bins=50, range=(-3, 3), label=wp)
plt.xlabel('Muon $\\eta$')
plt.ylabel('Number of muons')
plt.yscale('log')
plt.title(r'Muon type $\eta$ distribution for $Z\rightarrow \mu\mu$ events')
_ = plt.legend()
Calibration¶
By default the muons we pulled are Medium
quality and calibrated. One can request different systematic errors using the calibration
argument to the Muons
method.
To grab the raw jets (without calibration) we just set the calibrated
parameter to None
(there is very little reason one will do this normally):
raw_muons = (ds
.Select(lambda e: e.Muons(uncalibrated_collection = "Muons"))
.Select(lambda l_muons: [m for m in l_muons if m.pt() > 30000.0])
.Select(lambda l_muons: {
'pt': [m.pt() / 1000.0 for m in l_muons],
'eta': [m.eta() for m in l_muons],
'phi': [m.phi() for m in l_muons],
})
.AsAwkwardArray()
.value())
The number of raw jets and the number of calibrated jets are quite different from the number of raw jets, so we’ll need to match them in \(\eta\) and \(\phi\):
len(ak.flatten(raw_muons.pt)), len(ak.flatten(muons.pt))
(1153980, 839038)
raw_muons_matched = match_objects(muons, raw_muons)
Note the units along the x-axis here!!
plt.hist(ak.flatten(muons.pt-raw_muons_matched.pt), bins=50, range=(-0.8, 0.8))
plt.xlabel('$\Delta p_T$ for calibrated muons matched to their raw muons [GeV]')
plt.ylabel('Number of muons')
_ = plt.title('The effect of muon calibration on muon $p_T$ in $Z\\rightarrow ee$ events')
If we instead want a particular systematic error, we need only name that error to get it back. Knowing what the names of the systematic errors, however, is not something that can be programmatically determined ahead of time. See the further information section at the end of this chapter to links to the ATLAS muon calibration info twiki.
sys_muon = (calib_tools.query_sys_error(ds, 'MUON_ID__1up')
.Select(lambda e: e.Muons())
.Select(lambda l_muons: [m for m in l_muons if m.pt() > 30000.0])
.Select(lambda l_muons: {
'pt': [m.pt() / 1000.0 for m in l_muons],
'eta': [m.eta() for m in l_muons],
'phi': [m.phi() for m in l_muons],
})
.AsAwkwardArray()
.value())
sys_muons_matched = match_objects(muons, sys_muon)
plt.hist(ak.flatten(muons.pt-sys_muons_matched.pt)/1000.0, bins=50, range=(-0.002, 0.002))
plt.xlabel('$\Delta p_T$ for calibrated muons matched to their reco stat muons [MeV]')
plt.ylabel('Number of muons')
_ = plt.title('The effect of a muon calibration sys error on muon $p_T$ in $Z\\rightarrow ee$ events')
The Data Model¶
The data model when this documentation was last built is.
from func_adl_servicex_xaodr21.xAOD.muon_v1 import Muon_v1
help(Muon_v1)
Help on class Muon_v1 in module func_adl_servicex_xaodr21.xAOD.muon_v1:
class Muon_v1(builtins.object)
| A class
|
| Methods defined here:
|
| charge(self) -> 'float'
| A method
|
| clearDecorations(self) -> 'bool'
| A method
|
| cluster(self) -> 'func_adl_servicex_xaodr21.xAOD.calocluster_v1.CaloCluster_v1'
| A method
|
| clusterLink(self) -> 'func_adl_servicex_xaodr21.elementlink_datavector_xaod_calocluster_v1__.ElementLink_DataVector_xAOD_CaloCluster_v1__'
| A method
|
| combinedTrackParticleLink(self) -> 'func_adl_servicex_xaodr21.elementlink_datavector_xaod_trackparticle_v1__.ElementLink_DataVector_xAOD_TrackParticle_v1__'
| A method
|
| e(self) -> 'float'
| A method
|
| eta(self) -> 'float'
| A method
|
| extrapolatedMuonSpectrometerTrackParticleLink(self) -> 'func_adl_servicex_xaodr21.elementlink_datavector_xaod_trackparticle_v1__.ElementLink_DataVector_xAOD_TrackParticle_v1__'
| A method
|
| hasNonConstStore(self) -> 'bool'
| A method
|
| hasStore(self) -> 'bool'
| A method
|
| inDetTrackParticleLink(self) -> 'func_adl_servicex_xaodr21.elementlink_datavector_xaod_trackparticle_v1__.ElementLink_DataVector_xAOD_TrackParticle_v1__'
| A method
|
| index(self) -> 'int'
| A method
|
| m(self) -> 'float'
| A method
|
| msOnlyExtrapolatedMuonSpectrometerTrackParticleLink(self) -> 'func_adl_servicex_xaodr21.elementlink_datavector_xaod_trackparticle_v1__.ElementLink_DataVector_xAOD_TrackParticle_v1__'
| A method
|
| muonSegment(self, i: 'int') -> 'func_adl_servicex_xaodr21.xAOD.muonsegment_v1.MuonSegment_v1'
| A method
|
| muonSegmentLink(self, i: 'int') -> 'func_adl_servicex_xaodr21.elementlink_datavector_xaod_muonsegment_v1__.ElementLink_DataVector_xAOD_MuonSegment_v1__'
| A method
|
| muonSegmentLinks(self) -> 'func_adl_servicex_xaodr21.vector_elementlink_datavector_xaod_muonsegment_v1___.vector_ElementLink_DataVector_xAOD_MuonSegment_v1___'
| A method
|
| muonSpectrometerTrackParticleLink(self) -> 'func_adl_servicex_xaodr21.elementlink_datavector_xaod_trackparticle_v1__.ElementLink_DataVector_xAOD_TrackParticle_v1__'
| A method
|
| nMuonSegments(self) -> 'int'
| A method
|
| p4(self) -> 'func_adl_servicex_xaodr21.tlorentzvector.TLorentzVector'
| A method
|
| passesHighPtCuts(self) -> 'bool'
| A method
|
| passesIDCuts(self) -> 'bool'
| A method
|
| phi(self) -> 'float'
| A method
|
| primaryTrackParticle(self) -> 'func_adl_servicex_xaodr21.xAOD.trackparticle_v1.TrackParticle_v1'
| A method
|
| primaryTrackParticleLink(self) -> 'func_adl_servicex_xaodr21.elementlink_datavector_xaod_trackparticle_v1__.ElementLink_DataVector_xAOD_TrackParticle_v1__'
| A method
|
| pt(self) -> 'float'
| A method
|
| rapidity(self) -> 'float'
| A method
|
| usingPrivateStore(self) -> 'bool'
| A method
|
| usingStandaloneStore(self) -> 'bool'
| A method
|
| ----------------------------------------------------------------------
| Readonly properties defined here:
|
| auxdataConst
| 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)
Further Information¶
The
xAOD::Muon_v1
C++ header file with all the inline documentation.The Muon Recommendation Pages for R21 on the ATLAS TWiki