00001
00002
00003 import optparse
00004 import commands
00005 import pprint
00006 import re
00007 import os
00008 import sys
00009
00010 piecesRE = re.compile (r'(.+?)\s+"(\S+)"\s+"(\S*)"\s+"(\S+)"')
00011
00012 nonAlphaRE = re.compile (r'\W')
00013 commaRE = re.compile (r',')
00014 queueCommand = '/uscms/home/cplager/bin/clpQueue.pl addjob %s'
00015 logDir = 'logfiles'
00016 compRootDir = 'compRoot'
00017
00018
00019 vectorRE = re.compile (r'^vector<([^<>]+)>')
00020 detSetVecRE = re.compile (r'^edm::DetSetVector<([^<>]+)>')
00021 edColRE = re.compile (r'^edm::EDCollection<([^<>]+)>')
00022 sortedColRE = re.compile (r'^edm::SortedCollection<([^<>]+),\S+?> >')
00023 singletonRE = re.compile (r'^([\w:]+)$')
00024 containerList = [vectorRE, detSetVecRE, edColRE, sortedColRE]
00025
00026 class EdmObject (object):
00027
00028 def __init__ (self, tup):
00029 self.container, self.one, self.two, self.three = tup
00030 self.bool = False
00031 for regex in containerList:
00032 match = regex.search( self.container)
00033 if match:
00034 self.bool = True
00035 self.name = match.group(1)
00036 break
00037
00038 def __str__ (self):
00039 return pprint.pformat (self.__dict__)
00040
00041 def __bool__ (self):
00042 return self.bool
00043
00044 def label (self):
00045 return "%s,%s,%s" % (self.one, self.two, self.three)
00046
00047
00048 if __name__ == "__main__":
00049
00050
00051
00052
00053 parser = optparse.OptionParser ("%prog [options] file1.root [file2.root]"\
00054 "\nFor more details, see\nhttps://twiki.cern.ch/twiki/bin/view/CMS/SWGuidePhysicsToolsEdmOneToOneComparison")
00055 describeGroup = optparse.OptionGroup (parser, "Description Options")
00056 precisionGroup = optparse.OptionGroup (parser, "Precision Options")
00057 summaryGroup = optparse.OptionGroup (parser, "Summary Options")
00058 queueGroup = optparse.OptionGroup (parser, "Queue Options")
00059 verboseGroup = optparse.OptionGroup (parser, "Verbose Options")
00060
00061 parser.add_option ("--compRoot", dest="compRoot",
00062 action="store_true", default=False,
00063 help="Make compRoot files.")
00064 parser.add_option ('--strictPairing', dest='strictPairing',
00065 action='store_true',
00066 help="Objects are paired uniquely by order in collection")
00067 parser.add_option ("--prefix", dest="prefix", type="string",
00068 help="Prefix to prepend to logfile name")
00069 parser.add_option ("--regex", dest='regex', action="append",
00070 type="string", default=[],
00071 help="Only run on branches containing regex")
00072
00073 describeGroup.add_option ("--describeOnly", dest="describeOnly",
00074 action="store_true", default=False,
00075 help="Run description step only and stop.")
00076 describeGroup.add_option ("--forceDescribe", dest="forceDescribe",
00077 action="store_true", default=False,
00078 help="Run description step even if "\
00079 "file already exists.")
00080 describeGroup.add_option ("--singletons", dest="singletons",
00081 action="store_true", default=False,
00082 help="Describe singleton objects (" \
00083 "used only with --describeOnly option).")
00084 describeGroup.add_option ("--privateMemberData", dest="privateMemberData",
00085 action="store_true", default=False,
00086 help="include private member data "\
00087 "(NOT for comparisons)")
00088
00089 precisionGroup.add_option ("--precision", dest="precision", type="string",
00090 help="Change precision use for floating "\
00091 "point numbers")
00092 precisionGroup.add_option ('--absolute', dest='absolute',
00093 action='store_true', default=False,
00094 help='Precision is checked against '\
00095 'absolute difference')
00096 precisionGroup.add_option ('--relative', dest='relative',
00097 action='store_true', default=False,
00098 help='Precision is checked against '\
00099 'relative difference')
00100
00101 summaryGroup.add_option ("--summary", dest="summary",
00102 action="store_true", default=False,
00103 help="Print out summary counts at end")
00104 summaryGroup.add_option ("--summaryFull", dest="summaryFull",
00105 action="store_true", default=False,
00106 help="Print out full summary at end (VERY LONG)")
00107
00108 queueGroup.add_option ("--noQueue", dest="noQueue",
00109 action="store_true", default=True,
00110 help="Do not use queue, but run "\
00111 "jobs serially (default).")
00112 queueGroup.add_option ("--queue", dest="noQueue",
00113 action="store_false",
00114 help="Use defaultqueueing system.")
00115 queueGroup.add_option ("--queueCommand", dest="queueCommand", type="string",
00116 help="Use QUEUECOMMAND TO queue jobs")
00117
00118 verboseGroup.add_option ("--verbose", dest="verbose",
00119 action="store_true", default=False,
00120 help="Verbose output")
00121 verboseGroup.add_option ("--verboseDebug", dest="verboseDebug",
00122 action="store_true", default=False,
00123 help="Verbose output for debugging")
00124 parser.add_option_group (describeGroup)
00125 parser.add_option_group (precisionGroup)
00126 parser.add_option_group (summaryGroup)
00127 parser.add_option_group (queueGroup)
00128 parser.add_option_group (verboseGroup)
00129 options, args = parser.parse_args()
00130
00131
00132 from Validation.Tools.GenObject import GenObject
00133 if len (args) < 1 or len (args) > 2:
00134 raise RuntimeError, "You must provide 1 or 2 root files"
00135
00136
00137
00138
00139 if options.queueCommand:
00140 queueCommand = options.queueCommand
00141 options.noQueue = False
00142 if not re.match (r'%%s', queueCommand):
00143 queueCommand += ' %s'
00144 if options.noQueue:
00145 command = 'src/Validation/Tools/scripts/runCommand.bash'
00146 else:
00147 command = 'src/Validation/Tools/scripts/runCMScommand.bash'
00148
00149
00150 if options.compRoot or options.summary or options.summaryFull:
00151 raise RuntimeError, "You can not use --compRoot or --summary "\
00152 "in --queue mode"
00153
00154
00155
00156
00157 base = os.environ.get ('CMSSW_BASE')
00158 release_base = os.environ.get ('CMSSW_RELEASE_BASE')
00159 if not base or not release_base:
00160 raise RuntimeError, "You must have already setup a CMSSW environment."
00161
00162 found = False
00163 for directory in [base, release_base]:
00164 fullCommand = directory + '/' + command
00165 if os.path.exists (fullCommand):
00166 found = True
00167 break
00168 if not found:
00169 raise RuntimeError, "Can not find %s" % command
00170 if not options.noQueue:
00171 fullCommand = queueCommand % fullCommand
00172 if not os.path.isdir (logDir):
00173 os.mkdir (logDir)
00174 if not os.path.isdir (logDir):
00175 raise RuntimeError, "Can't create %s directory" % logDir
00176 if options.compRoot and not os.path.isdir (compRootDir):
00177 os.mkdir (compRootDir)
00178 if not os.path.isdir (compRootDir):
00179 raise RuntimeError, "Can't create %s directory" % compRootDir
00180 logPrefix = logDir + '/'
00181 compRootPrefix = compRootDir + '/'
00182 if options.prefix:
00183 logPrefix += options.prefix + '_'
00184 currentDir = os.getcwd()
00185 filename1 = args[0]
00186 if len (args) == 2:
00187 filename2 = args[1]
00188 else:
00189 filename2 = filename1
00190 if not os.path.exists (filename1) or not os.path.exists (filename2):
00191 raise RuntimeError, "Can not find '%s' or '%s'" % (filename1, filename2)
00192
00193 if options.verboseDebug:
00194 options.verbose = True
00195 if options.verbose:
00196 print "files", filename1, filename2
00197 if options.singletons and not options.describeOnly:
00198 raise RuntimeError, "--singletons can only be used with "\
00199 "--describeOnly option"
00200 if options.privateMemberData and not options.describeOnly:
00201 raise RuntimeError, "--privateMemberData can only be used with "\
00202 "--describeOnly option"
00203 if options.singletons:
00204 containerList.append (singletonRE)
00205
00206
00207
00208
00209 print "Getting edmDumpEventContent output"
00210 regexLine = ""
00211 for regex in options.regex:
00212 regexLine += ' "--regex=%s"' % regex
00213 dumpCommand = 'edmDumpEventContent %s %s' % (regexLine, filename1)
00214 if options.verboseDebug:
00215 print dumpCommand, '\n'
00216 output = commands.getoutput (dumpCommand).split("\n")
00217 if not len(output):
00218 raise RuntimeError, "No output from edmDumpEventContent."
00219 if options.verboseDebug:
00220 print "output:\n", "\n".join(output)
00221 collection = {}
00222 total = failed = skipped = useless = 0
00223 for line in output:
00224 total += 1
00225 match = piecesRE.search(line)
00226 if match:
00227 obj = EdmObject( match.group(1,2,3,4) )
00228 if obj.bool:
00229 collection.setdefault( obj.container, [] ).append(obj)
00230 else:
00231 skipped += 1
00232 else:
00233 skipped += 1
00234
00235
00236
00237
00238 for key, value in sorted (collection.iteritems()):
00239 name = value[0].name
00240 prettyName = nonAlphaRE.sub('', name)
00241 descriptionName = prettyName + '.txt'
00242 if os.path.exists (descriptionName) \
00243 and os.path.getsize (descriptionName) \
00244 and not options.forceDescribe:
00245 if options.verbose:
00246 print '%s exists. Skipping' % descriptionName
00247 continue
00248
00249 describeCmd = "%s %s %s useReflexToDescribeForGenObject.py %s '--type=%s'" \
00250 % (fullCommand, currentDir, logPrefix + prettyName,
00251 GenObject.encodeNonAlphanumerics (name),
00252
00253 GenObject.encodeNonAlphanumerics (key))
00254 if options.precision:
00255 describeCmd += " --precision=" + options.precision
00256 if options.verbose:
00257 print "describing %s" % name
00258 if options.verboseDebug:
00259 print describeCmd, '\n'
00260 returnCode = os.system (describeCmd)
00261 if returnCode:
00262
00263 if returnCode == GenObject.uselessReturnCode << 8:
00264 useless += 1
00265 else:
00266 print "Error trying to describe '%s'. Continuing.\n" % \
00267 (name)
00268 failed += 1
00269 if options.describeOnly:
00270 print "Total: %3d Skipped: %3d Failed: %3d Useless: %3d" % \
00271 (total, skipped, failed, useless)
00272 if not options.noQueue:
00273 print "Note: Failed not recorded when using queuing system."
00274 sys.exit()
00275
00276
00277
00278
00279 for key, value in sorted (collection.iteritems()):
00280
00281 for obj in value:
00282
00283 name = obj.name
00284 prettyName = nonAlphaRE.sub('', name)
00285 prettyLabel = commaRE.sub ('_', obj.label())
00286 compareCmd = 'edmOneToOneComparison.py %s %s %s --compare --label=reco^%s^%s' \
00287 % (prettyName + '.txt',
00288 filename1,
00289 filename2,
00290 prettyName,
00291 obj.label())
00292 fullCompareCmd = '%s %s %s %s' \
00293 % (fullCommand, currentDir,
00294 logPrefix + prettyName + '_' + prettyLabel,
00295 compareCmd)
00296 if options.relative:
00297 fullCompareCmd += ' --relative'
00298 elif options.absolute:
00299 fullCompareCmd += ' --absolute'
00300 if options.compRoot:
00301 compRootName = compRootPrefix + prettyName \
00302 + '_' + prettyLabel + '.root'
00303 fullCompareCmd += ' --compRoot=%s' % compRootName
00304 if options.strictPairing:
00305 fullCompareCmd += ' --strictPairing'
00306 if options.verbose:
00307 print "comparing branch %s %s" % (name, obj.label())
00308 if options.verboseDebug:
00309 print fullCompareCmd,'\n'
00310 os.system (fullCompareCmd)
00311
00312
00313
00314
00315 if options.summary or options.summaryFull:
00316 if options.prefix:
00317 summaryMask = options.prefix + '_%_'
00318 else:
00319 summaryMask = '%_'
00320 if options.summaryFull:
00321 summaryOptions = '--diffTree'
00322 else:
00323 summaryOptions = '--counts'
00324 summaryCmd = 'summarizeEdmComparisonLogfiles.py %s %s logfiles' \
00325 % (summaryOptions, summaryMask)
00326 print commands.getoutput (summaryCmd)