6 '''Script to dump trigger counts to a text file'''
14 from collections
import 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_eEM/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)
187 all_keys =
set(in_counts)
188 all_keys.update(ref_counts)
189 for k
in sorted(all_keys):
190 v = in_counts[k]
if k
in in_counts
else 'n/a'
191 ref_v = ref_counts[k]
if k
in ref_counts
else 'n/a'
202 for kv
in name_dict_as_list:
203 kv_split = kv.split(
':')
204 if len(kv_split) < 2:
206 name_dict[kv_split[0]] = kv_split[1]
211 if hist_name
in name_dict:
212 return name_dict[hist_name]
214 return hist_name.replace(
'/',
'_')
217 def count_diff(count_in, count_ref, total_in, total_ref, thr_frac, thr_num):
219 count_in_norm = (count_in /
float(total_in)) * total_ref
220 frac = count_in_norm /
float(count_ref)
if count_ref != 0
else None
222 num_diff = abs(count_in_norm - count_ref) > thr_num
223 frac_diff = abs(frac - 1.0) > thr_frac
if frac
else True
225 return num_diff
and frac_diff
230 in_total = json_dict[total_events_key][
'count']
231 ref_total = json_dict[total_events_key][
'ref_count']
232 for text_name
in sorted(json_dict):
233 if text_name == total_events_key:
238 for item_name, item_counts
in json_dict[text_name][
'counts'].
items():
239 v = item_counts[
'count']
240 ref_v = item_counts[
'ref_count']
242 missing_val.append([item_name, v, ref_v])
243 item_counts[
'ref_diff'] =
True
245 missing_ref.append([item_name, v, ref_v])
246 item_counts[
'ref_diff'] =
True
247 elif count_diff(v, ref_v, in_total, ref_total, thr_frac, thr_num):
248 diff_val.append([item_name, v, ref_v])
249 item_counts[
'ref_diff'] =
True
251 item_counts[
'ref_diff'] =
False
253 if len(diff_val) > 0:
256 [
' {e[0]:{nw}s} {e[1]:>{w}d} {e[2]:>{w}d}'.
format(
257 e=element, nw=name_width, w=column_width)
for element
in diff_val])
258 logging.info(
'%s has %d item(s) out of tolerance:\n%s',
259 text_name, len(diff_val), dump)
260 if (len(missing_ref)) > 0:
262 dump =
'\n'.
join([
' {e[0]:s}'.
format(e=element)
for element
in missing_ref])
263 logging.info(
'%s has %d item(s) missing in the reference:\n%s',
264 text_name, len(missing_ref), dump)
265 if (len(missing_val)) > 0:
267 dump =
'\n'.
join([
' {e[0]:s}'.
format(e=element)
for element
in missing_val])
268 logging.info(
'%s has %d item(s) missing with respect to the reference:\n%s',
269 text_name, len(missing_val), dump)
271 logging.info(
'%s is matching the reference', text_name)
279 for text_name
in json_dict:
280 if text_name == total_events_key:
281 logging.info(
'%s: %d', text_name, json_dict[text_name][
'count'])
283 hist_name = json_dict[text_name][
'hist_name']
284 counts = json_dict[text_name][
'counts']
286 for item_counts
in counts.values():
287 if item_counts[
'ref_count'] !=
'n/a':
291 for item_name, item_counts
in counts.items():
292 v = item_counts[
'count']
293 line =
' {name:{nw}s} {val:>{w}s}'.
format(name=item_name, val=
str(v), nw=name_width, w=column_width)
295 ref_v = item_counts[
'ref_count']
296 diff = item_counts[
'ref_diff']
297 line +=
' {val:>{w}s}'.
format(val=
str(ref_v), w=column_width)
299 line +=
' <<<<<<<<<<'
300 dump_lines.append(line)
301 logging.info(
'Writing %s counts from histogram %s:\n%s', text_name, hist_name,
'\n'.
join(dump_lines))
305 if type(count)
is int:
306 return '{val:>{w}d}'.
format(val=count, w=column_width)
307 elif type(count)
is not str:
308 logging.error(
'Unexpected count type %s',
type(count))
312 return '{val:>{w}s}'.
format(val=count, w=column_width)
316 for text_name
in sorted(json_dict):
317 if text_name == total_events_key:
318 logging.info(
'Writing total event count to file %s.txt', text_name)
319 with open(
'{:s}.txt'.
format(text_name),
'w')
as outfile:
320 outfile.write(
'{:d}\n'.
format(json_dict[text_name][
'count']))
322 hist_name = json_dict[text_name][
'hist_name']
323 logging.info(
'Writing counts from histogram %s to file %s.txt', hist_name, text_name)
324 counts = json_dict[text_name][
'counts']
326 for item_counts
in counts.values():
327 if item_counts[
'ref_count'] !=
'n/a':
330 with open(
'{:s}.txt'.
format(text_name),
'w')
as outfile:
332 line =
'{name:{nw}s}'.
format(name=
'chain', nw=name_width)
334 line +=
'{name:{cw}s}'.
format(name=
'test', cw=column_width) +
'ref \n'
338 for item_name, item_counts
in counts.items():
339 v = item_counts[
'count']
342 ref_v = item_counts[
'ref_count']
343 diff = item_counts[
'ref_diff']
346 line +=
' <<<<<<<<<<'
350 outfile.write(line+
'\n')
355 light_dict = defaultdict(
lambda: defaultdict(
lambda: defaultdict(int)))
357 def extract_steps(in_name, out_name):
358 for name,c
in full_dict[in_name][
'counts'].
items():
361 chain_name, chain_step = name.split(
'_Step')
362 light_dict[chain_name][out_name][
int(chain_step)] = c[
'count']
365 for chain_name
in light_dict:
366 steps = light_dict[chain_name][out_name]
367 light_dict[chain_name][out_name] = {i:steps[k]
for i,k
in enumerate(
sorted(steps))}
369 extract_steps(
'HLTStep',
'stepCounts')
370 extract_steps(
'HLTDecision',
'stepFeatures')
373 for chain_name,c
in full_dict[
'HLTChain'][
'counts'].
items():
374 light_dict[chain_name][
'eventCount'] = c[
'count']
376 if any(chain_name.startswith(s)
for s
in [
'All',
'grp_',
'str_']):
377 del light_dict[chain_name]
379 if includeL1Counts
and 'L1AV' in full_dict:
381 {name:{
"eventCount": counts[
"count"]}
for name,counts
in full_dict[
"L1AV"][
"counts"].
items()}
389 logging.basicConfig(stream=sys.stdout,
390 format=
'%(levelname)-8s %(message)s',
391 level=logging.DEBUG
if args.verbose
else logging.INFO)
401 logging.error(
'Failed to open input file %s', args.inputFile)
403 logging.debug(
'Opened input file %s', args.inputFile)
405 if args.referenceFile:
408 logging.error(
'Failed to open input file %s', args.referenceFile)
410 logging.debug(
'Opened input file %s', args.referenceFile)
417 if len(in_hists) == 0:
418 logging.error(
'No count histograms could be loaded.')
420 logging.info(
'Loaded count histograms: %s',
sorted(in_hists))
423 if len(in_total_hists) == 0:
424 logging.error(
'No total-events histogram could be loaded')
426 items =
list(in_total_hists.items())
428 logging.info(
'Loaded total-events histogram %s, number of events: %d',
429 items[0][0], in_total)
432 ref_total_hists =
None
434 if args.referenceFile:
436 logging.info(
'Loaded reference count histograms: %s',
sorted(ref_hists))
437 missing_refs = [k
for k
in in_hists
if k
not in ref_hists]
438 if len(missing_refs) > 0:
439 logging.error(
'Count histogram(s) %s missing in the reference', missing_refs)
442 if len(ref_total_hists) == 0:
443 logging.error(
'No total-events reference histogram could be loaded')
446 logging.info(
'Loaded total-events reference histogram %s, number of events: %d',
447 list(ref_total_hists.keys())[0], ref_total)
455 'hist_name':
list(in_total_hists.keys())[0],
456 'count':
int(in_total),
457 'ref_count':
int(ref_total)
if ref_total
else 'n/a'
461 for hist_name, hist
in in_hists.items():
463 if text_name
in json_dict:
465 'Name "%s" assigned to more than one histogram, ', text_name,
466 'results would be overwritten. Use --countHists and ',
467 '--histDict options to avoid duplicates. Exiting.')
469 rowLabel =
'Express' if 'Express' in text_name
else 'Output'
473 ref_hist = ref_hists[hist_name]
474 ref_counts =
get_2D_counts(ref_hist)
if text_name
in [
'HLTStep',
'HLTDecision']
else get_counts(ref_hist, rowLabel)
477 json_dict[text_name] = {
478 'hist_name': hist_name,
487 if args.referenceFile:
488 logging.info(
'Comparing counts to reference')
489 retcode =
compare_ref(json_dict, args.fracTolerance, args.intTolerance)
491 if args.printOnly
and not args.diffOnly:
492 logging.info(
'Printing counts instead of dumping to files because of --printOnly option')
495 if not args.printOnly:
499 logging.info(
'Writing results to %s', args.json)
500 with open(args.json,
'w')
as outfile:
501 json.dump(json_dict, outfile, sort_keys=
True)
504 logging.info(
'Writing results extract to %s', args.yaml)
506 with open(args.yaml,
'w')
as outfile:
507 yaml.dump(light_dict, outfile, sort_keys=
True)
512 if '__main__' in __name__: