File indexing completed on 2023-10-25 10:07:40
0001
0002
0003 from __future__ import print_function
0004 import optparse
0005 import subprocess
0006 import pprint
0007 import re
0008 import os
0009 import sys
0010
0011 piecesRE = re.compile (r'(.+?)\s+"(\S+)"\s+"(\S*)"\s+"(\S+)"')
0012
0013 nonAlphaRE = re.compile (r'\W')
0014 commaRE = re.compile (r',')
0015 queueCommand = '/uscms/home/cplager/bin/clpQueue.pl addjob %s'
0016 logDir = 'logfiles'
0017 compRootDir = 'compRoot'
0018
0019
0020 doubleRE = re.compile (r'^(double|int)')
0021 vectorRE = re.compile (r'^vector<([^<>]+)>')
0022 detSetVecRE = re.compile (r'^edm::DetSetVector<([^<>]+)>')
0023 edColRE = re.compile (r'^edm::EDCollection<([^<>]+)>')
0024 sortedColRE = re.compile (r'^edm::SortedCollection<([^<>]+),\S+?> >')
0025 singletonRE = re.compile (r'^([\w:]+)$')
0026 containerList = [vectorRE, detSetVecRE, edColRE, sortedColRE, doubleRE]
0027
0028 class EdmObject (object):
0029
0030 def __init__ (self, tup):
0031 self.container, self.one, self.two, self.three = tup
0032 self.bool = False
0033 for regex in containerList:
0034 match = regex.search( self.container)
0035 if match:
0036 self.bool = True
0037 self.name = match.group(1)
0038 break
0039
0040 def __str__ (self):
0041 return pprint.pformat (self.__dict__)
0042
0043 def __bool__ (self):
0044 return self.bool
0045
0046 def label (self):
0047 return "%s,%s,%s" % (self.one, self.two, self.three)
0048
0049
0050 if __name__ == "__main__":
0051
0052
0053
0054
0055 parser = optparse.OptionParser ("%prog [options] file1.root [file2.root]"\
0056 "\nFor more details, see\nhttps://twiki.cern.ch/twiki/bin/view/CMS/SWGuidePhysicsToolsEdmOneToOneComparison")
0057 describeGroup = optparse.OptionGroup (parser, "Description Options")
0058 precisionGroup = optparse.OptionGroup (parser, "Precision Options")
0059 summaryGroup = optparse.OptionGroup (parser, "Summary Options")
0060 queueGroup = optparse.OptionGroup (parser, "Queue Options")
0061 verboseGroup = optparse.OptionGroup (parser, "Verbose Options")
0062
0063 parser.add_option ("--compRoot", dest="compRoot",
0064 action="store_true", default=False,
0065 help="Make compRoot files.")
0066 parser.add_option ('--strictPairing', dest='strictPairing',
0067 action='store_true',
0068 help="Objects are paired uniquely by order in collection")
0069 parser.add_option ("--prefix", dest="prefix", type="string",
0070 help="Prefix to prepend to logfile name")
0071 parser.add_option ("--regex", dest='regex', action="append",
0072 type="string", default=[],
0073 help="Only run on branches containing regex")
0074
0075 describeGroup.add_option ("--describeOnly", dest="describeOnly",
0076 action="store_true", default=False,
0077 help="Run description step only and stop.")
0078 describeGroup.add_option ("--forceDescribe", dest="forceDescribe",
0079 action="store_true", default=False,
0080 help="Run description step even if "\
0081 "file already exists.")
0082 describeGroup.add_option ("--singletons", dest="singletons",
0083 action="store_true", default=False,
0084 help="Describe singleton objects (" \
0085 "used only with --describeOnly option).")
0086 describeGroup.add_option ("--privateMemberData", dest="privateMemberData",
0087 action="store_true", default=False,
0088 help="include private member data "\
0089 "(NOT for comparisons)")
0090
0091 precisionGroup.add_option ("--precision", dest="precision", type="string",
0092 help="Change precision use for floating "\
0093 "point numbers")
0094 precisionGroup.add_option ('--absolute', dest='absolute',
0095 action='store_true', default=False,
0096 help='Precision is checked against '\
0097 'absolute difference')
0098 precisionGroup.add_option ('--relative', dest='relative',
0099 action='store_true', default=False,
0100 help='Precision is checked against '\
0101 'relative difference')
0102
0103 summaryGroup.add_option ("--summary", dest="summary",
0104 action="store_true", default=False,
0105 help="Print out summary counts at end")
0106 summaryGroup.add_option ("--summaryFull", dest="summaryFull",
0107 action="store_true", default=False,
0108 help="Print out full summary at end (VERY LONG)")
0109
0110 queueGroup.add_option ("--noQueue", dest="noQueue",
0111 action="store_true", default=True,
0112 help="Do not use queue, but run "\
0113 "jobs serially (default).")
0114 queueGroup.add_option ("--queue", dest="noQueue",
0115 action="store_false",
0116 help="Use defaultqueueing system.")
0117 queueGroup.add_option ("--queueCommand", dest="queueCommand", type="string",
0118 help="Use QUEUECOMMAND TO queue jobs")
0119
0120 verboseGroup.add_option ("--verbose", dest="verbose",
0121 action="store_true", default=False,
0122 help="Verbose output")
0123 verboseGroup.add_option ("--verboseDebug", dest="verboseDebug",
0124 action="store_true", default=False,
0125 help="Verbose output for debugging")
0126 parser.add_option_group (describeGroup)
0127 parser.add_option_group (precisionGroup)
0128 parser.add_option_group (summaryGroup)
0129 parser.add_option_group (queueGroup)
0130 parser.add_option_group (verboseGroup)
0131 options, args = parser.parse_args()
0132
0133
0134 from Validation.Tools.GenObject import GenObject
0135 if len (args) < 1 or len (args) > 2:
0136 raise RuntimeError("You must provide 1 or 2 root files")
0137
0138
0139
0140
0141 if options.queueCommand:
0142 queueCommand = options.queueCommand
0143 options.noQueue = False
0144 if not re.match (r'%%s', queueCommand):
0145 queueCommand += ' %s'
0146 if options.noQueue:
0147 command = 'src/Validation/Tools/scripts/runCommand.bash'
0148 else:
0149 command = 'src/Validation/Tools/scripts/runCMScommand.bash'
0150
0151
0152 if options.compRoot or options.summary or options.summaryFull:
0153 raise RuntimeError("You can not use --compRoot or --summary "\
0154 "in --queue mode")
0155
0156
0157
0158
0159 base = os.environ.get ('CMSSW_BASE')
0160 release_base = os.environ.get ('CMSSW_RELEASE_BASE')
0161 if not base or not release_base:
0162 raise RuntimeError("You must have already setup a CMSSW environment.")
0163
0164 found = False
0165 for directory in [base, release_base]:
0166 fullCommand = directory + '/' + command
0167 if os.path.exists (fullCommand):
0168 found = True
0169 break
0170 if not found:
0171 raise RuntimeError("Can not find %s" % command)
0172 if not options.noQueue:
0173 fullCommand = queueCommand % fullCommand
0174 if not os.path.isdir (logDir):
0175 os.mkdir (logDir)
0176 if not os.path.isdir (logDir):
0177 raise RuntimeError("Can't create %s directory" % logDir)
0178 if options.compRoot and not os.path.isdir (compRootDir):
0179 os.mkdir (compRootDir)
0180 if not os.path.isdir (compRootDir):
0181 raise RuntimeError("Can't create %s directory" % compRootDir)
0182 logPrefix = logDir + '/'
0183 compRootPrefix = compRootDir + '/'
0184 if options.prefix:
0185 logPrefix += options.prefix + '_'
0186 currentDir = os.getcwd()
0187 filename1 = args[0]
0188 if len (args) == 2:
0189 filename2 = args[1]
0190 else:
0191 filename2 = filename1
0192 if not os.path.exists (filename1) or not os.path.exists (filename2):
0193 raise RuntimeError("Can not find '%s' or '%s'" % (filename1, filename2))
0194
0195 if options.verboseDebug:
0196 options.verbose = True
0197 if options.verbose:
0198 print("files", filename1, filename2)
0199 if options.singletons and not options.describeOnly:
0200 raise RuntimeError("--singletons can only be used with "\
0201 "--describeOnly option")
0202 if options.privateMemberData and not options.describeOnly:
0203 raise RuntimeError("--privateMemberData can only be used with "\
0204 "--describeOnly option")
0205 if options.singletons:
0206 containerList.append (singletonRE)
0207
0208
0209
0210
0211 print("Getting edmDumpEventContent output")
0212 regexLine = ""
0213 for regex in options.regex:
0214 regexLine += ' "--regex=%s"' % regex
0215 dumpCommand = 'edmDumpEventContent %s %s' % (regexLine, filename1)
0216 if options.verboseDebug:
0217 print(dumpCommand, '\n')
0218 output = subprocess.getoutput (dumpCommand).split("\n")
0219 if not len(output):
0220 raise RuntimeError("No output from edmDumpEventContent.")
0221 if options.verboseDebug:
0222 print("output:\n", "\n".join(output))
0223 collection = {}
0224 total = failed = skipped = useless = 0
0225 for line in output:
0226 total += 1
0227 match = piecesRE.search(line)
0228 if match:
0229 obj = EdmObject( match.group(1,2,3,4) )
0230 if obj.bool:
0231 collection.setdefault( obj.container, [] ).append(obj)
0232 else:
0233 skipped += 1
0234 else:
0235 skipped += 1
0236
0237
0238
0239
0240 for key, value in sorted (collection.items()):
0241 name = value[0].name
0242 prettyName = nonAlphaRE.sub('', name)
0243 descriptionName = prettyName + '.txt'
0244 if os.path.exists (descriptionName) \
0245 and os.path.getsize (descriptionName) \
0246 and not options.forceDescribe:
0247 if options.verbose:
0248 print('%s exists. Skipping' % descriptionName)
0249 continue
0250
0251 describeCmd = "%s %s %s useReflexToDescribeForGenObject.py %s '--type=%s'" \
0252 % (fullCommand, currentDir, logPrefix + prettyName,
0253 GenObject.encodeNonAlphanumerics (name),
0254
0255 GenObject.encodeNonAlphanumerics (key))
0256 if options.precision:
0257 describeCmd += " --precision=" + options.precision
0258 if options.verbose:
0259 print("describing %s" % name)
0260 if options.verboseDebug:
0261 print(describeCmd, '\n')
0262 returnCode = os.system (describeCmd)
0263 if returnCode:
0264
0265 if returnCode == GenObject.uselessReturnCode << 8:
0266 useless += 1
0267 else:
0268 print("Error trying to describe '%s'. Continuing.\n" % \
0269 (name))
0270 failed += 1
0271 if options.describeOnly:
0272 print("Total: %3d Skipped: %3d Failed: %3d Useless: %3d" % \
0273 (total, skipped, failed, useless))
0274 if not options.noQueue:
0275 print("Note: Failed not recorded when using queuing system.")
0276 sys.exit()
0277
0278
0279
0280
0281 for key, value in sorted (collection.items()):
0282
0283 for obj in value:
0284
0285 name = obj.name
0286 prettyName = nonAlphaRE.sub('', name)
0287 scriptName = 'edmOneToOneComparison.py'
0288 if prettyName in ['int', 'double']:
0289 scriptName = 'simpleEdmComparison.py'
0290 prettyLabel = commaRE.sub ('_', obj.label())
0291 compareCmd = '%s %s %s %s --compare --label=reco^%s^%s' \
0292 % (scriptName,
0293 prettyName + '.txt',
0294 filename1,
0295 filename2,
0296 prettyName,
0297 obj.label())
0298 fullCompareCmd = '%s %s %s %s' \
0299 % (fullCommand, currentDir,
0300 logPrefix + prettyName + '_' + prettyLabel,
0301 compareCmd)
0302 if options.relative:
0303 fullCompareCmd += ' --relative'
0304 elif options.absolute:
0305 fullCompareCmd += ' --absolute'
0306 if options.compRoot:
0307 compRootName = compRootPrefix + prettyName \
0308 + '_' + prettyLabel + '.root'
0309 fullCompareCmd += ' --compRoot=%s' % compRootName
0310 if options.strictPairing:
0311 fullCompareCmd += ' --strictPairing'
0312 if options.verbose:
0313 print("comparing branch %s %s" % (name, obj.label()))
0314 if options.verboseDebug:
0315 print(fullCompareCmd,'\n')
0316 os.system (fullCompareCmd)
0317
0318
0319
0320
0321 if options.summary or options.summaryFull:
0322 if options.prefix:
0323 summaryMask = options.prefix + '_%_'
0324 else:
0325 summaryMask = '%_'
0326 if options.summaryFull:
0327 summaryOptions = '--diffTree'
0328 else:
0329 summaryOptions = '--counts'
0330 summaryCmd = 'summarizeEdmComparisonLogfiles.py %s %s logfiles' \
0331 % (summaryOptions, summaryMask)
0332 print(summaryCmd)
0333 print(subprocess.getoutput (summaryCmd))