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