CMS 3D CMS Logo

runEdmFileComparison.py
Go to the documentation of this file.
1 #! /usr/bin/env python
2 
3 from __future__ import print_function
4 import optparse
5 import commands
6 import pprint
7 import re
8 import os
9 import sys
10 import six
11 
12 piecesRE = re.compile (r'(.+?)\s+"(\S+)"\s+"(\S*)"\s+"(\S+)"')
13 #colonRE = re.compile (r':+')
14 nonAlphaRE = re.compile (r'\W')
15 commaRE = re.compile (r',')
16 queueCommand = '/uscms/home/cplager/bin/clpQueue.pl addjob %s'
17 logDir = 'logfiles'
18 compRootDir = 'compRoot'
19 # Containers
20 #vectorRE = re.compile (r'^vector<(\S+)>')
21 doubleRE = re.compile (r'^(double|int)')
22 vectorRE = re.compile (r'^vector<([^<>]+)>')
23 detSetVecRE = re.compile (r'^edm::DetSetVector<([^<>]+)>')
24 edColRE = re.compile (r'^edm::EDCollection<([^<>]+)>')
25 sortedColRE = re.compile (r'^edm::SortedCollection<([^<>]+),\S+?> >')
26 singletonRE = re.compile (r'^([\w:]+)$')
27 containerList = [vectorRE, detSetVecRE, edColRE, sortedColRE, doubleRE]
28 
29 class EdmObject (object):
30 
31  def __init__ (self, tup):
32  self.container, self.one, self.two, self.three = tup
33  self.bool = False
34  for regex in containerList:
35  match = regex.search( self.container)
36  if match:
37  self.bool = True
38  self.name = match.group(1)
39  break
40 
41  def __str__ (self):
42  return pprint.pformat (self.__dict__)
43 
44  def __bool__ (self):
45  return self.bool
46 
47  def label (self):
48  return "%s,%s,%s" % (self.one, self.two, self.three)
49 
50 
51 if __name__ == "__main__":
52 
53 
56  parser = optparse.OptionParser ("%prog [options] file1.root [file2.root]"\
57  "\nFor more details, see\nhttps://twiki.cern.ch/twiki/bin/view/CMS/SWGuidePhysicsToolsEdmOneToOneComparison")
58  describeGroup = optparse.OptionGroup (parser, "Description Options")
59  precisionGroup = optparse.OptionGroup (parser, "Precision Options")
60  summaryGroup = optparse.OptionGroup (parser, "Summary Options")
61  queueGroup = optparse.OptionGroup (parser, "Queue Options")
62  verboseGroup = optparse.OptionGroup (parser, "Verbose Options")
63  # general optionos
64  parser.add_option ("--compRoot", dest="compRoot",
65  action="store_true", default=False,
66  help="Make compRoot files.")
67  parser.add_option ('--strictPairing', dest='strictPairing',
68  action='store_true',
69  help="Objects are paired uniquely by order in collection")
70  parser.add_option ("--prefix", dest="prefix", type="string",
71  help="Prefix to prepend to logfile name")
72  parser.add_option ("--regex", dest='regex', action="append",
73  type="string", default=[],
74  help="Only run on branches containing regex")
75  # describe options
76  describeGroup.add_option ("--describeOnly", dest="describeOnly",
77  action="store_true", default=False,
78  help="Run description step only and stop.")
79  describeGroup.add_option ("--forceDescribe", dest="forceDescribe",
80  action="store_true", default=False,
81  help="Run description step even if "\
82  "file already exists.")
83  describeGroup.add_option ("--singletons", dest="singletons",
84  action="store_true", default=False,
85  help="Describe singleton objects (" \
86  "used only with --describeOnly option).")
87  describeGroup.add_option ("--privateMemberData", dest="privateMemberData",
88  action="store_true", default=False,
89  help="include private member data "\
90  "(NOT for comparisons)")
91  # precision options
92  precisionGroup.add_option ("--precision", dest="precision", type="string",
93  help="Change precision use for floating "\
94  "point numbers")
95  precisionGroup.add_option ('--absolute', dest='absolute',
96  action='store_true', default=False,
97  help='Precision is checked against '\
98  'absolute difference')
99  precisionGroup.add_option ('--relative', dest='relative',
100  action='store_true', default=False,
101  help='Precision is checked against '\
102  'relative difference')
103  # summary options
104  summaryGroup.add_option ("--summary", dest="summary",
105  action="store_true", default=False,
106  help="Print out summary counts at end")
107  summaryGroup.add_option ("--summaryFull", dest="summaryFull",
108  action="store_true", default=False,
109  help="Print out full summary at end (VERY LONG)")
110  # queue options
111  queueGroup.add_option ("--noQueue", dest="noQueue",
112  action="store_true", default=True,
113  help="Do not use queue, but run "\
114  "jobs serially (default).")
115  queueGroup.add_option ("--queue", dest="noQueue",
116  action="store_false",
117  help="Use defaultqueueing system.")
118  queueGroup.add_option ("--queueCommand", dest="queueCommand", type="string",
119  help="Use QUEUECOMMAND TO queue jobs")
120  # verbose options
121  verboseGroup.add_option ("--verbose", dest="verbose",
122  action="store_true", default=False,
123  help="Verbose output")
124  verboseGroup.add_option ("--verboseDebug", dest="verboseDebug",
125  action="store_true", default=False,
126  help="Verbose output for debugging")
127  parser.add_option_group (describeGroup)
128  parser.add_option_group (precisionGroup)
129  parser.add_option_group (summaryGroup)
130  parser.add_option_group (queueGroup)
131  parser.add_option_group (verboseGroup)
132  options, args = parser.parse_args()
133  # Because Root and PyRoot are _really annoying_, you have wait to
134  # import this until command line options are parsed.
135  from Validation.Tools.GenObject import GenObject
136  if len (args) < 1 or len (args) > 2:
137  raise RuntimeError("You must provide 1 or 2 root files")
138 
139 
142  if options.queueCommand:
143  queueCommand = options.queueCommand
144  options.noQueue = False
145  if not re.match (r'%%s', queueCommand):
146  queueCommand += ' %s'
147  if options.noQueue:
148  command = 'src/Validation/Tools/scripts/runCommand.bash'
149  else:
150  command = 'src/Validation/Tools/scripts/runCMScommand.bash'
151  # make sure we aren't trying to use options that should not be
152  # used with the queueing system
153  if options.compRoot or options.summary or options.summaryFull:
154  raise RuntimeError("You can not use --compRoot or --summary "\
155  "in --queue mode")
156 
157 
160  base = os.environ.get ('CMSSW_BASE')
161  release_base = os.environ.get ('CMSSW_RELEASE_BASE')
162  if not base or not release_base:
163  raise RuntimeError("You must have already setup a CMSSW environment.")
164  # find command
165  found = False
166  for directory in [base, release_base]:
167  fullCommand = directory + '/' + command
168  if os.path.exists (fullCommand):
169  found = True
170  break
171  if not found:
172  raise RuntimeError("Can not find %s" % command)
173  if not options.noQueue:
174  fullCommand = queueCommand % fullCommand
175  if not os.path.isdir (logDir):
176  os.mkdir (logDir)
177  if not os.path.isdir (logDir):
178  raise RuntimeError("Can't create %s directory" % logDir)
179  if options.compRoot and not os.path.isdir (compRootDir):
180  os.mkdir (compRootDir)
181  if not os.path.isdir (compRootDir):
182  raise RuntimeError("Can't create %s directory" % compRootDir)
183  logPrefix = logDir + '/'
184  compRootPrefix = compRootDir + '/'
185  if options.prefix:
186  logPrefix += options.prefix + '_'
187  currentDir = os.getcwd()
188  filename1 = args[0]
189  if len (args) == 2:
190  filename2 = args[1]
191  else:
192  filename2 = filename1
193  if not os.path.exists (filename1) or not os.path.exists (filename2):
194  raise RuntimeError("Can not find '%s' or '%s'" % (filename1, filename2))
195  # if verboseDebug is set, set verbose as well
196  if options.verboseDebug:
197  options.verbose = True
198  if options.verbose:
199  print("files", filename1, filename2)
200  if options.singletons and not options.describeOnly:
201  raise RuntimeError("--singletons can only be used with "\
202  "--describeOnly option")
203  if options.privateMemberData and not options.describeOnly:
204  raise RuntimeError("--privateMemberData can only be used with "\
205  "--describeOnly option")
206  if options.singletons:
207  containerList.append (singletonRE)
208 
209 
212  print("Getting edmDumpEventContent output")
213  regexLine = ""
214  for regex in options.regex:
215  regexLine += ' "--regex=%s"' % regex
216  dumpCommand = 'edmDumpEventContent %s %s' % (regexLine, filename1)
217  if options.verboseDebug:
218  print(dumpCommand, '\n')
219  output = commands.getoutput (dumpCommand).split("\n")
220  if not len(output):
221  raise RuntimeError("No output from edmDumpEventContent.")
222  if options.verboseDebug:
223  print("output:\n", "\n".join(output))
224  collection = {}
225  total = failed = skipped = useless = 0
226  for line in output:
227  total += 1
228  match = piecesRE.search(line)
229  if match:
230  obj = EdmObject( match.group(1,2,3,4) )
231  if obj.bool:
232  collection.setdefault( obj.container, [] ).append(obj)
233  else:
234  skipped += 1
235  else:
236  skipped += 1
237 
238 
241  for key, value in sorted (six.iteritems(collection)):
242  name = value[0].name
243  prettyName = nonAlphaRE.sub('', name)
244  descriptionName = prettyName + '.txt'
245  if os.path.exists (descriptionName) \
246  and os.path.getsize (descriptionName) \
247  and not options.forceDescribe:
248  if options.verbose:
249  print('%s exists. Skipping' % descriptionName)
250  continue
251  #print name, prettyName, key
252  describeCmd = "%s %s %s useReflexToDescribeForGenObject.py %s '--type=%s'" \
253  % (fullCommand, currentDir, logPrefix + prettyName,
254  GenObject.encodeNonAlphanumerics (name),
255  #name,
256  GenObject.encodeNonAlphanumerics (key))
257  if options.precision:
258  describeCmd += " --precision=" + options.precision
259  if options.verbose:
260  print("describing %s" % name)
261  if options.verboseDebug:
262  print(describeCmd, '\n')
263  returnCode = os.system (describeCmd)
264  if returnCode:
265  # return codes are shifted by 8 bits:
266  if returnCode == GenObject.uselessReturnCode << 8:
267  useless += 1
268  else:
269  print("Error trying to describe '%s'. Continuing.\n" % \
270  (name))
271  failed += 1
272  if options.describeOnly:
273  print("Total: %3d Skipped: %3d Failed: %3d Useless: %3d" % \
274  (total, skipped, failed, useless))
275  if not options.noQueue:
276  print("Note: Failed not recorded when using queuing system.")
277  sys.exit()
278 
279 
282  for key, value in sorted (six.iteritems(collection)):
283  #print "%-40s" % key,
284  for obj in value:
285  # print " ", obj.label(),
286  name = obj.name
287  prettyName = nonAlphaRE.sub('', name)
288  scriptName = 'edmOneToOneComparison.py'
289  if prettyName in ['int', 'double']:
290  scriptName = 'simpleEdmComparison.py'
291  prettyLabel = commaRE.sub ('_', obj.label())
292  compareCmd = '%s %s %s %s --compare --label=reco^%s^%s' \
293  % (scriptName,
294  prettyName + '.txt',
295  filename1,
296  filename2,
297  prettyName,
298  obj.label())
299  fullCompareCmd = '%s %s %s %s' \
300  % (fullCommand, currentDir,
301  logPrefix + prettyName + '_' + prettyLabel,
302  compareCmd)
303  if options.relative:
304  fullCompareCmd += ' --relative'
305  elif options.absolute:
306  fullCompareCmd += ' --absolute'
307  if options.compRoot:
308  compRootName = compRootPrefix + prettyName \
309  + '_' + prettyLabel + '.root'
310  fullCompareCmd += ' --compRoot=%s' % compRootName
311  if options.strictPairing:
312  fullCompareCmd += ' --strictPairing'
313  if options.verbose:
314  print("comparing branch %s %s" % (name, obj.label()))
315  if options.verboseDebug:
316  print(fullCompareCmd,'\n')
317  os.system (fullCompareCmd)
318 
319 
322  if options.summary or options.summaryFull:
323  if options.prefix:
324  summaryMask = options.prefix + '_%_'
325  else:
326  summaryMask = '%_'
327  if options.summaryFull:
328  summaryOptions = '--diffTree'
329  else:
330  summaryOptions = '--counts'
331  summaryCmd = 'summarizeEdmComparisonLogfiles.py %s %s logfiles' \
332  % (summaryOptions, summaryMask)
333  print(summaryCmd)
334  print(commands.getoutput (summaryCmd))
resolutioncreator_cfi.object
object
Definition: resolutioncreator_cfi.py:4
runEdmFileComparison.EdmObject.bool
bool
Definition: runEdmFileComparison.py:33
join
static std::string join(char **cmd)
Definition: RemoteFile.cc:17
runEdmFileComparison.EdmObject.label
def label(self)
Definition: runEdmFileComparison.py:47
submitPVValidationJobs.split
def split(sequence, size)
Definition: submitPVValidationJobs.py:352
runEdmFileComparison.EdmObject
Definition: runEdmFileComparison.py:29
runEdmFileComparison.EdmObject.__bool__
def __bool__(self)
Definition: runEdmFileComparison.py:44
print
void print(TMatrixD &m, const char *label=nullptr, bool mathematicaFormat=false)
Definition: Utilities.cc:46
runEdmFileComparison.EdmObject.__init__
def __init__(self, tup)
Definition: runEdmFileComparison.py:31
mps_setup.append
append
Definition: mps_setup.py:85
runEdmFileComparison.EdmObject.name
name
Definition: runEdmFileComparison.py:38
GenObject
runEdmFileComparison.EdmObject.__str__
def __str__(self)
Definition: runEdmFileComparison.py:41
runEdmFileComparison.EdmObject.three
three
Definition: runEdmFileComparison.py:32