Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2023-10-25 10:07:40

0001 #! /usr/bin/env python3
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 #colonRE      = re.compile (r':+')
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 # Containers
0019 #vectorRE       = re.compile (r'^vector<(\S+)>')
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     ## Setup Options ##
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     # general optionos
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     # describe options
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     # precision options
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     # summary options
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     # queue options
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     # verbose options
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     # Because Root and PyRoot are _really annoying_, you have wait to
0133     # import this until command line options are parsed.
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     ## Check Queuing Options ##
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         # make sure we aren't trying to use options that should not be
0151         # used with the queueing system
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     ## Make Sure CMSSW is Setup ##
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     # find command
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     # if verboseDebug is set, set verbose as well
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     ## Run edmDumpEventContent ##
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    ## Run useReflexToDescribeForGenObject ##
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         #print name, prettyName, key
0251         describeCmd = "%s %s %s useReflexToDescribeForGenObject.py %s '--type=%s'" \
0252                   % (fullCommand, currentDir, logPrefix + prettyName,
0253                      GenObject.encodeNonAlphanumerics (name),
0254                      #name,
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             # return codes are shifted by 8 bits:
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     ## Run edmOneToOneComparison.py ##
0280     ##################################
0281     for key, value in sorted (collection.items()):
0282         #print "%-40s" % key,
0283         for obj in value:
0284             # print "  ", obj.label(),
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     ## Print Summary (if requested) ##
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))