3 from __future__
import print_function
5 ROOT.PyConfig.IgnoreCommandLineOptions =
True
11 from DQMServices.FileIO.blacklist
import get_blacklist
13 def create_dif(base_file_path, pr_file_path, pr_number, test_number, cmssw_version, output_dir_path):
14 base_file = ROOT.TFile(base_file_path,
'read')
15 ROOT.gROOT.GetListOfFiles().Remove(base_file)
17 pr_file = ROOT.TFile(pr_file_path,
'read')
18 ROOT.gROOT.GetListOfFiles().Remove(pr_file)
20 if base_file.IsOpen():
21 print(
'Baseline file successfully opened', file=sys.stderr)
23 print(
'Unable to open base file', file=sys.stderr)
27 print(
'PR file successfully opened', file=sys.stderr)
29 print(
'Unable to open PR file', file=sys.stderr)
39 shared_paths = list(set(pr_flat_dict).
intersection(set(base_flat_dict)))
42 only_pr_paths = list(set(pr_flat_dict).difference(set(base_flat_dict)))
45 only_base_paths = list(set(base_flat_dict).difference(set(pr_flat_dict)))
48 paths_to_save_in_base = []
51 paths_to_save_in_pr = []
54 compare(shared_paths, pr_flat_dict, base_flat_dict, paths_to_save_in_pr, paths_to_save_in_base)
57 for path
in only_base_paths:
58 item = base_flat_dict[path]
63 paths_to_save_in_base.append(path)
66 for path
in only_pr_paths:
67 item = pr_flat_dict[path]
72 paths_to_save_in_pr.append(path)
74 base_output_filename =
get_output_filename(pr_file_path, pr_number, test_number, cmssw_version,
False)
75 pr_output_filename =
get_output_filename(pr_file_path, pr_number, test_number, cmssw_version,
True)
78 save_paths(base_flat_dict, paths_to_save_in_base, os.path.join(output_dir_path,
'base', base_output_filename))
81 save_paths(pr_flat_dict, paths_to_save_in_pr, os.path.join(output_dir_path,
'pr', pr_output_filename))
87 nr_of_changed_elements = len(set(paths_to_save_in_base).
intersection(set(paths_to_save_in_pr)))
88 nr_of_removed_elements = len(paths_to_save_in_base) - nr_of_changed_elements
89 nr_of_added_elements = len(paths_to_save_in_pr) - nr_of_changed_elements
91 print(
'Base output file. PR output file. Changed elements, removed elements, added elements:')
92 print(base_output_filename)
93 print(pr_output_filename)
94 print(
'%s %s %s' % (nr_of_changed_elements, nr_of_removed_elements, nr_of_added_elements))
96 def compare(shared_paths, pr_flat_dict, base_flat_dict, paths_to_save_in_pr, paths_to_save_in_base):
98 for path
in shared_paths:
99 pr_item = pr_flat_dict[path]
100 base_item = base_flat_dict[path]
102 if pr_item ==
None or base_item ==
None:
107 if pr_item.InheritsFrom(
'TProfile2D')
and base_item.InheritsFrom(
'TProfile2D'):
111 elif pr_item.InheritsFrom(
'TProfile')
and base_item.InheritsFrom(
'TProfile'):
115 elif pr_item.InheritsFrom(
'TH1')
and base_item.InheritsFrom(
'TH1'):
117 pr_array = root_numpy.hist2array(hist=pr_item, include_overflow=
True, copy=
False)
118 base_array = root_numpy.hist2array(hist=base_item, include_overflow=
True, copy=
False)
120 if pr_array.shape != base_array.shape
or not np.allclose(pr_array, base_array, equal_nan=
True):
124 if pr_item != base_item:
128 paths_to_save_in_pr.append(path)
129 paths_to_save_in_base.append(path)
133 if pr_item.GetSize() != base_item.GetSize():
136 for i
in range(pr_item.GetSize()):
137 pr_bin_content = pr_item.GetBinContent(i)
138 base_bin_content = base_item.GetBinContent(i)
140 pr_bin_entries = pr_item.GetBinEntries(i)
141 base_bin_entries = base_item.GetBinEntries(i)
143 pr_bin_error = pr_item.GetBinError(i)
144 base_bin_error = base_item.GetBinError(i)
146 if not np.isclose(pr_bin_content, base_bin_content, equal_nan=
True):
149 if not np.isclose(pr_bin_entries, base_bin_entries, equal_nan=
True):
152 if not np.isclose(pr_bin_error, base_bin_error, equal_nan=
True):
159 for key
in file.GetListOfKeys():
169 if hasattr(node,
'GetListOfKeys'):
170 for key
in node.GetListOfKeys():
174 path = tuple(new_dir_list)
178 if node.InheritsFrom(
'TObjString'):
180 name = node.GetName().
split(
'>')[0][1:]
183 return node.GetName()
186 return '_string_monitor_element'
190 dirs_list = dirs_list[:]
199 print(
'No differences were observed - output will not be written', file=sys.stderr)
203 result_dir = os.path.dirname(result_file_path)
204 if not os.path.exists(result_dir):
205 os.makedirs(result_dir)
207 result_file = ROOT.TFile(result_file_path,
'recreate')
208 ROOT.gROOT.GetListOfFiles().Remove(result_file)
210 if not result_file.IsOpen():
211 print(
'Unable to open %s output file' % result_file_path, file=sys.stderr)
218 print(
'Output written to %s file' % result_file_path, file=sys.stderr)
222 histogram = flat_dict[path]
224 current = output_file
227 for directory
in path[:-1]:
235 dir = parent_dir.Get(name)
237 dir = parent_dir.mkdir(name)
246 input_file_name = os.path.basename(input_file_path)
248 run = input_file_name.split(
'_')[2]
249 workflow = os.path.basename(os.path.dirname(input_file_path)).
split(
'_')[0].
replace(
'.',
'_')
254 if run ==
'R000000001':
255 relval_prefix =
'RelVal_'
261 return 'DQM_V0001_%s__%swf%s_%s__%s-PR%s-%s__DQMIO.root' % (run, relval_prefix, workflow, baseOrPr, cmssw_version, pr_number, test_number)
264 return os.path.basename(file_path).
split(
'_')[2].lstrip(
'R').lstrip(
'0')
266 if __name__ ==
'__main__':
267 parser = argparse.ArgumentParser(description=
"This tool compares DQM monitor elements found in base-file with the ones found in pr-file."
268 "Comparison is done bin by bin and output is written to a root file containing only the changes.")
269 parser.add_argument(
'-b',
'--base-file', help=
'Baseline IB DQM root file', required=
True)
270 parser.add_argument(
'-p',
'--pr-file', help=
'PR DQM root file', required=
True)
271 parser.add_argument(
'-n',
'--pr-number', help=
'PR number under test', default=
'00001')
272 parser.add_argument(
'-t',
'--test-number', help=
'Unique test number to distinguish different comparisons of the same PR.', default=
'1')
273 parser.add_argument(
'-r',
'--release-format', help=
'Release format in this format: CMSSW_10_5_X_2019-02-17-0000', default=os.environ[
'CMSSW_VERSION'])
274 parser.add_argument(
'-o',
'--output-dir', help=
'Comparison root files output directory', default=
'dqmHistoComparisonOutput')
275 args = parser.parse_args()
277 cmssw_version =
'_'.
join(args.release_format.split(
'_')[:4])
279 create_dif(args.base_file, args.pr_file, args.pr_number, args.test_number, cmssw_version, args.output_dir)