CMS 3D CMS Logo

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