CMS 3D CMS Logo

/data/refman/pasoursint/CMSSW_6_1_2_SLHC2/src/Validation/Tools/scripts/runEdmFileComparison.py

Go to the documentation of this file.
00001 #! /usr/bin/env python
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 #colonRE      = re.compile (r':+')
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 # Containers
00018 #vectorRE       = re.compile (r'^vector<(\S+)>')
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     ## Setup Options ##
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     # general optionos
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     # describe options
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     # precision options
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     # summary options
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     # queue options
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     # verbose options
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     # Because Root and PyRoot are _really annoying_, you have wait to
00132     # import this until command line options are parsed.
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     ## Check Queuing Options ##
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         # make sure we aren't trying to use options that should not be
00150         # used with the queueing system
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     ## Make Sure CMSSW is Setup ##
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     # find command
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     # if verboseDebug is set, set verbose as well
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     ## Run edmDumpEventContent ##
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    ## Run useReflexToDescribeForGenObject ##
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         #print name, prettyName, key
00250         describeCmd = "%s %s %s useReflexToDescribeForGenObject.py %s '--type=%s'" \
00251                   % (fullCommand, currentDir, logPrefix + prettyName,
00252                      GenObject.encodeNonAlphanumerics (name),
00253                      #name,
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             # return codes are shifted by 8 bits:
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     ## Run edmOneToOneComparison.py ##
00279     ##################################
00280     for key, value in sorted (collection.iteritems()):
00281         #print "%-40s" % key,
00282         for obj in value:
00283             # print "  ", obj.label(),
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     ## Print Summary (if requested) ##
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)