Belle II Software  release-08-00-04
fullTrackingTableValidationAnalyseData.py
1 #!/usr/bin/env python3
2 
3 
10 
11 """
12 <header>
13  <contact>software-tracking@belle2.org</contact>
14  <output>fullTrackingValidationTable.root</output>
15  <input>matching_validation.root</input>
16  <description>This module generates events for the validation using the full tracking with a tabular output.</description>
17 </header>
18 """
19 import basf2
20 from ROOT import TFile, TNamed
21 import os
22 
23 VALIDATION_OUTPUT_FILE = "fullTrackingTableValidation.root"
24 
25 try:
26  import uproot # noqa
27  import pandas as pd # noqa
28 except ImportError:
29  basf2.B2FATAL("You need to have pandas installed for this validation script to run.")
30 
31 FORMAT_STRING = "&nbsp;{:.2%} <br/> -{:.2%} <br/> <b>-{:.2%}</b> <br/> Matching: {:.2%} <br/> CDC: {:.2%} <br/> VXD: {:.2%}"
32 SHORT_FORMAT_STRING = "MC: &nbsp;{:.2%} <br/>Missing: -{:.2%} <br/>Missing and !fit: <b>-{:.2%}</b>"
33 
34 
35 def reducelist(list_of_cuts, df, current_name=None, current_cut=None, x=0, y=0):
36  if current_name is not None:
37  if y == 5:
38  return_string = FORMAT_STRING.format(current_cut.mean(),
39  (current_cut & (df.is_matched == 0)).mean(),
40  (current_cut & (df.fitted_is_matched == 0)).mean(),
41  (current_cut & (df.both_related == 1)).mean(),
42  (current_cut & (df.cdc_has_related == 1)).mean(),
43  (current_cut & (df.vxd_has_related == 1)).mean())
44  else:
45  return_string = SHORT_FORMAT_STRING.format(current_cut.mean(),
46  (current_cut & (df.is_matched == 0)).mean(),
47  (current_cut & (df.fitted_is_matched == 0)).mean())
48  yield (y, x, current_name), return_string
49 
50  if not list_of_cuts:
51  return
52 
53  name, cut = list_of_cuts[0]
54 
55  if cut is None:
56  # Make a "always true" cut
57  def cut(x):
58  return x.is_missing == x.is_missing
59 
60  if current_name is None:
61  yield from reducelist(list_of_cuts[1:], df, name, cut(df),
62  x + 2 ** (len(list_of_cuts) - 1), y + 1)
63  else:
64  yield from reducelist(list_of_cuts[1:], df, current_name + "_no_" + name, current_cut & (~cut(df)),
65  x, y + 1)
66  yield from reducelist(list_of_cuts[1:], df, current_name + "_" + name, current_cut & (cut(df)),
67  x + 2 ** (len(list_of_cuts) - 1), y + 1)
68 
69 
70 def make_chunks(k, n):
71  return [k[i:i + n] for i in range(0, len(k), n)]
72 
73 
74 def write_value_cell(key, value):
75  y, x, name, _ = key
76  colspan = 2 ** int(5 - y)
77 
78  colors = {
79  3: ["white", "gray", "orange", "green"],
80  4: ["gray", "white", "gray", "gray",
81  "orange", "orange", "green", "green"],
82  5: ["gray", "gray", "red", "green",
83  "gray", "gray", "gray", "gray",
84  "red", "gray", "red", "orange",
85  "green", "gray", "orange", "green"]
86  }
87 
88  if y in colors:
89  color_index = int((x - 2 ** 4) / (2 ** (5 - y)))
90  color = colors[y][color_index]
91  else:
92  color = "white"
93 
94  return """
95  <td style="border: 1px solid black" colspan={colspan}
96  align="center" valign=middle bgcolor="{color}">{value}</td>
97  """.format(colspan=colspan, color=color, value=value)
98 
99 
100 def make_html_row(x):
101  keys = [key for key, _ in x.iteritems()]
102  titles = [key[2] for key, _ in x.iteritems()]
103 
104  chunked_titles = make_chunks(titles, 2)
105  common_prefixes = list(map(os.path.commonprefix, chunked_titles))
106 
107  shorter_titles = [title.replace(prefix, "").replace("_", " ")
108  for list_titles, prefix in zip(chunked_titles, common_prefixes)
109  for title in list_titles]
110 
111  row_content = "".join([write_value_cell(key, value) for key, value in zip(keys, shorter_titles)])
112  html = "<tr>" + row_content + "</tr>"
113 
114  row_content = "".join([write_value_cell(key, value) for key, value in x.sort_index().iteritems()])
115  html += "<tr>" + row_content + "</tr>"
116 
117  return html
118 
119 
120 def get_html(df, test):
121  results = pd.DataFrame(dict(reducelist(test, df)), index=[0]).unstack()
122 
123  last_row_titles = ["", "", "CDCTF may help", "Criteria?", "", "", "", "", "VXDTF may help", "",
124  "hard cases", "CKF may help", "Criteria?", "", "CKF may help", "Merging"]
125 
126  html = "<table>"
127  html += "".join(results.groupby(level=0).apply(make_html_row))
128  html += "<tr>" + ("".join(["<td>" + value + "</td>" for value in last_row_titles])) + "</tr>"
129  html += "</table>"
130 
131  return html
132 
133 
134 if __name__ == '__main__':
135  # These are the categories to be tested successively
136  test = [
137  ("all", None),
138  ("has_vxd", lambda x: (x.n_svd_hits >= 2)),
139  ("vxd_was_found", lambda x: x["vxd_was_found"] == 1),
140  ("has_cdc", lambda x: x.n_cdc_hits >= 3),
141  ("cdc_was_found", lambda x: x["cdc_was_found"] == 1),
142  ]
143 
144  df = uproot.open("../matching_validation.root")['VxdCdcPartFinderHarvester_tree'].arrays(library='pd')
145  html = get_html(df, test)
146 
147  tfile = TFile(VALIDATION_OUTPUT_FILE, "RECREATE")
148  html_content = TNamed("Tracking Table Validation", html)
149  html_content.Write()
150  tfile.Close()