Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-04-06 12:33:41

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