6 '''Script to dump trigger counts to a text file'''
14 from collections
import OrderedDict, defaultdict
16 total_events_key =
'TotalEventsProcessed'
21 from yaml.representer
import Representer
22 yaml.add_representer(defaultdict, Representer.represent_dict)
25 parser = argparse.ArgumentParser(usage=
'%(prog)s [options]',
27 parser.add_argument(
'-f',
'--inputFile',
29 default=
'expert-monitoring.root',
30 help=
'Name of input root file')
31 parser.add_argument(
'-r',
'--referenceFile',
33 help=
'Name of reference root file')
34 parser.add_argument(
'-v',
'--verbose',
36 help=
'Increase output verbosity')
37 parser.add_argument(
'-p',
'--printOnly',
40 help=
'Print counts instead of saving to file')
41 parser.add_argument(
'-d',
'--diffOnly',
44 help=
'Only store out of tolerance results (does not change JSON)')
45 parser.add_argument(
'--json',
48 const=
'chainDump.json',
49 help=
'Save outputs also to a json file with the given name or %(const)s if no name is given')
50 parser.add_argument(
'--yaml',
53 const=
'chainDump.yml',
54 help=
'Produce a small yaml file including condensed counts information for test file only '
55 '(no ref) with the given name or %(const)s if no name is given')
56 parser.add_argument(
'--yamlL1',
58 help=
'Include the L1 count information to the yaml file')
59 parser.add_argument(
'--fracTolerance',
63 help=
'Tolerance as a fraction, default = %(default)s. '
64 'Flagged diffs must exceed all tolerances')
65 parser.add_argument(
'--intTolerance',
69 help=
'Tolerance as a number of counts, default = %(default)s. '
70 'Flagged diffs must exceed all tolerances')
71 parser.add_argument(
'--countHists',
75 'HLTFramework/TrigSignatureMoni/SignatureAcceptance',
76 'HLTFramework/TrigSignatureMoni/../TrigSignatureMoni/SignatureAcceptance',
77 'HLTFramework/../HLTFramework/TrigSignatureMoni/SignatureAcceptance',
78 'TrigSteer_HLT/ChainAcceptance',
79 'TrigSteer_HLT/NumberOfActiveTEs',
80 'HLTFramework/TrigSignatureMoni/DecisionCount',
81 'CTPSimulation/L1ItemsAV',
82 'L1/CTPSimulation/output/tavById'],
83 help=
'Histograms to use for counts dump. All existing '
84 'histograms from the list are used, default = %(default)s')
85 parser.add_argument(
'--totalHists',
89 'TrigSteer_HLT/NInitialRoIsPerEvent',
90 'HLTFramework/HLTSeeding/RoIs_EM/count'],
91 help=
'Histograms to use for total events. First existing '
92 'histogram from the list is used, default = %(default)s')
93 parser.add_argument(
'--histDict',
97 'HLTFramework/TrigSignatureMoni/SignatureAcceptance:HLTChain',
98 'HLTFramework/TrigSignatureMoni/../TrigSignatureMoni/SignatureAcceptance:HLTExpress',
99 'HLTFramework/../HLTFramework/TrigSignatureMoni/SignatureAcceptance:HLTStep',
100 'TrigSteer_HLT/ChainAcceptance:HLTChain',
101 'TrigSteer_HLT/NumberOfActiveTEs:HLTTE',
102 'HLTFramework/TrigSignatureMoni/DecisionCount:HLTDecision',
103 'CTPSimulation/L1ItemsAV:L1AV',
104 'L1/CTPSimulation/output/tavById:L1AV'],
105 help=
'Dictionary defining names of output text files for each '
106 'histogram, default = %(default)s')
107 parser.add_argument(
'--printHeader',
110 help=
'Add title of columns to the output txt (just for readability)')
115 f = ROOT.TFile(file_path)
116 if f.IsOpen()
and not f.IsZombie():
124 for hist_path
in hist_paths:
125 h = root_file.Get(hist_path)
126 if not isinstance(h, ROOT.TH1):
127 logging.debug(
'Cannot open histogram %s, skipping', hist_path)
129 logging.debug(
'Loaded histogram %s', hist_path)
130 hist_dict[hist_path] = h
136 Extract {xlabel, value} dictionary from a histogram. Values are stored as integers.
137 If histogram is 2D, the y-bin labelled rowLabel is used to extract the value.
140 nbinsx = hist.GetNbinsX()
141 nbinsy = hist.GetNbinsY()
143 for bin
in range(1, nbinsy):
144 if hist.GetYaxis().GetBinLabel(bin) == rowLabel:
149 for b
in range(1, nbinsx+1):
150 label = hist.GetXaxis().GetBinLabel(b)
152 logging.debug(
'Bin %d in histogram %s has no label, skipping', b, hist.GetName())
155 value = hist.GetBinContent(b)
if hist.GetDimension() == 1
else hist.GetBinContent(b, outputRow
or nbinsy)
156 counts[label] =
int(value)
162 Extract {xlabel_ylabel, value} dictionary from a histogram. Values are stored as integers.
164 nbinsx = hist.GetNbinsX()
165 nbinsy = hist.GetNbinsY()
167 for x
in range(1, nbinsx+1):
168 label = hist.GetXaxis().GetBinLabel(x)
170 logging.debug(
'Bin %d in histogram %s has no label, skipping', x, hist.GetName())
173 for y
in range(3, nbinsy):
174 rowName = hist.GetYaxis().GetBinLabel(y)
176 if rowName
in [
'Input',
'AfterPS',
'Output',
'Express']:
178 name = label +
'_' + rowName
179 name = name.replace(
' ',
'')
180 value = hist.GetBinContent(x, y)
181 counts[name] =
int(value)
186 counts = OrderedDict()
187 all_keys =
set(in_counts.keys())
188 all_keys.update(ref_counts.keys())
189 keys_sorted =
sorted(all_keys)
190 for k
in keys_sorted:
191 v = in_counts[k]
if k
in in_counts
else 'n/a'
192 ref_v = ref_counts[k]
if k
in ref_counts
else 'n/a'
203 for kv
in name_dict_as_list:
204 kv_split = kv.split(
':')
205 if len(kv_split) < 2:
207 name_dict[kv_split[0]] = kv_split[1]
212 if hist_name
in name_dict.keys():
213 return name_dict[hist_name]
215 return hist_name.replace(
'/',
'_')
218 def count_diff(count_in, count_ref, total_in, total_ref, thr_frac, thr_num):
220 count_in_norm = (count_in /
float(total_in)) * total_ref
221 frac = count_in_norm /
float(count_ref)
if count_ref != 0
else None
223 num_diff = abs(count_in_norm - count_ref) > thr_num
224 frac_diff = abs(frac - 1.0) > thr_frac
if frac
else True
226 return num_diff
and frac_diff
231 in_total = json_dict[total_events_key][
'count']
232 ref_total = json_dict[total_events_key][
'ref_count']
233 for text_name
in sorted(json_dict.keys()):
234 if text_name == total_events_key:
239 for item_name, item_counts
in json_dict[text_name][
'counts'].
items():
240 v = item_counts[
'count']
241 ref_v = item_counts[
'ref_count']
243 missing_val.append([item_name, v, ref_v])
244 item_counts[
'ref_diff'] =
True
246 missing_ref.append([item_name, v, ref_v])
247 item_counts[
'ref_diff'] =
True
248 elif count_diff(v, ref_v, in_total, ref_total, thr_frac, thr_num):
249 diff_val.append([item_name, v, ref_v])
250 item_counts[
'ref_diff'] =
True
252 item_counts[
'ref_diff'] =
False
254 if len(diff_val) > 0:
257 [
' {e[0]:{nw}s} {e[1]:>{w}d} {e[2]:>{w}d}'.
format(
258 e=element, nw=name_width, w=column_width)
for element
in diff_val])
259 logging.info(
'%s has %d item(s) out of tolerance:\n%s',
260 text_name, len(diff_val), dump)
261 if (len(missing_ref)) > 0:
263 dump =
'\n'.
join([
' {e[0]:s}'.
format(e=element)
for element
in missing_ref])
264 logging.info(
'%s has %d item(s) missing in the reference:\n%s',
265 text_name, len(missing_ref), dump)
266 if (len(missing_val)) > 0:
268 dump =
'\n'.
join([
' {e[0]:s}'.
format(e=element)
for element
in missing_val])
269 logging.info(
'%s has %d item(s) missing with respect to the reference:\n%s',
270 text_name, len(missing_val), dump)
272 logging.info(
'%s is matching the reference', text_name)
280 for text_name
in json_dict.keys():
281 if text_name == total_events_key:
282 logging.info(
'%s: %d', text_name, json_dict[text_name][
'count'])
284 hist_name = json_dict[text_name][
'hist_name']
285 counts = json_dict[text_name][
'counts']
287 for item_counts
in counts.values():
288 if item_counts[
'ref_count'] !=
'n/a':
292 for item_name, item_counts
in counts.items():
293 v = item_counts[
'count']
294 line =
' {name:{nw}s} {val:>{w}s}'.
format(name=item_name, val=
str(v), nw=name_width, w=column_width)
296 ref_v = item_counts[
'ref_count']
297 diff = item_counts[
'ref_diff']
298 line +=
' {val:>{w}s}'.
format(val=
str(ref_v), w=column_width)
300 line +=
' <<<<<<<<<<'
301 dump_lines.append(line)
302 logging.info(
'Writing %s counts from histogram %s:\n%s', text_name, hist_name,
'\n'.
join(dump_lines))
306 if type(count)
is int:
307 return '{val:>{w}d}'.
format(val=count, w=column_width)
308 elif type(count)
is not str:
309 logging.error(
'Unexpected count type %s',
type(count))
313 return '{val:>{w}s}'.
format(val=count, w=column_width)
317 for text_name
in sorted(json_dict.keys()):
318 if text_name == total_events_key:
319 logging.info(
'Writing total event count to file %s.txt', text_name)
320 with open(
'{:s}.txt'.
format(text_name),
'w')
as outfile:
321 outfile.write(
'{:d}\n'.
format(json_dict[text_name][
'count']))
323 hist_name = json_dict[text_name][
'hist_name']
324 logging.info(
'Writing counts from histogram %s to file %s.txt', hist_name, text_name)
325 counts = json_dict[text_name][
'counts']
327 for item_counts
in counts.values():
328 if item_counts[
'ref_count'] !=
'n/a':
331 with open(
'{:s}.txt'.
format(text_name),
'w')
as outfile:
333 line =
'{name:{nw}s}'.
format(name=
'chain', nw=name_width)
335 line +=
'{name:{cw}s}'.
format(name=
'test', cw=column_width) +
'ref \n'
339 for item_name, item_counts
in counts.items():
340 v = item_counts[
'count']
343 ref_v = item_counts[
'ref_count']
344 diff = item_counts[
'ref_diff']
347 line +=
' <<<<<<<<<<'
351 outfile.write(line+
'\n')
356 light_dict = defaultdict(
lambda: defaultdict(
lambda: defaultdict(int)))
358 def extract_steps(in_name, out_name):
359 for name,c
in full_dict[in_name][
'counts'].
items():
362 chain_name, chain_step = name.split(
'_Step')
363 light_dict[chain_name][out_name][
int(chain_step)] = c[
'count']
366 for chain_name
in light_dict.keys():
367 steps = light_dict[chain_name][out_name]
368 light_dict[chain_name][out_name] = {i:steps[k]
for i,k
in enumerate(
sorted(steps.keys()))}
370 extract_steps(
'HLTStep',
'stepCounts')
371 extract_steps(
'HLTDecision',
'stepFeatures')
374 for chain_name,c
in full_dict[
'HLTChain'][
'counts'].
items():
375 light_dict[chain_name][
'eventCount'] = c[
'count']
377 if any(chain_name.startswith(s)
for s
in [
'All',
'grp_',
'str_']):
378 del light_dict[chain_name]
380 if includeL1Counts
and 'L1AV' in full_dict:
382 {name:{
"eventCount": counts[
"count"]}
for name,counts
in full_dict[
"L1AV"][
"counts"].
items()}
390 logging.basicConfig(stream=sys.stdout,
391 format=
'%(levelname)-8s %(message)s',
392 level=logging.DEBUG
if args.verbose
else logging.INFO)
402 logging.error(
'Failed to open input file %s', args.inputFile)
404 logging.debug(
'Opened input file %s', args.inputFile)
406 if args.referenceFile:
409 logging.error(
'Failed to open input file %s', args.referenceFile)
411 logging.debug(
'Opened input file %s', args.referenceFile)
418 if len(in_hists) == 0:
419 logging.error(
'No count histograms could be loaded.')
421 logging.info(
'Loaded count histograms: %s',
sorted(in_hists.keys()))
424 if len(in_total_hists) == 0:
425 logging.error(
'No total-events histogram could be loaded')
427 items =
list(in_total_hists.items())
429 logging.info(
'Loaded total-events histogram %s, number of events: %d',
430 items[0][0], in_total)
433 ref_total_hists =
None
435 if args.referenceFile:
437 logging.info(
'Loaded reference count histograms: %s',
sorted(ref_hists.keys()))
438 missing_refs = [k
for k
in in_hists.keys()
if k
not in ref_hists.keys()]
439 if len(missing_refs) > 0:
440 logging.error(
'Count histogram(s) %s missing in the reference', missing_refs)
443 if len(ref_total_hists) == 0:
444 logging.error(
'No total-events reference histogram could be loaded')
447 logging.info(
'Loaded total-events reference histogram %s, number of events: %d',
448 list(ref_total_hists.keys())[0], ref_total)
454 json_dict = OrderedDict()
455 json_dict[total_events_key] = OrderedDict()
456 json_dict[total_events_key][
'hist_name'] =
list(in_total_hists.keys())[0]
457 json_dict[total_events_key][
'count'] =
int(in_total)
458 json_dict[total_events_key][
'ref_count'] =
int(ref_total)
if ref_total
else 'n/a'
460 for hist_name, hist
in in_hists.items():
462 if text_name
in json_dict.keys():
464 'Name "%s" assigned to more than one histogram, ', text_name,
465 'results would be overwritten. Use --countHists and ',
466 '--histDict options to avoid duplicates. Exiting.')
468 rowLabel =
'Express' if 'Express' in text_name
else 'Output'
472 ref_hist = ref_hists[hist_name]
473 ref_counts =
get_2D_counts(ref_hist)
if text_name
in [
'HLTStep',
'HLTDecision']
else get_counts(ref_hist, rowLabel)
476 json_dict[text_name] = OrderedDict()
477 json_dict[text_name][
'hist_name'] = hist_name
478 json_dict[text_name][
'counts'] = d
485 if args.referenceFile:
486 logging.info(
'Comparing counts to reference')
487 retcode =
compare_ref(json_dict, args.fracTolerance, args.intTolerance)
489 if args.printOnly
and not args.diffOnly:
490 logging.info(
'Printing counts instead of dumping to files because of --printOnly option')
493 if not args.printOnly:
497 logging.info(
'Writing results to %s', args.json)
498 with open(args.json,
'w')
as outfile:
499 json.dump(json_dict, outfile, sort_keys=
True)
502 logging.info(
'Writing results extract to %s', args.yaml)
504 with open(args.yaml,
'w')
as outfile:
505 yaml.dump(light_dict, outfile, sort_keys=
True)
510 if '__main__' in __name__: