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')
../_images/muons_4_0.png

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()
../_images/muons_7_0.png

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')
../_images/muons_15_0.png

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')
../_images/muons_19_0.png

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