Belle II Software  release-05-01-25
b2hlt_print_result.py
1 #!/usr/bin/env python3
2 from ROOT import PyConfig
3 PyConfig.IgnoreCommandLineOptions = True
4 PyConfig.StartGuiThread = False
5 
6 import basf2
7 from argparse import ArgumentParser
8 from root_pandas import read_root
9 import pandas as pd
10 import numpy as np
11 
12 
13 if __name__ == "__main__":
14  parser = ArgumentParser(description="Print the results of the SoftwareTrigger decision for a certain file.")
15  parser.add_argument(
16  "input",
17  help="Input file name (where to read the events from). "
18  "If omitted, just use the already produced result by another SoftwareTriggerResultPrinter execution",
19  default="",
20  nargs="?")
21  parser.add_argument("--output", help="Output file name (will be used internally). "
22  "Defaults to trigger_results.root.",
23  default="software_trigger_results.root")
24  choices = ["list", "categorized"]
25  try:
26  from tabulate import tabulate
27  choices += ['jira', 'grid', 'stash']
28  except ImportError:
29  pass
30 
31  parser.add_argument("--format", help="Choose the format how to print the trigger cuts. "
32  "To get access to more options please install the tabulate package using pip",
33  choices=choices, default="categorized")
34  parser.add_argument("--override-globaltags", dest="override", action="store_true", default=False,
35  help="Use this option in case the data file does not provide globaltag information. "
36  "The only case where this should occur is when analyzing raw data.")
37  parser.add_argument('--local-db-path', type=str,
38  help="set path to the local payload locations to use for the ConditionDB",
39  default=None)
40 
41  args = parser.parse_args()
42 
43  if args.input:
44  # For data, the prescales are only valid when using the online database!
45  basf2.reset_database()
46  if args.local_db_path is not None:
47  basf2.conditions.metadata_providers = ["file://" + basf2.find_file(args.local_db_path + "/metadata.sqlite")]
48  basf2.conditions.payload_locations = [basf2.find_file(args.local_db_path)]
49 
50  if args.override:
51  basf2.conditions.override_globaltags(["online"])
52 
53  path = basf2.Path()
54 
55  if args.input.endswith(".sroot"):
56  path.add_module("SeqRootInput", inputFileName=args.input)
57  else:
58  path.add_module("RootInput", inputFileName=args.input)
59  path.add_module("SoftwareTriggerResultPrinter", outputFileName=args.output)
60 
61  basf2.process(path)
62 
63  df = read_root(args.output)
64 
65  # Make sure to cope with strings rather than bools (which is a bit strange in pandas)
66  df[["accept_or_reject", "prescaled", "cut"]] = df[["accept_or_reject", "prescaled", "cut"]].astype("str")
67 
68  # Group and order as we need it
69  df = df.set_index(["cut", "accept_or_reject", "prescaled"]).T
70  df.index = df.index.str.replace("software_trigger_cut_", "")
71  df.index = df.index.str.replace("_", " ")
72 
73  # Separate cuts and prescaling
74  df_prescales = df["False"].copy()
75  df_cuts = df["True"].copy()
76 
77  # For the prescaling, the total_events is nonsense...
78  df_prescales.loc["total events"] = np.NAN
79 
80  # Now also separate out only the accepted results
81  df_cuts = df_cuts["True"].copy()
82 
83  # Give the columns some meaningful names
84  df_cuts = df_cuts[["True", "False"]]
85  df_cuts.columns = ["Prescaled", "Non Prescaled"]
86 
87  # Make sure to print all information
88  pd.set_option("display.max_rows", 500)
89  pd.set_option("display.max_colwidth", 200)
90  pd.set_option('display.max_columns', 500)
91  pd.set_option('display.width', 1000)
92 
93  # Function used for formatting
94  def format(x, total_events):
95  if np.isnan(x):
96  return ""
97  return f"{int(x):d} ({x/total_events:7.2%})"
98 
99  # Create a new dataframe just for printing
100  df_print = pd.DataFrame(index=df_cuts.index)
101 
102  df_print["Prescaled"] = df_cuts["Prescaled"].apply(lambda x: format(x, df_cuts["Prescaled"]["total events"]))
103  df_print["Non Prescaled"] = df_cuts["Non Prescaled"].apply(lambda x: format(x, df_cuts["Non Prescaled"]["total events"]))
104  df_print["Prescales"] = df_prescales.fillna("")
105  df_print = df_print[["Prescaled", "Non Prescaled", "Prescales"]]
106 
107  if args.format == "list":
108  print(df_print)
109  elif args.format == "categorized":
110  from softwaretrigger import filter_categories
111 
112  def local_print_function(title, categories):
113  empty_row = {key: "" for key in df_print.columns}
114  tmp = pd.DataFrame(columns=df_print.columns)
115  tmp = tmp.append(pd.Series(empty_row, name=title))
116  tmp = tmp.append(df_print.reindex(categories))
117  tmp = tmp.append(pd.Series(empty_row, name=""))
118 
119  return tmp
120 
121  df_sorted = pd.concat([
122  local_print_function("Overview", filter_categories.RESULTS),
123  local_print_function("ECL - Physics", filter_categories.ECL_PHYSICS),
124  local_print_function("ECL - Potentially Prescaled", filter_categories.ECL_PRESCALED),
125  local_print_function("CDC - Physics", filter_categories.CDC_PHYSICS),
126  local_print_function("CDC - Potentially Prescaled", filter_categories.CDC_PRESCALED),
127  local_print_function("Targeted Physics Lines", filter_categories.PHYSICS),
128  local_print_function("QED / Control Samples", filter_categories.QED),
129  local_print_function("Level 1 Passthrough ", filter_categories.LEVEL1),
130  local_print_function("Prescaled Vetoes", filter_categories.VETOES),
131  local_print_function("Skims", [index for index in df_print.index if index.startswith("skim ")]),
132  ])
133 
134  remaining_columns = set(df_print.index) - set(df_sorted.index)
135  if remaining_columns:
136  df_sorted = df_sorted.append(local_print_function("Uncategorized", remaining_columns))
137 
138  print(df_sorted)
139 
140  elif args.format == "jira":
141  print(tabulate(df_print, tablefmt="jira", showindex=True, headers="keys"))
142  elif args.format == "stash":
143  print(tabulate(df_print, tablefmt="pipe", showindex=True, headers="keys"))
144  elif args.format == "grid":
145  print(tabulate(df_print, tablefmt="grid", showindex=True, headers="keys"))
basf2.process
def process(path, max_event=0)
Definition: __init__.py:25