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 from builtins import range
0004 import inspect
0005 import itertools
0006 import logging
0007 import optparse
0008 import pprint
0009 import random
0010 import sys
0011 
0012 import ROOT
0013 from DataFormats.FWLite import Events, Handle
0014 
0015 typeMap = { 'double' : ['double', 'vector<double>'],
0016             'int'    : ['int',    'vector<int>'],}
0017 
0018 class ProductNotFoundError(RuntimeError):
0019     """
0020     Special exception for a product not in file
0021     """
0022     pass
0023 
0024 def compareEvents(event1, event2, handleName, label, options):
0025     """
0026     Compare two events
0027     """
0028 
0029     # Is it a vector of objects or object (funky ROOT buffer for single value)
0030     isSimpleObject = (handleName.find('vector') == -1)
0031 
0032     # Compare run, lumi, event
0033     aux1 = event1.eventAuxiliary()
0034     aux2 = event2.eventAuxiliary()
0035 
0036     rle1 = (aux1.run(), aux1.luminosityBlock(), aux1.event())
0037     rle2 = (aux2.run(), aux2.luminosityBlock(), aux2.event())
0038 
0039     logging.debug("Comparing RLE #'s %s and %s" % (rle1, rle2))
0040 
0041     if rle1 != rle2:
0042         raise RuntimeError("Run/Lumi/Events don't match: %s vs %s" % (rle1, rle2))
0043     handle1 = Handle(handleName)
0044     handle2 = Handle(handleName)
0045 
0046     if event1.getByLabel(label, handle1) and event2.getByLabel(label, handle2):
0047         objects1 = handle1.product()
0048         objects2 = handle1.product()
0049     else:
0050         raise ProductNotFoundError("Product %s %s not found." % (handleName, label))
0051 
0052     if isSimpleObject:
0053         val1 = objects1[0]
0054         val2 = objects2[0]
0055         if options.blurRate and options.blur and random.random() < options.blurRate:
0056             # This is different than Charles's method, which makes no sense to me
0057             val1 += (random.random()-0.5) * options.blur
0058         if val1 != val2:
0059             logging.error("Mismatch %s and %s in %s" % (val1, val2, aux2.event()))
0060             return (1, 1)
0061         else:
0062             logging.debug("Match of %s in %s" % (objects1[0], aux2.event()))
0063             return (1, 0)
0064     else:
0065         count    = 0
0066         mismatch = 0
0067         for val1, val2 in itertools.izip_longest(objects1, objects2):
0068             count += 1
0069             if options.blurRate and options.blur and random.random() < options.blurRate:
0070                 # This is different than Charles's method, which makes no sense to me
0071                 val1 += (random.random()-0.5) * options.blur * val1
0072             if val1 != val2:
0073                 mismatch += 1
0074                 logging.error("Comparison problem %s != %s" % (val1, val2))
0075         logging.debug("Compared %s elements" % count)
0076         return (count, mismatch)
0077 
0078 if __name__ == "__main__":
0079 
0080     ###################
0081     ## Setup Options ##
0082     ###################
0083 
0084     random.seed()
0085     logging.basicConfig(level=logging.INFO)
0086 
0087     parser = optparse.OptionParser("usage: %prog [options] config.txt file1.root file2.root\nVisit https://twiki.cern.ch/twiki/bin/view/CMS/SWGuidePhysicsToolsEdmOneToOneComparison\nfor full documentation.")
0088     modeGroup    = optparse.OptionGroup (parser, "Mode Conrols")
0089     tupleGroup   = optparse.OptionGroup (parser, "Tuple Controls")
0090     optionsGroup = optparse.OptionGroup (parser, "Options")
0091 
0092     modeGroup.add_option ('--compare', dest='compare', action='store_true',
0093                           help='Compare tuple1 to tuple2')
0094 
0095     tupleGroup.add_option ('--numEvents', dest='numEvents', type='int',
0096                            default=1e9,
0097                            help="number of events for first and second file")
0098 
0099     tupleGroup.add_option ('--label', dest='label', type='string',
0100                            action='append',
0101                            help="Change label ('tuple^object^label')")
0102 
0103     optionsGroup.add_option ('--blur1', dest='blur', type='float',
0104                              default=0.05,
0105                              help="Randomly changes values by 'BLUR'  " +\
0106                              "from tuple1.  For debugging only.")
0107     optionsGroup.add_option ('--blurRate', dest='blurRate', type='float',
0108                              default=0.00,
0109                              help="Rate at which objects will be changed. " + \
0110                              "(%default default)")
0111 
0112     parser.add_option_group (modeGroup)
0113     parser.add_option_group (tupleGroup)
0114     parser.add_option_group (optionsGroup)
0115     (options, args) = parser.parse_args()
0116 
0117     if len(args) != 3:
0118         parser.error("Too many or too few arguments")
0119     options.config = args[0]
0120     options.file1  = args[1]
0121     options.file2  = args[2]
0122 
0123     # Parse object name and label out of Charles format
0124     tName, objName, lName = options.label[0].split('^')
0125     label = lName.split(',')
0126 
0127     ROOT.gROOT.SetBatch()
0128 
0129     ROOT.gSystem.Load("libFWCoreFWLite.so")
0130     ROOT.gSystem.Load("libDataFormatsFWLite.so")
0131     ROOT.FWLiteEnabler.enable()
0132 
0133     chain1 = Events ([options.file1], forceEvent=True)
0134     chain2 = Events ([options.file2], forceEvent=True)
0135 
0136     if chain1.size() != chain1.size():
0137         raise RuntimeError("Files have different #'s of events")
0138     numEvents = min(options.numEvents, chain1.size())
0139 
0140     # Parameters to this script are the same regardless if the
0141     # product is double or vector<double> so have to try both
0142     productsCompared = 0
0143     totalCount = 0
0144     mismatches = 0
0145     for handleName in typeMap[objName]:
0146         try:
0147             chain1.toBegin()
0148             chain2.toBegin()
0149             logging.info("Testing identity for handle=%s, label=%s" % (handleName, label))
0150             # Use itertools to iterate over lists in ||
0151             for ev1, ev2, count in itertools.izip(chain1, chain2, range(numEvents)):
0152                 evCount, evMismatch = compareEvents(event1=ev1, event2=ev2, handleName=handleName, label=label, options=options)
0153                 totalCount += evCount
0154                 mismatches += evMismatch
0155             logging.info("Compared %s events" % (count+1))
0156             productsCompared += 1
0157             # Try to reproduce the output that Charles's summary script is expecting
0158             plagerDict = {'eventsCompared' : count+1}
0159             plagerDict.update({'count_%s' % objName : totalCount})
0160             if mismatches:
0161                 plagerDict.update({objName: {'_var' : {handleName:mismatches}}})
0162             print("Summary")
0163             pprint.pprint(plagerDict)
0164         except ProductNotFoundError:
0165             logging.info("No product found for handle=%s, label=%s" % (handleName, label))
0166 
0167     logging.info("Total products compared: %s, %s/%s" % (productsCompared, mismatches, totalCount))
0168 
0169     if not productsCompared:
0170         print("Plager compatible message: not able to get any products")
0171         sys.exit()