ATLAS Offline Software
Loading...
Searching...
No Matches
rootcomp.py
Go to the documentation of this file.
1#!/usr/bin/env python
2#
3# Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
4# @file: rootcomp.py
5# @purpose: Script to compare the histograms in two root files
6# @author: Frank Winklmeier, Will Buttinger
7#
8import sys
9import os
10import os.path
11
12def main():
13
14 from optparse import OptionParser
15 parser = OptionParser(usage = "usage: %prog [options] reference file",
16 description = "Compare the histograms in two root files. See https://twiki.cern.ch/twiki/bin/view/Atlas/TrigValTools#rootcomp_py for more details and examples.")
17
18 parser.add_option("-c", "--chi2",
19 action = "store_true",
20 help = "use chi2 comparison instead of bin-by-bin")
21
22 parser.add_option("-a", "--axis",
23 action = "store_true",
24 help = "use axis comparison instead of bin-by-bin")
25
26 parser.add_option("-l", "--sortLabels",
27 action = "store_true", default=False,
28 help = "sort/deflate alphanumeric axis before comparing")
29
30 parser.add_option("-t", "--threshold",
31 action = "store", type="float",
32 help = "threshold for bin or chi2 comparison (default: 1e-6 or 0.95)")
33
34 parser.add_option("-o", "--output",
35 action = "store", dest = "outFile",
36 metavar = "NAME", default = "rootcomp",
37 help = "write output to NAME.[ps,root] (default: rootcomp)")
38
39 parser.add_option("-s", "--skip",
40 action = "append", default=[], type="string",
41 help = "add objects to skip (regular expression, can be used multiple times, mutual exclusive with -e)")
42
43 parser.add_option("-e", "--select",
44 action = "append", default=[], type="string",
45 help = "select histograms to compare (regular expression, can be used multiple times, mutual exclusive with -s)")
46
47 parser.add_option("--refBaseDir",
48 action = "store", default = "",
49 help = "base directory of reference file")
50
51 parser.add_option("--fileBaseDir",
52 action = "store", default = "",
53 help = "base directory of file")
54
55 parser.add_option("-S", "--noSkipList",
56 action = "store_true", default=False,
57 help = "do not use default list of histograms to skip")
58
59 parser.add_option("-n", "--noRoot",
60 action = "store_true",
61 help = "do not write .root file")
62
63 parser.add_option("--noPS",
64 action = "store_true",
65 help = "do not write ps/pdf file")
66
67 parser.add_option("-N", "--norm",
68 action = "store_true", default = False,
69 help = "draw normalized")
70
71 parser.add_option("--noDiff",
72 action = "store_true", default = False,
73 help = "do not plot difference histogram")
74
75 parser.add_option("--ignoreMissingRef",
76 action = "store_true", default = False,
77 help = "ignore missing references for overall test result")
78
79 parser.add_option("-z", "--zip",
80 action = "store_true",
81 help = "gzip postscript output file")
82
83 parser.add_option("-p", "--pdf",
84 action = "store_true",
85 help = "create pdf instead of ps output file")
86
87 parser.add_option("-v", "--verbose",
88 action = "store_true", default = False,
89 help = "be verbose")
90
91 parser.add_option("--html",action="store_true",default=False,help="generate root html code to view results in web browser")
92
93 (opts, args) = parser.parse_args()
94
95 if len(args)!=2:
96 parser.print_help()
97 return 255
98
99 if not opts.noSkipList:
100 opts.skip += ["Unpck$", "BufFreeCnt$", "CalEvtSize$"] # muon calibration buffer
101 opts.skip += ["/TIME_"] # timers from Monitored framework
102 opts.skip += ["/athenaHLT.*/.*Time$"] # HLTMPPU timing histograms
103 opts.skip += ["HltEventLoopMgr/.*Time.*"] # custom timers
104 opts.skip += ["HltEventLoopMgr/PopScheduler.*"] # scheduler monitoring
105 opts.skip += ["MessageSvc/MessageCount"] # MessageSvc
106 opts.skip += ["TrigSignatureMoni/.*Rate"] # Rate monitoring
107 opts.skip += ["TrigOpMonitor/GeneralOpInfo"] # release number, etc.
108 opts.skip += ["TrigOpMonitor/IOVDb.*"] # conditions data IOVs, size and time
109 opts.skip += ["TrigOpMonitor/.*ReadTime"] # conditions read time
110 opts.skip += ["TrigOpMonitor/.*BytesRead"] # conditions read size
111 opts.skip += ["HLTFramework/ROBDataProviderSvc"] # RDP histograms differ in MT due to caching
112 opts.skip += ["HLTFramework/SchedulerMonSvc"] # ATR-22345, not reproducible by definition
113 opts.skip += ["HLTSeeding/Random"] # Prescale validation (ATR-21935)
114
115
116 # Default thresholds
117 if not opts.threshold:
118 if opts.chi2: opts.threshold = 0.95
119 else: opts.threshold = 1e-6
120
121 print("-"*70)
122 print("Command : rootcomp.py %s\n" % (" ".join(sys.argv[1:])))
123 print("Reference : %s" % args[0])
124 print("File : %s" % args[1])
125 print("Comparison : ", end="")
126 if opts.chi2: print("CHI2 (%.2f)" % opts.threshold)
127 elif opts.axis: print("AXIS")
128 else: print("BIN-BY-BIN (%.1e)" % opts.threshold)
129 if not opts.skip==[]: print("Ignored histograms: %s" % (", ".join(opts.skip)))
130 if not opts.select==[]: print("Selected histograms: %s" % (", ".join(opts.select)))
131
132 print("-"*70)
133
134 # Now import ROOT
135 from PyUtils import RootUtils
136 ROOT = RootUtils.import_root( batch=True ) # noqa: F841
137
138 sys.stdout.flush()
139 sys.stderr.flush()
140
141 from ROOT import TRootCompare
142 from ROOT import gROOT, gStyle
143 gROOT.SetStyle("Plain")
144 gStyle.SetOptStat(111111)
145
146 valid = TRootCompare()
147 valid.setVerbose(opts.verbose)
148
149 # Set algorithm
150 if opts.chi2:
151 valid.setAlg(TRootCompare.CHI2, opts.threshold)
152 elif opts.axis:
153 valid.setAlg(TRootCompare.AXIS, opts.threshold)
154 else:
155 valid.setAlg(TRootCompare.BIN, opts.threshold)
156
157 # Select these histograms
158 for s in opts.select:
159 valid.passBeforeFailRegexp()
160 valid.addPassRegexp(s)
161
162 # Skip these histograms
163 for s in opts.skip:
164 valid.addFailRegexp(s)
165
166 # Select output (root, ps)
167 if not opts.noRoot: valid.setOutputFile(opts.outFile+".root")
168
169 if opts.noPS:
170 valid.setPsFile("")
171 elif opts.pdf:
172 valid.setPsFile(opts.outFile+".pdf")
173 else:
174 valid.setPsFile(opts.outFile+".ps")
175
176 valid.sortLabels(opts.sortLabels)
177 valid.drawNormalized(opts.norm)
178 valid.drawDiff(not opts.noDiff)
179
180 # Run
181 rc = valid.setReferenceFile(args[0],opts.refBaseDir)
182 if rc is False:
183 return 255
184
185 rc = valid.run(args[1],opts.fileBaseDir)
186
187 sys.stdout.flush()
188 sys.stderr.flush()
189
190 if opts.zip and not opts.pdf:
191 print("GZipping postscript file -> %s.ps.gz" % opts.outFile)
192 os.system("gzip -f %s.ps" % (opts.outFile))
193
194 if rc != 0:
195 result = 255
196 elif valid.totalHist()>0:
197 # Return 0 if all histograms are matching
198 if opts.ignoreMissingRef: result = min(valid.totalHist()-valid.matchingHist(),255)
199 # Return 0 if all histograms are matching and none missing
200 else: result = min(valid.totalHist()-valid.matchingHist()-valid.missingHist(),255)
201 elif valid.totalHist()==0 and valid.missingHist()==0 and valid.matchingHist()==0:
202 # Return 0 if no histograms found
203 result = 0
204 else:
205 result = 255
206
207 if opts.html:
208 os.system("root2html.py *.root")
209
210 print("Overall test result: %i" % result)
211 return result
212
213if __name__ == "__main__":
214 sys.exit(main())
void print(char *figname, TCanvas *c1)
#define min(a, b)
Definition cfImp.cxx:40
Class to compare the histograms in two root files.