Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-12-01 23:40:46

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