CMS 3D CMS Logo

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