Skip to content

Instantly share code, notes, and snippets.

@artlbv
Last active April 20, 2023 12:41
Show Gist options
  • Save artlbv/81ff8562e5dc4faf6b68a155f6c93a08 to your computer and use it in GitHub Desktop.
Save artlbv/81ff8562e5dc4faf6b68a155f6c93a08 to your computer and use it in GitHub Desktop.
Read L1 uGT algo block bits and names
# method to read L1 bits
# only unprescaled ones are considered for the total L1 decision
def read_L1_bits_alias(fnames, prescale_file_name = None, use_prescale_file=True, L1bitTree = "l1uGTTree/L1uGTTree"):
L1bittrees = []
for filepath in fnames:
file = uproot.open(filepath)
L1bittrees.append( file[L1bitTree] )
# we need to make sure to apply prescales properly!
# as the anomaly team does it, we only use un-prescaled paths
if use_prescale_file:
with open(prescale_file_name) as prescale_file:
wanted_keys = [line.split(',')[1] for line in prescale_file if line.split(',')[4] == "1"]
else: wanted_keys = []
bits_part = []
for tree in L1bittrees:
decisions = tree["m_algoDecisionFinal"].array()
resultdict = {}
aliases = tree.aliases
for alias in aliases:
if alias in wanted_keys or not use_prescale_file:
decision_index_string = aliases[alias]
decision_position = int(re.match(r"L1uGT\.m_algoDecisionInitial\[([0-9]+)\]", decision_index_string).group(1))
resultdict[alias] = decisions[:,decision_position]
# calculating the total L1 bis, as the one stored in L1 ntuples also consideres prescaled paths
# (as a L1_AlwaysTrue is contained, the total L1 bit is just true everywhere)
total_L1_bit = np.any( np.asarray( list(resultdict.values()) ) , axis=0 ).flatten()
df_total_L1 = pd.DataFrame( {"total L1": total_L1_bit} )
df_trigger_bits = pd.DataFrame(resultdict)
df_bits = df_total_L1.join(df_trigger_bits)
bits_part.append(df_bits)
bits = pd.concat(bits_part)
return bits
def read_L1_bits(fnames, prescale_fname,
treename = "l1uGTTree/L1uGTTree",
decision_branch = "m_algoDecisionFinal",
ps_select = "ps = 1"
):
'''
####################################################################################
Disclaimer: this method relies on the fact that the prescale CSV file is relevant
for all the data-taking period (MC campaign) being processed here !!
If any L1 seed <> bit name association change, this will not work.
(one will need to rely on the tree.alias to get the name<>bit association,
but this means that *that* CSV file cannot be used anymore)
####################################################################################
'''
## Read PS file and find PS=1 bits (i.e. unprescaled)
df_ps = pd.read_csv(prescale_fname)
# column 4 is the highest lumi column in the CSV file
ps_col = df_ps.iloc[:,4]
if ps_select == "ps = 1": sel_ps1 = ps_col == 1 # only unprescaled
elif ps_select == "ps any": sel_ps1 = ps_col > 0 # include prescaled seeds
else: sel_ps1 = ps_col > -1 # dump even disabled seeds
ps1_idxs = df_ps[sel_ps1].Index.values
ps1_names = df_ps[sel_ps1].Name.values
# load final GT decision
decisions = uproot.concatenate({fname:treename for fname in fnames}, decision_branch)
decisions = ak.to_numpy(decisions[decision_branch])
# Build bit df
df_bits = pd.DataFrame(dict(zip(ps1_names,decisions[:,ps1_idxs].T)))
# compute total OR as sum of all columns
df_total_L1 = pd.DataFrame( {"L1_total": df_bits.sum(axis =1) > 0} )
df_bits = df_total_L1.join(df_bits)
return df_bits
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment