3 from __future__
import print_function
5 ROOT.PyConfig.IgnoreCommandLineOptions =
True
10 from DQMServices.FileIO.blacklist
import get_blacklist
11 import multiprocessing
13 def create_dif(base_file_path, pr_file_path, pr_number, test_number, cmssw_version, num_processes, 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 = []
55 print(
"starting comparison using %d process(es)" % num_processes)
56 manager = multiprocessing.Manager()
57 return_dict = manager.dict()
61 block = len(shared_paths)//num_processes
62 for i
in range(num_processes):
63 p = multiprocessing.Process(target=compareMP, args=(shared_paths[i*block:(i+1)*block], pr_flat_dict, base_flat_dict, i, return_dict))
67 p = multiprocessing.Process(target=compareMP, args=(shared_paths[(i+1)*block:len(shared_paths)], pr_flat_dict, base_flat_dict, num_processes, return_dict))
72 for i
in range(iProc):
74 paths_to_save_in_pr.extend(return_dict[i][
'pr'])
75 paths_to_save_in_base.extend(return_dict[i][
'base'])
77 paths_to_save_in_pr.sort()
78 paths_to_save_in_base.sort()
81 compare(shared_paths, pr_flat_dict, base_flat_dict, paths_to_save_in_pr, paths_to_save_in_base)
84 for path
in only_base_paths:
85 item = base_flat_dict[path]
90 paths_to_save_in_base.append(path)
93 for path
in only_pr_paths:
94 item = pr_flat_dict[path]
99 paths_to_save_in_pr.append(path)
101 base_output_filename =
get_output_filename(pr_file_path, pr_number, test_number, cmssw_version,
False)
102 pr_output_filename =
get_output_filename(pr_file_path, pr_number, test_number, cmssw_version,
True)
105 save_paths(base_flat_dict, paths_to_save_in_base, os.path.join(output_dir_path,
'base', base_output_filename))
108 save_paths(pr_flat_dict, paths_to_save_in_pr, os.path.join(output_dir_path,
'pr', pr_output_filename))
114 nr_of_changed_elements = len(set(paths_to_save_in_base).
intersection(set(paths_to_save_in_pr)))
115 nr_of_removed_elements = len(paths_to_save_in_base) - nr_of_changed_elements
116 nr_of_added_elements = len(paths_to_save_in_pr) - nr_of_changed_elements
118 print(
'Base output file. PR output file. Changed elements, removed elements, added elements:')
119 print(base_output_filename)
120 print(pr_output_filename)
121 print(
'%s %s %s' % (nr_of_changed_elements, nr_of_removed_elements, nr_of_added_elements))
123 def compareMP(shared_paths, pr_flat_dict, base_flat_dict, iProc, return_dict):
125 comparisons = {
'pr': [],
'base': []}
128 for path
in shared_paths:
129 pr_item = pr_flat_dict[path]
130 base_item = base_flat_dict[path]
132 if pr_item ==
None or base_item ==
None:
137 if pr_item.InheritsFrom(
'TProfile2D')
and base_item.InheritsFrom(
'TProfile2D'):
141 elif pr_item.InheritsFrom(
'TProfile')
and base_item.InheritsFrom(
'TProfile'):
145 elif pr_item.InheritsFrom(
'TH1')
and base_item.InheritsFrom(
'TH1'):
147 pr_array = np.array(pr_item)
148 base_array = np.array(base_item)
150 if pr_array.shape != base_array.shape
or not np.allclose(pr_array, base_array, equal_nan=
True):
154 if pr_item != base_item:
158 comparisons[
'pr'].
append(path)
159 comparisons[
'base'].
append(path)
160 return_dict[iProc] = comparisons
162 def compare(shared_paths, pr_flat_dict, base_flat_dict, paths_to_save_in_pr, paths_to_save_in_base):
164 for path
in shared_paths:
165 pr_item = pr_flat_dict[path]
166 base_item = base_flat_dict[path]
168 if pr_item ==
None or base_item ==
None:
173 if pr_item.InheritsFrom(
'TProfile2D')
and base_item.InheritsFrom(
'TProfile2D'):
177 elif pr_item.InheritsFrom(
'TProfile')
and base_item.InheritsFrom(
'TProfile'):
181 elif pr_item.InheritsFrom(
'TH1')
and base_item.InheritsFrom(
'TH1'):
183 pr_array = np.array(pr_item)
184 base_array = np.array(base_item)
186 if pr_array.shape != base_array.shape
or not np.allclose(pr_array, base_array, equal_nan=
True):
190 if pr_item != base_item:
194 paths_to_save_in_pr.append(path)
195 paths_to_save_in_base.append(path)
199 if pr_item.GetSize() != base_item.GetSize():
202 for i
in range(pr_item.GetSize()):
203 pr_bin_content = pr_item.GetBinContent(i)
204 base_bin_content = base_item.GetBinContent(i)
206 pr_bin_entries = pr_item.GetBinEntries(i)
207 base_bin_entries = base_item.GetBinEntries(i)
209 pr_bin_error = pr_item.GetBinError(i)
210 base_bin_error = base_item.GetBinError(i)
212 if not np.isclose(pr_bin_content, base_bin_content, equal_nan=
True):
215 if not np.isclose(pr_bin_entries, base_bin_entries, equal_nan=
True):
218 if not np.isclose(pr_bin_error, base_bin_error, equal_nan=
True):
225 for key
in file.GetListOfKeys():
235 if hasattr(node,
'GetListOfKeys'):
236 for key
in node.GetListOfKeys():
240 path = tuple(new_dir_list)
244 if node.InheritsFrom(
'TObjString'):
246 name = node.GetName().
split(
'>')[0][1:]
249 return node.GetName()
252 return '_string_monitor_element'
256 dirs_list = dirs_list[:]
265 print(
'No differences were observed - output will not be written', file=sys.stderr)
269 result_dir = os.path.dirname(result_file_path)
270 if not os.path.exists(result_dir):
271 os.makedirs(result_dir)
273 result_file = ROOT.TFile(result_file_path,
'recreate')
274 ROOT.gROOT.GetListOfFiles().Remove(result_file)
276 if not result_file.IsOpen():
277 print(
'Unable to open %s output file' % result_file_path, file=sys.stderr)
284 print(
'Output written to %s file' % result_file_path, file=sys.stderr)
288 histogram = flat_dict[path]
290 current = output_file
293 for directory
in path[:-1]:
301 dir = parent_dir.Get(name)
303 dir = parent_dir.mkdir(name)
312 input_file_name = os.path.basename(input_file_path)
314 run = input_file_name.split(
'_')[2]
315 workflow = os.path.basename(os.path.dirname(input_file_path)).
split(
'_')[0].
replace(
'.',
'_')
320 if run ==
'R000000001':
321 relval_prefix =
'RelVal_'
327 return 'DQM_V0001_%s__%swf%s_%s__%s-PR%s-%s__DQMIO.root' % (run, relval_prefix, workflow, baseOrPr, cmssw_version, pr_number, test_number)
330 return os.path.basename(file_path).
split(
'_')[2].lstrip(
'R').lstrip('0')
332 if __name__ ==
'__main__':
333 parser = argparse.ArgumentParser(description=
"This tool compares DQM monitor elements found in base-file with the ones found in pr-file."
334 "Comparison is done bin by bin and output is written to a root file containing only the changes.")
335 parser.add_argument(
'-b',
'--base-file', help=
'Baseline IB DQM root file', required=
True)
336 parser.add_argument(
'-p',
'--pr-file', help=
'PR DQM root file', required=
True)
337 parser.add_argument(
'-n',
'--pr-number', help=
'PR number under test', default=
'00001')
338 parser.add_argument(
'-t',
'--test-number', help=
'Unique test number to distinguish different comparisons of the same PR.', default=
'1')
339 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'])
340 parser.add_argument(
'-j',
'--num-processes', help=
'Number of processes forked to parallel process the comparison', default=1, type=int)
341 parser.add_argument(
'-o',
'--output-dir', help=
'Comparison root files output directory', default=
'dqmHistoComparisonOutput')
342 args = parser.parse_args()
344 cmssw_version =
'_'.
join(args.release_format.split(
'_')[:4])
346 create_dif(args.base_file, args.pr_file, args.pr_number, args.test_number, cmssw_version, args.num_processes, args.output_dir)
boost::dynamic_bitset append(const boost::dynamic_bitset<> &bs1, const boost::dynamic_bitset<> &bs2)
this method takes two bitsets bs1 and bs2 and returns result of bs2 appended to the end of bs1 ...
const uint16_t range(const Frame &aFrame)
double intersection(double r12)
void print(TMatrixD &m, const char *label=nullptr, bool mathematicaFormat=false)
static std::string join(char **cmd)