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 ("--prefix", dest="prefix", type="string",
00065 help="Prefix to prepend to logfile name")
00066 parser.add_option ("--regex", dest='regex', action="append",
00067 type="string", default=[],
00068 help="Only run on branches containing regex")
00069
00070 describeGroup.add_option ("--describeOnly", dest="describeOnly",
00071 action="store_true", default=False,
00072 help="Run description step only and stop.")
00073 describeGroup.add_option ("--forceDescribe", dest="forceDescribe",
00074 action="store_true", default=False,
00075 help="Run description step even if "\
00076 "file already exists.")
00077 describeGroup.add_option ("--singletons", dest="singletons",
00078 action="store_true", default=False,
00079 help="Describe singleton objects (" \
00080 "used only with --describeOnly option).")
00081 describeGroup.add_option ("--privateMemberData", dest="privateMemberData",
00082 action="store_true", default=False,
00083 help="include private member data "\
00084 "(NOT for comparisons)")
00085
00086 precisionGroup.add_option ("--precision", dest="precision", type="string",
00087 help="Change precision use for floating "\
00088 "point numbers")
00089 precisionGroup.add_option ('--absolute', dest='absolute',
00090 action='store_true', default=False,
00091 help='Precision is checked against '\
00092 'absolute difference')
00093 precisionGroup.add_option ('--relative', dest='relative',
00094 action='store_true', default=False,
00095 help='Precision is checked against '\
00096 'relative difference')
00097
00098 summaryGroup.add_option ("--summary", dest="summary",
00099 action="store_true", default=False,
00100 help="Print out summary counts at end")
00101 summaryGroup.add_option ("--summaryFull", dest="summaryFull",
00102 action="store_true", default=False,
00103 help="Print out full summary at end (VERY LONG)")
00104
00105 queueGroup.add_option ("--noQueue", dest="noQueue",
00106 action="store_true", default=True,
00107 help="Do not use queue, but run "\
00108 "jobs serially (default).")
00109 queueGroup.add_option ("--queue", dest="noQueue",
00110 action="store_false",
00111 help="Use defaultqueueing system.")
00112 queueGroup.add_option ("--queueCommand", dest="queueCommand", type="string",
00113 help="Use QUEUECOMMAND TO queue jobs")
00114
00115 verboseGroup.add_option ("--verbose", dest="verbose",
00116 action="store_true", default=False,
00117 help="Verbose output")
00118 verboseGroup.add_option ("--verboseDebug", dest="verboseDebug",
00119 action="store_true", default=False,
00120 help="Verbose output for debugging")
00121 parser.add_option_group (describeGroup)
00122 parser.add_option_group (precisionGroup)
00123 parser.add_option_group (summaryGroup)
00124 parser.add_option_group (queueGroup)
00125 parser.add_option_group (verboseGroup)
00126 options, args = parser.parse_args()
00127
00128
00129 from Validation.Tools.GenObject import GenObject
00130 if len (args) < 1 or len (args) > 2:
00131 raise RuntimeError, "You must provide 1 or 2 root files"
00132
00133
00134
00135
00136 if options.queueCommand:
00137 queueCommand = options.queueCommand
00138 options.noQueue = False
00139 if not re.match (r'%%s', queueCommand):
00140 queueCommand += ' %s'
00141 if options.noQueue:
00142 command = 'src/Validation/Tools/scripts/runCommand.bash'
00143 else:
00144 command = 'src/Validation/Tools/scripts/runCMScommand.bash'
00145
00146
00147 if options.compRoot or options.summary or options.summaryFull:
00148 raise RuntimeError, "You can not use --compRoot or --summary "\
00149 "in --queue mode"
00150
00151
00152
00153
00154 base = os.environ.get ('CMSSW_BASE')
00155 release_base = os.environ.get ('CMSSW_RELEASE_BASE')
00156 if not base or not release_base:
00157 raise RuntimeError, "You must have already setup a CMSSW environment."
00158
00159 found = False
00160 for directory in [base, release_base]:
00161 fullCommand = directory + '/' + command
00162 if os.path.exists (fullCommand):
00163 found = True
00164 break
00165 if not found:
00166 raise RuntimeError, "Can not find %s" % command
00167 if not options.noQueue:
00168 fullCommand = queueCommand % fullCommand
00169 if not os.path.isdir (logDir):
00170 os.mkdir (logDir)
00171 if not os.path.isdir (logDir):
00172 raise RuntimeError, "Can't create %s directory" % logDir
00173 if options.compRoot and not os.path.isdir (compRootDir):
00174 os.mkdir (compRootDir)
00175 if not os.path.isdir (compRootDir):
00176 raise RuntimeError, "Can't create %s directory" % compRootDir
00177 logPrefix = logDir + '/'
00178 compRootPrefix = compRootDir + '/'
00179 if options.prefix:
00180 logPrefix += options.prefix + '_'
00181 currentDir = os.getcwd()
00182 filename1 = args[0]
00183 if len (args) == 2:
00184 filename2 = args[1]
00185 else:
00186 filename2 = filename1
00187 if not os.path.exists (filename1) or not os.path.exists (filename2):
00188 raise RuntimeError, "Can not find '%s' or '%s'" % (filename1, filename2)
00189
00190 if options.verboseDebug:
00191 options.verbose = True
00192 if options.verbose:
00193 print "files", filename1, filename2
00194 if options.singletons and not options.describeOnly:
00195 raise RuntimeError, "--singletons can only be used with "\
00196 "--describeOnly option"
00197 if options.privateMemberData and not options.describeOnly:
00198 raise RuntimeError, "--privateMemberData can only be used with "\
00199 "--describeOnly option"
00200 if options.singletons:
00201 containerList.append (singletonRE)
00202
00203
00204
00205
00206 print "Getting edmDumpEventContent output"
00207 regexLine = ""
00208 for regex in options.regex:
00209 regexLine += ' "--regex=%s"' % regex
00210 dumpCommand = 'edmDumpEventContent %s %s' % (regexLine, filename1)
00211 if options.verboseDebug:
00212 print dumpCommand, '\n'
00213 output = commands.getoutput (dumpCommand).split("\n")
00214 if not len(output):
00215 raise RuntimeError, "No output from edmDumpEventContent."
00216 if options.verboseDebug:
00217 print "output:\n", "\n".join(output)
00218 collection = {}
00219 total = failed = skipped = useless = 0
00220 for line in output:
00221 total += 1
00222 match = piecesRE.search(line)
00223 if match:
00224 obj = EdmObject( match.group(1,2,3,4) )
00225 if obj.bool:
00226 collection.setdefault( obj.container, [] ).append(obj)
00227 else:
00228 skipped += 1
00229 else:
00230 skipped += 1
00231
00232
00233
00234
00235 for key, value in sorted (collection.iteritems()):
00236 name = value[0].name
00237 prettyName = nonAlphaRE.sub('', name)
00238 descriptionName = prettyName + '.txt'
00239 if os.path.exists (descriptionName) \
00240 and os.path.getsize (descriptionName) \
00241 and not options.forceDescribe:
00242 if options.verbose:
00243 print '%s exists. Skipping' % descriptionName
00244 continue
00245
00246 describeCmd = "%s %s %s useReflexToDescribeForGenObject.py %s '--type=%s'" \
00247 % (fullCommand, currentDir, logPrefix + prettyName,
00248 GenObject.encodeNonAlphanumerics (name),
00249
00250 GenObject.encodeNonAlphanumerics (key))
00251 if options.precision:
00252 describeCmd += " --precision=" + options.precision
00253 if options.verbose:
00254 print "describing %s" % name
00255 if options.verboseDebug:
00256 print describeCmd, '\n'
00257 returnCode = os.system (describeCmd)
00258 if returnCode:
00259
00260 if returnCode == GenObject.uselessReturnCode << 8:
00261 useless += 1
00262 else:
00263 print "Error trying to describe '%s'. Continuing.\n" % \
00264 (name)
00265 failed += 1
00266 if options.describeOnly:
00267 print "Total: %3d Skipped: %3d Failed: %3d Useless: %3d" % \
00268 (total, skipped, failed, useless)
00269 if not options.noQueue:
00270 print "Note: Failed not recorded when using queuing system."
00271 sys.exit()
00272
00273
00274
00275
00276 for key, value in sorted (collection.iteritems()):
00277
00278 for obj in value:
00279
00280 name = obj.name
00281 prettyName = nonAlphaRE.sub('', name)
00282 prettyLabel = commaRE.sub ('_', obj.label())
00283 compareCmd = 'edmOneToOneComparison.py %s %s %s --compare --label=reco^%s^%s' \
00284 % (prettyName + '.txt',
00285 filename1,
00286 filename2,
00287 prettyName,
00288 obj.label())
00289 fullCompareCmd = '%s %s %s %s' \
00290 % (fullCommand, currentDir,
00291 logPrefix + prettyName + '_' + prettyLabel,
00292 compareCmd)
00293 if options.relative:
00294 fullCompareCmd += ' --relative'
00295 elif options.absolute:
00296 fullCompareCmd += ' --absolute'
00297 if options.compRoot:
00298 compRootName = compRootPrefix + prettyName \
00299 + '_' + prettyLabel + '.root'
00300 fullCompareCmd += ' --compRoot=%s' % compRootName
00301 if options.verbose:
00302 print "comparing branch %s %s" % (name, obj.label())
00303 if options.verboseDebug:
00304 print fullCompareCmd,'\n'
00305 os.system (fullCompareCmd)
00306
00307
00308
00309
00310 if options.summary or options.summaryFull:
00311 if options.prefix:
00312 summaryMask = options.prefix + '_%_'
00313 else:
00314 summaryMask = '%_'
00315 if options.summaryFull:
00316 summaryOptions = '--diffTree'
00317 else:
00318 summaryOptions = '--counts'
00319 summaryCmd = 'summarizeEdmComparisonLogfiles.py %s %s logfiles' \
00320 % (summaryOptions, summaryMask)
00321 print commands.getoutput (summaryCmd)