CMS 3D CMS Logo

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