Source code for columnflow.production.cms.gen_top_decay

# coding: utf-8

"""
Producers that determine the generator-level particles related to a top quark decay.
"""

from __future__ import annotations

from columnflow.production import Producer, producer
from columnflow.util import maybe_import
from columnflow.columnar_util import set_ak_column

ak = maybe_import("awkward")


[docs] @producer( uses={"GenPart.{genPartIdxMother,pdgId,statusFlags}"}, produces={"gen_top_decay"}, ) def gen_top_decay_products(self: Producer, events: ak.Array, **kwargs) -> ak.Array: """ Creates a new ragged column "gen_top_decay" with one element per hard top quark. Each element is a GenParticleArray with five or more objects in a distinct order: top quark, bottom quark, W boson, down-type quark or charged lepton, up-type quark or neutrino, and any additional decay produces of the W boson (if any, then most likly photon radiations). Per event, the structure will be similar to: .. code-block:: python [ # event 1 [ # top 1 [t1, b1, W1, q1/l, q2/n(, additional_w_decay_products)], # top 2 [...], ], # event 2 ... ] """ # find hard top quarks abs_id = abs(events.GenPart.pdgId) t = events.GenPart[abs_id == 6] t = t[t.hasFlags("isHardProcess")] t = t[~ak.is_none(t, axis=1)] # distinct top quark children (b's and W's) t_children = t.distinctChildrenDeep[t.distinctChildrenDeep.hasFlags("isHardProcess")] # get b's b = t_children[abs(t_children.pdgId) == 5][:, :, 0] # get W's w = t_children[abs(t_children.pdgId) == 24][:, :, 0] # distinct W children w_children = w.distinctChildrenDeep[w.distinctChildrenDeep.hasFlags("isHardProcess")] # reorder the first two W children (leptons or quarks) so that the charged lepton / down-type # quark is listed first (they have an odd pdgId) w_children_firsttwo = w_children[:, :, :2] w_children_firsttwo = w_children_firsttwo[(w_children_firsttwo.pdgId % 2 == 0) * 1] w_children_rest = w_children[:, :, 2:] # concatenate to create the structure to return groups = ak.concatenate( [ t[:, :, None], b[:, :, None], w[:, :, None], w_children_firsttwo, w_children_rest, ], axis=2, ) # save the column events = set_ak_column(events, "gen_top_decay", groups) return events
@gen_top_decay_products.skip def gen_top_decay_products_skip(self: Producer, **kwargs) -> bool: """ Custom skip function that checks whether the dataset is a MC simulation containing top quarks in the first place. """ return self.dataset_inst.is_data or not self.dataset_inst.has_tag("has_top")