CMS 3D CMS Logo

GenObject.py

Go to the documentation of this file.
00001 ##  Note: Please do not use or modify any data or functions with a
00002 ##  leading underscore.  If you "mess" with the internal structure,
00003 ##  the classes may not function as intended.
00004 
00005 
00006 from FWCore.Python.Enumerate import Enumerate
00007 import re
00008 import os
00009 import copy
00010 import ROOT
00011 import ConfigParser
00012 import PhysicsTools.PythonAnalysis as cmstools
00013 import pprint
00014 import random
00015 
00016 
00017 class GenObject (object):
00018     """Infrastruture to define general objects and their attributes."""
00019 
00020     ########################
00021     ## Static Member Data ##
00022     ########################
00023 
00024     types              = Enumerate ("float int string", "type")
00025     _objFunc           = Enumerate ("obj func", "of")
00026     _cppType           = dict ( {types.float  : 'double',
00027                                  types.int    : 'int',
00028                                  types.string : 'std::string' } )
00029     _defaultValue      = dict ( {types.float  : 0.,
00030                                  types.int    : 0,
00031                                  types.string : '""' } )
00032     _objsDict          = {} # info about GenObjects
00033     _equivDict         = {} # hold info about 'equivalent' muons
00034     _ntupleDict        = {} # information about different ntuples
00035     _tofillDict        = {} # information on how to fill from different ntuples
00036     _rootObjectDict    = {} # hold objects and stl::vectors to objects
00037                             # hooked up to a root tree
00038     _rootClassDict     = {} # holds classes (not instances) associated with
00039                             # a given GenObject
00040     _kitchenSinkDict   = {} # dictionary that holds everything else...
00041     
00042     #############################
00043     ## Static Member Functions ##
00044     #############################
00045 
00046     @staticmethod
00047     def addObjectVariable (obj, var, **optionsDict):
00048         """ User passes in in object and variable names."""
00049         if not optionsDict.has_key ('varType'):
00050             optionsDict['varType'] = GenObject.types.float
00051         varType = optionsDict['varType']
00052         if not GenObject.types.isValidValue (varType):
00053             print "Type '%s' not valid.  Skipping (%s, %s, %s)." % \
00054                   (varType, obj, var, varType)
00055             return
00056         if not optionsDict.has_key ('default'):
00057             optionsDict['default'] = GenObject._defaultValue[varType]
00058         if obj.startswith ("_") or var.startswith ("_"):
00059             print "Skipping (%s, %s, %s) because of leading underscore." % \
00060                   (obj, var, varType)
00061             return
00062         GenObject._objsDict.setdefault (obj, {}).setdefault (var, optionsDict)
00063 
00064 
00065     @staticmethod
00066     def getVariableProperty (obj, var, key):
00067         """Returns property assoicated with 'key' for variable 'var'
00068         of object 'obj'.  Returns 'None' if any of the above are not
00069         defined."""
00070         return GenObject._objsDict.get (obj, {}).get (var, {}). get (key, None)
00071 
00072 
00073     @staticmethod
00074     def setEquivExpression (obj, variable, precision):
00075         """Adds an equivalence constraint.  Must have at least one to
00076         compare GO objects."""
00077         if obj.startswith ("_"):
00078             print "Skipping (%s, %s) because of leading underscore." % \
00079                   (obj, expression)
00080             return
00081         GenObject._equivDict.setdefault (obj,[]).append ( (variable,
00082                                                            precision) )
00083         
00084     
00085     @staticmethod
00086     def printStatic():
00087         """Meant for debugging, but ok if called by user"""
00088         print "objs: "
00089         pprint.pprint (GenObject._objsDict,   indent=4)
00090         print "equiv: "
00091         pprint.pprint (GenObject._equivDict,  indent=4)
00092         print "ntuple: "
00093         pprint.pprint (GenObject._ntupleDict, indent=4)
00094         print "tofill: "
00095         pprint.pprint (GenObject._tofillDict, indent=4)
00096         print "kitchenSink: "
00097         pprint.pprint (GenObject._kitchenSinkDict, indent=4)
00098 
00099 
00100     @staticmethod
00101     def checksum (str):
00102         """Calculates a checksum of a string.  Returns it as a hex
00103         string"""
00104         return hex( reduce( lambda x, y : x + y, map(ord, str) ) )[2:]
00105 
00106 
00107     @staticmethod
00108     def rootClassName (objName):
00109         """Returns the name of the equivalent Root object"""
00110         return "go_" + objName
00111 
00112 
00113     @staticmethod
00114     def _createCppClass (objName):
00115         """Returns a string containing the '.C' file necessary to
00116         generate a shared object library with dictionary."""
00117         if not GenObject._objsDict.has_key (objName):
00118             # not good
00119             print "Error: GenObject does not know about object '%s'." % objName
00120             raise RuntimeError, "Failed to create C++ class."
00121         classname = GenObject.rootClassName (objName)
00122         retval = "#include <string>\n#include <vector>\n" \
00123                  + "using namespace std;\n\nclass %s\n" % classname
00124         retval = retval + "{\n  public:\n"
00125         retval = retval + "      typedef std::vector< %s > Collection;\n\n" \
00126                  % classname
00127         # constructor
00128         retval = retval + "      %s() :\n" % classname
00129         datadec = "\n      // data members\n"
00130         first = True
00131         for key in sorted( GenObject._objsDict[objName].keys() ):
00132             if key.startswith ("_"): continue
00133             varTypeList = GenObject._objsDict[objName][key]
00134             cppType = GenObject._cppType[ varTypeList['varType'] ]
00135             default = varTypeList['default']
00136             if first:
00137                 first = False
00138             else:
00139                 retval = retval + ",\n"
00140             retval = retval + "         %s (%s)" % (key, default)
00141             # definition
00142             datadec  = datadec + "      %s %s;\n" % (cppType, key)
00143         retval = retval + "\n      {}\n" + datadec
00144         retval = retval + "};\n";
00145         retval = retval + "#ifdef __MAKECINT__\n#pragma link C++ class " + \
00146                  "vector< %s >+;\n#endif\n\n" % classname
00147         return retval
00148 
00149 
00150     @staticmethod
00151     def _loadGoRootLibrary ():
00152         """Loads Root shared object library associated with all
00153         defined GenObjects. Will create library if necessary."""
00154         print "Loading GO Root Library"
00155         key = "_loadedLibrary"        
00156         if GenObject._kitchenSinkDict.get (key):
00157             # Already done, don't do it again:
00158             return
00159         # Mark it as done
00160         GenObject._kitchenSinkDict[key] = True
00161         # Generate source code
00162         sourceCode = ""
00163         for objClassName in sorted( GenObject._objsDict.keys() ):
00164             sourceCode = sourceCode + GenObject._createCppClass (objClassName)
00165         GenObjectRootLibDir = "genobjectrootlibs"
00166         if not os.path.exists (GenObjectRootLibDir):
00167             os.mkdir (GenObjectRootLibDir)
00168         key = GenObject.checksum( sourceCode )
00169         basename = "%s_%s" % ("GenObject", key)
00170         SO = "%s/%s_C" % (GenObjectRootLibDir, basename)
00171         linuxSO = "%s.so" % SO
00172         windowsSO = "%s.dll" % SO
00173         if not os.path.exists (linuxSO) and not os.path.exists (windowsSO):
00174             print "creating SO"
00175             filename = "%s/%s.C" % (GenObjectRootLibDir, basename)
00176             if not os.path.exists (filename):
00177                 print "creating .C file"
00178                 target = open (filename, "w")
00179                 target.write (sourceCode)
00180                 target.close()
00181             else:
00182                 print "%s exists" % filename
00183             command = "echo .L %s+ | root.exe -b" % filename
00184             os.system (command)
00185         ROOT.gSystem.Load(SO)
00186         return
00187 
00188 
00189     @staticmethod
00190     def _tofillGenObject():
00191         """Makes sure that I know how to read root files I made myself"""
00192         genObject = "GenObject"
00193         ntupleDict = GenObject._ntupleDict.setdefault (genObject, {})
00194         ntupleDict['_useChain'] = True
00195         ntupleDict['_tree'] = "goTree"
00196         for objName in GenObject._objsDict.keys():
00197             rootObjName = GenObject.rootClassName (objName)
00198             if GenObject.isSingleton (objName):
00199                 ntupleDict[objName] = objName
00200             else:
00201                 ntupleDict[objName] = objName + "s"
00202             tofillDict = GenObject._tofillDict.\
00203                          setdefault (genObject, {}).\
00204                          setdefault (objName, {})
00205             for varName in GenObject._objsDict [objName].keys():
00206                 # if the key starts with an '_', then it is not a
00207                 # variable, so don't treat it as one.
00208                 if varName.startswith ("_"):
00209                     continue
00210                 tofillDict[varName] = [ [(varName, GenObject._objFunc.obj)],
00211                                         {}]
00212 
00213 
00214     @staticmethod
00215     def prepareToLoadGenObject():
00216         """Makes all necessary preparations to load root files created
00217         by GenObject."""
00218         GenObject._tofillGenObject()
00219         GenObject._loadGoRootLibrary()
00220 
00221 
00222     @staticmethod
00223     def loadConfigFile (configFile):
00224         """Loads configuration file"""
00225         objName    = ""
00226         tupleName  = ""
00227         tofillName = ""
00228         modeEnum   = Enumerate ("none define tofill ntuple", "mode")
00229         mode       = modeEnum.none
00230         config     = ConfigParser.SafeConfigParser()
00231         config.read (configFile)
00232         for section in config.sections():
00233             pieces = re.split (r'\s+', section)
00234             if not len (pieces): continue
00235             objName, pieces = pieces[0], pieces[1:]
00236             colonMatch = re.search (r'(.+?):(.+?):(.+)', objName)
00237             mode = modeEnum.none
00238             if colonMatch:
00239                 ##########################
00240                 ## Object 'tofill' Info ##
00241                 ##########################
00242                 mode = modeEnum.tofill
00243                 objName    = colonMatch.group (1)
00244                 tupleName  = colonMatch.group (2)
00245                 tofillName = colonMatch.group (3)
00246                 ntupleDict = GenObject._ntupleDict.\
00247                              setdefault (tupleName, {})
00248                 ntupleDict[objName] = tofillName
00249                 for word in pieces:
00250                     aliasMatch = re.search (r'alias=(\S+)', word)
00251                     if aliasMatch:
00252                         myTuple = (tofillName, aliasMatch.group (1))
00253                         ntupleDict.setdefault ('_alias', []).append (myTuple)
00254                         continue
00255                     # If we're still here, then we didn't have a valid
00256                     # option.  Complain vociferously
00257                     print "I don't understand '%s' in section '%s' : %s" \
00258                           % (word, section, mode)
00259                     raise RuntimeError, "Config file parsing error"
00260             else:
00261                 colonMatch = re.search (r'(.+?):(.+)', objName)
00262                 if colonMatch:
00263                     #######################
00264                     ## Ntuple Definition ##
00265                     #######################
00266                     mode = modeEnum.ntuple
00267                     ntupleDict = GenObject._ntupleDict.\
00268                                 setdefault (colonMatch.group(1), {})
00269                     ntupleDict['_tree'] = colonMatch.group(2)
00270             if not re.search (r':', section):
00271                 ##########################
00272                 ## GenObject Definition ##
00273                 ##########################
00274                 mode = modeEnum.define
00275                 for word in pieces:
00276                     if re.match (r'singleton', word, re.IGNORECASE):
00277                         #GenObject._singletonSet.add (objName)
00278                         objsDict = GenObject._objsDict.setdefault (objName, {})
00279                         objsDict['_singleton'] = True
00280                         continue
00281                     # If we're still here, then we didn't have a valid
00282                     # option.  Complain vociferously
00283                     print "I don't understand '%s' in section '%s' : %s" \
00284                           % (word, section, mode)
00285                     raise RuntimeError, "Config file parsing error"
00286             if modeEnum.none == mode:
00287                 # Poorly formatted 'section' tag
00288                 print "I don't understand section '%s'." % section
00289                 raise RuntimeError, "Config file parsing error"
00290             for varName in config.options (section):
00291                 option = config.get (section, varName)
00292                 if option:
00293                     pieces = re.split (r'\s+', option)
00294                 else:
00295                     pieces = []
00296                 if modeEnum.define == mode:
00297                     #########################
00298                     ## Variable Definition ##
00299                     #########################
00300                     # is this a variable or an option?
00301                     if varName.startswith("-"):
00302                         # this is an option
00303                         if "-equiv" == varName.lower():
00304                             for part in pieces:
00305                                 halves = part.split (",")
00306                                 if 2 != len (halves):
00307                                     print "Problem with -equiv '%s' in '%s'" % \
00308                                           (part, section)
00309                                     raise RuntimeError, \
00310                                           "Config file parsing error"
00311                                 if halves[1]:
00312                                     halves[1] = float (halves[1])
00313                                     if not halves[1] > 0:
00314                                         print "Problem with -equiv ",\
00315                                               "'%s' in '%s'" % \
00316                                               (part, section)
00317                                         raise RuntimeError, \
00318                                               "Config file parsing error"
00319                                 GenObject.setEquivExpression (section,
00320                                                               halves[0],
00321                                                               halves[1])
00322                         continue
00323                     # If we're here, then this is a variable
00324                     optionsDict = {}
00325                     for word in pieces:
00326                         typeMatch = re.search (r'type=(\S+)', word)
00327                         if typeMatch and \
00328                                GenObject.types.isValidKey (typeMatch.group(1)):
00329                             varType = typeMatch.group(1).lower()
00330                             optionsDict['varType'] = GenObject.types (varType)
00331                             continue
00332                         defaultMatch = re.search (r'default=(\S+)', word)
00333                         if defaultMatch:
00334                             optionsDict['default'] = defaultMatch.group(1)
00335                             continue
00336                         precMatch =  re.search (r'prec=(\S+)', word)
00337                         if precMatch:
00338                             optionsDict['prec'] = float (precMatch.group (1))
00339                             continue
00340                         formMatch =  re.search (r'form=(\S+)', word)
00341                         if formMatch:
00342                             optionsDict['form'] = formMatch.group (1)
00343                             continue
00344                         # If we're still here, then we didn't have a valid
00345                         # option.  Complain vociferously
00346                         print "I don't understand '%s' in section '%s'." \
00347                               % (word, option)
00348                         raise RuntimeError, "Config file parsing error"
00349                     GenObject.addObjectVariable (objName, varName, \
00350                                                  **optionsDict)
00351                 else:
00352                     ############################
00353                     ## Variable 'tofill' Info ##
00354                     ############################
00355                     if len (pieces) < 1:
00356                         continue
00357                     fillname, pieces = pieces[0], pieces[1:]
00358                     parts = re.split (r'\s*\.\s*', fillname)
00359                     partsList = []
00360                     for part in parts:
00361                         parenMatch = re.search (r'(.+)\(.*\)', part)
00362                         mode = GenObject._objFunc.obj
00363                         if parenMatch:
00364                             part = parenMatch.group (1)
00365                             mode = GenObject._objFunc.func
00366                         partsList.append(  (part, mode) )
00367                     # I don't yet have any options available here, but
00368                     # I'm keeping the code here for when I add them.
00369                     optionsDict = {}
00370                     for word in pieces:
00371                         # If we're still here, then we didn't have a valid
00372                         # option.  Complain vociferously
00373                         print "I don't understand '%s' in section '%s'." \
00374                               % (word, option)
00375                         raise RuntimeError, "Config file parsing error"
00376                     tofillDict = GenObject._tofillDict.\
00377                                  setdefault (tupleName, {}).\
00378                                  setdefault (objName, {})
00379                     tofillDict[varName] = [partsList, optionsDict]
00380 
00381 
00382     @staticmethod
00383     def _genObjectClone (objName, tupleName, obj):
00384         """Creates a GenObject copy of Root object"""
00385         tofillObjDict = GenObject._tofillDict.get(tupleName, {})\
00386                         .get(objName, {})
00387         genObj = GenObject (objName)
00388         origObj = obj
00389         #print "obj", objName
00390         for genVar, ntDict in tofillObjDict.iteritems():
00391             partsList = ntDict[0]
00392             for part in partsList:
00393                 #print "  ", part
00394                 obj = getattr (obj, part[0])
00395             if GenObject._objFunc.func == part[1]:                
00396                 obj = obj()
00397             setattr (genObj, genVar, obj)
00398             obj = origObj
00399         return genObj
00400 
00401 
00402     @staticmethod
00403     def _rootObjectCopy (goSource, rootTarget):
00404         """Copies information from goSourse into Root Object"""
00405         objName = goSource._objName
00406         for varName in GenObject._objsDict [objName].keys():
00407             # if the key starts with an '_', then it is not a
00408             # variable, so don't treat it as one.
00409             if varName.startswith ("_"):
00410                 continue
00411             setattr( rootTarget, varName, goSource (varName) )
00412         
00413         
00414     @staticmethod
00415     def _rootObjectClone (obj):
00416         """Creates the approprite type of Root object and copies the
00417         information into it from the GO object."""
00418         objName = obj._objName
00419         rootObj = GenObject._rootClassDict[objName]()
00420         for varName in GenObject._objsDict [objName].keys():
00421             setattr( rootObj, varName, obj (varName) )
00422         return rootObj
00423 
00424 
00425     @staticmethod
00426     def setupOutputTree (outputfile, treename, treeDescription = "",
00427                          otherNtupleName = ""):
00428         """Opens the output file, loads all of the necessary shared
00429         object libraries, and returns the output file and tree.  If
00430         'otherNtupleName' is given, it will check and make sure that
00431         only objects that are defined in it are written out."""
00432         rootfile = ROOT.TFile.Open (outputfile, "recreate")
00433         tree = ROOT.TTree (treename, treeDescription)
00434         GenObject._loadGoRootLibrary()
00435         for objName in sorted (GenObject._objsDict.keys()):
00436             classname = GenObject.rootClassName (objName)
00437             rootObj = \
00438                     GenObject._rootClassDict[objName] = \
00439                     getattr (ROOT, classname)
00440             if GenObject.isSingleton (objName):
00441                 # singleton object
00442                 obj = GenObject._rootObjectDict[objName] = rootObj()
00443                 tree.Branch (objName, classname, obj)
00444             else:
00445                 # vector of objects - PLEASE don't forget the '()' on
00446                 # the end of the declaration.  Without this, you are
00447                 # defining a type, not instantiating an object.
00448                 vec = \
00449                     GenObject._rootObjectDict[objName] = \
00450                     ROOT.std.vector( rootObj )()
00451                 
00452                 branchName = objName + "s"
00453                 vecName = "vector<%s>" % classname
00454                 tree.Branch( branchName, vecName, vec)
00455             # end else if isSingleton
00456         # end for objName
00457         return rootfile, tree
00458 
00459 
00460     @staticmethod
00461     def _fillRootObjects (event):
00462         """Fills root objects from GenObject 'event'"""
00463         for objName, obj in sorted (event.iteritems()):
00464             if GenObject.isSingleton (objName):
00465                 # Just one
00466                 GenObject._rootObjectCopy (obj,
00467                                            GenObject._rootObjectDict[objName])
00468             else:
00469                 # a vector
00470                 vec = GenObject._rootObjectDict[objName]
00471                 vec.clear()
00472                 for goObj in obj:
00473                     vec.push_back( GenObject._rootObjectClone (goObj) )
00474 
00475 
00476     @staticmethod
00477     def isSingleton (objName):
00478         """Returns true if object is a singleton"""
00479         return GenObject._objsDict[objName].get('_singleton')
00480 
00481 
00482     @staticmethod
00483     def loadEventFromTree (eventTree, eventIndex,
00484                            onlyRunEvent  = False):
00485         """Loads event information from Root file (as interfaced by
00486         'cmstools.EventTree' or 'ROOT.TChain').  Returns a dictionary
00487         'event' containing lists of objects or singleton object.  If
00488         'onlyRunEvent' is et to True, then only run and event number
00489         is read in from the tree."""
00490         tupleName = GenObject._kitchenSinkDict[eventTree]['tupleName']
00491         event = {}
00492         # is this a cint tree
00493         isChain = eventTree.__class__.__name__ == 'TChain'
00494         if isChain:
00495             # This means that 'eventTree' is a ROOT.TChain
00496             eventTree.GetEntry (eventIndex)
00497         else:
00498             # This means that 'evenTree' is a cmstools.EventTree
00499             rootEvent = eventTree[eventIndex]
00500         tofillDict = GenObject._tofillDict.get (tupleName)
00501         ntupleDict = GenObject._ntupleDict.get (tupleName)
00502         if not tofillDict:
00503             print "Don't know how to fill from '%s' ntuple." % tupleName
00504             return
00505         eventBranchName = ntupleDict['runevent']
00506         for objName in tofillDict:
00507             branchName = ntupleDict[objName]
00508             if onlyRunEvent and branchName != eventBranchName:
00509                 # not now
00510                 continue
00511             # Have we been given 'tofill' info for this object?
00512             if not branchName:
00513                 # guess not
00514                 continue
00515             if isChain:
00516                 objects = getattr (eventTree, branchName)
00517             else:
00518                 objects = rootEvent.getProduct (branchName)
00519             # is this a singleton?
00520             if GenObject.isSingleton (objName):
00521                 event[objName] = GenObject.\
00522                                  _genObjectClone (objName,
00523                                                   tupleName,
00524                                                   objects)
00525                 continue
00526             # if we're here then we have a vector of items
00527             event[objName] = []
00528             for obj in objects:
00529                 event[objName].append( GenObject.\
00530                                        _genObjectClone (objName,
00531                                                         tupleName,
00532                                                         obj) )
00533             # end for obj
00534         # end for objName
00535         return event
00536 
00537 
00538     @staticmethod
00539     def printEvent (event):
00540         """Prints out event dictionary.  Mostly for debugging"""
00541         # Print out all singletons first
00542         for objName, obj in sorted (event.iteritems()):
00543             #obj = event[objName]
00544             # is this a singleton?
00545             if GenObject.isSingleton (objName):
00546                 print "%s: %s" % (objName, obj)
00547         # Now print out all vectors
00548         for objName, obj in sorted (event.iteritems()):
00549             #obj = event[objName]
00550             # is this a singleton?
00551             if not GenObject.isSingleton (objName):
00552                 # o.k. obj is a vector
00553                 print "%s:" % objName
00554                 for single in obj:
00555                     print "  ", single
00556         print
00557 
00558 
00559     @staticmethod
00560     def setAliases (eventTree, tupleName):
00561         """runs SetAlias on all saved aliases"""
00562         aliases = GenObject._ntupleDict[tupleName].get('_alias', [])
00563         for alias in aliases:
00564             eventTree.SetAlias (alias[0], alias[1])
00565 
00566 
00567     @staticmethod
00568     def prepareTuple (tupleName, files):
00569         """Given the tuple name and list of files, returns either a
00570         TChain or EventTree, and number of entries"""
00571         if "GenObject" == tupleName:
00572             GenObject.prepareToLoadGenObject()            
00573         if isinstance (files, list):
00574             # for now, we can only deal with one file
00575             files = files[0:1]
00576         else:
00577             # If this isn't a list, make it one
00578             files = [files]
00579         ntupleDict = GenObject._ntupleDict[tupleName]
00580         treeName = ntupleDict["_tree"]
00581         chain = ROOT.TChain (treeName)
00582         for filename in files:
00583             chain.AddFile (filename)
00584         numEntries = chain.GetEntries()
00585         # Are we using a chain or EventTree here?
00586         if not ntupleDict.get('_useChain'):
00587             # cmstools.EventTree
00588             chain = cmstools.EventTree (chain)
00589             GenObject.setAliases (chain, tupleName)
00590         chainDict = GenObject._kitchenSinkDict.setdefault (chain, {})
00591         chainDict['numEntries'] = numEntries
00592         chainDict['tupleName' ] = tupleName
00593         return chain
00594 
00595 
00596     @staticmethod
00597     def getRunEventEntryDict (chain, tupleName, numEntries):
00598         """Returns a dictionary of run, event tuples to entryIndicies"""
00599         reeDict = {}
00600         for entryIndex in xrange (numEntries):
00601             event = GenObject.loadEventFromTree (chain,
00602                                                  entryIndex,
00603                                                  onlyRunEvent = True)
00604             runevent = event['runevent']
00605             reeDict[ (runevent.run, runevent.event) ] = entryIndex
00606         return reeDict
00607 
00608 
00609     @staticmethod
00610     def compareRunEventDicts (firstDict, secondDict):
00611         """Compares the keys of the two dicts and returns three sets:
00612         the overlap, first but not second, and second but not first."""
00613         overlap    = set()
00614         firstOnly  = set()
00615         secondOnly = set()
00616         # loop over the keys of the first dict and compare to second dict
00617         for key in firstDict.keys():
00618             if secondDict.has_key (key):
00619                 overlap.add (key)
00620             else:
00621                 firstOnly.add (key)
00622         # now loop over keys of second dict and only check for missing
00623         # entries in first dict
00624         for key in secondDict.keys():
00625             if not firstDict.has_key (key):
00626                 secondOnly.add (key)
00627         # All done
00628         return overlap, firstOnly, secondOnly
00629 
00630 
00631     @staticmethod
00632     def pairEquivalentObjects (vec1, vec2):
00633         """Finds the equivalent objects in the two vectors"""
00634         len1, len2 = len (vec1), len (vec2)
00635         if not len1 or not len2:
00636             # Nothing to see here folks.  Keep moving.
00637             if len1:
00638                 noMatch1Set = set( xrange(len1) )
00639             else:
00640                 noMatch1Set = set ()
00641             if len2:
00642                 noMatch2Set = set( xrange(len2) )
00643             else:
00644                 noMatch2Set = set ()
00645             return set(), noMatch1Set, noMatch2Set
00646         objName = vec1[0]._objName
00647         equivList = GenObject._equivDict[objName]
00648         firstDict = {}
00649         secondDict = {}
00650         # First, look for vec2 objects that are equivalent to a
00651         # given vec1 object.
00652         for index1 in xrange (len1):
00653             objList = []
00654             obj1 = vec1[index1]
00655             for index2 in xrange (len2):
00656                 total = 0.
00657                 obj2 = vec2[index2]
00658                 ok = True
00659                 for equiv in equivList:
00660                     var, precision = equiv[0], equiv[1]
00661                     val1 = obj1 (var)
00662                     val2 = obj2 (var)
00663                     # Do we check equality or a precision
00664                     if precision:
00665                         value = abs (val1 - val2) / precision
00666                         if value > 1.:
00667                             ok = False
00668                             break
00669                         total += value ** 2
00670                     elif val1 != val2:
00671                         ok = False
00672                         break
00673                 if ok:
00674                     objList.append( (total, index2) )
00675             objList.sort()
00676             firstDict[index1] = objList
00677         # Now do the same thing, but this time look for vec1 objects
00678         # that are equivalent to a given vec2 object
00679         for index2 in xrange (len2):
00680             objList = []
00681             obj2 = vec2[index2]
00682             for index1 in xrange (len1):
00683                 total = 0.
00684                 obj1 = vec1[index1]
00685                 ok = True
00686                 for equiv in equivList:
00687                     var, precision = equiv[0], equiv[1]
00688                     val2 = obj2 (var)
00689                     val1 = obj1 (var)
00690                     # Do we check equality or a precision
00691                     if precision:
00692                         value = abs (val2 - val1) / precision
00693                         if value > 1.:
00694                             ok = False
00695                             break
00696                         total += value ** 2
00697                     elif val2 != val1:
00698                         ok = False
00699                         break
00700                 if ok:
00701                     objList.append( (total, index1) )
00702             objList.sort()
00703             secondDict[index2] = objList
00704         # O.k. Now that we have the candidate matches, lets see who is
00705         # really matched.
00706         matchedSet = set()
00707         noMatch1Set = set()
00708         for index1 in firstDict.keys():
00709             list1 = firstDict[index1]
00710             # do I have a match?
00711             if not len (list1):
00712                 # no match
00713                 noMatch1Set.add (index1)
00714                 continue
00715             # we've got at least one match
00716             best1 = list1[0]
00717             index2 = best1[1]
00718             # Does this one match me?
00719             list2 = secondDict.get (index2, [])
00720             if len(list2) and list2[0][1] == index1:
00721                 matchedSet.add( (index1, index2) )
00722                 # get rid of the 2nd key hash
00723                 del secondDict[index2]
00724             else:
00725                 # no match
00726                 noMatch1Set.add (index1)
00727         noMatch2Set = set( secondDict.keys() )
00728         return matchedSet, noMatch1Set, noMatch2Set
00729 
00730 
00731     @staticmethod
00732     def compareTwoItems (item1, item2):
00733         """Compares all of the variables making sure they are the same
00734         on the two objects."""
00735         objName = item1._objName
00736         problems = {}
00737         for varName in GenObject._objsDict[objName].keys():
00738             prec = item1.getVariableProperty (varName, 'prec')
00739             if prec:
00740                 # we want to check within a precision
00741                 value = abs( item1(varName) - item2(varName) )
00742                 if value > prec:
00743                     # we've got a problem
00744                     problems[varName] = value
00745             else:
00746                 # we want to check equality
00747                 if item1(varName) != item2(varName):
00748                     # we have a problem.  sort the values
00749                     val1, val2 = item1(varName), item2(varName)
00750                     if val1 > val2:
00751                         val1, val2 = val2, val1
00752                     problems[varName] = "%s != %s" % (val1, val2)
00753         # end for
00754         return problems
00755 
00756 
00757     @staticmethod
00758     def blurEvent (event, value, where = ""):
00759         for objName in sorted (event.keys()):
00760             if "runevent" == objName:
00761                 # runevent is a special case.  We don't compare these
00762                 continue
00763             if GenObject.isSingleton (objName):
00764                 # I'll add this in later.  For now, just skip it
00765                 continue
00766             count = 0
00767             for obj in event[objName]:
00768                 count += 1
00769                 for varName in GenObject._objsDict[objName].keys():
00770                     randNumber = random.random()
00771                     #print "rN", randNumber
00772                     if randNumber < GenObject._kitchenSinkDict['blurRate']:
00773                         print "  %s: changing '%s' of '%s:%d'" \
00774                               % (where, varName, obj._objName, count)
00775                         obj.__dict__[varName] += value
00776         
00777 
00778     @staticmethod
00779     def compareTwoTrees (chain1, chain2, **kwargs):
00780         """Given all of the necessary information, this routine will
00781         go through and compare two trees making sure they are
00782         'identical' within requested precision."""
00783         print "Comparing Two Trees"
00784         tupleName1  = GenObject._kitchenSinkDict[chain1]['tupleName']
00785         numEntries1 = GenObject._kitchenSinkDict[chain1]['numEntries']
00786         tupleName2  = GenObject._kitchenSinkDict[chain2]['tupleName']
00787         numEntries2 = GenObject._kitchenSinkDict[chain2]['numEntries']
00788         ree1 = GenObject.getRunEventEntryDict (chain1, tupleName1, numEntries1)
00789         ree2 = GenObject.getRunEventEntryDict (chain2, tupleName2, numEntries2)
00790         overlap, firstOnly, secondOnly = \
00791                  GenObject.compareRunEventDicts (ree1, ree2)
00792         #print "overlap   ", overlap
00793         problemDict = {}
00794         if firstOnly:
00795             #print "firstOnly ", firstOnly
00796             problemDict.setdefault ('_runevent', {})['firstOnly'] = \
00797                                    len (firstOnly)
00798         if secondOnly:
00799             #print "secondOnly", secondOnly
00800             problemDict.setdefault ('_runevent', {})['secondOnly'] = \
00801                                    len (secondOnly)
00802         for reTuple in overlap:
00803             event1 = GenObject.loadEventFromTree (chain1, ree1 [reTuple])
00804             event2 = GenObject.loadEventFromTree (chain2, ree2 [reTuple])
00805             if GenObject._kitchenSinkDict.get('printEvent'):
00806                 print "event1:"
00807                 GenObject.printEvent (event1)
00808                 print "event2:"
00809                 GenObject.printEvent (event2)
00810             if GenObject._kitchenSinkDict.get('blur'):
00811                 where = "run %d event %d" % reTuple
00812                 GenObject.blurEvent (event1,
00813                                      GenObject._kitchenSinkDict['blur'],
00814                                      where)
00815             for objName in sorted (event1.keys()):
00816                 if "runevent" == objName:
00817                     # runevent is a special case.  We don't compare these
00818                     continue
00819                 if not GenObject._equivDict.get (objName):
00820                     # we don't know how to compare these objects, so
00821                     # skip them.
00822                     continue
00823                 if GenObject.isSingleton (objName):
00824                     # I'll add this in later.  For now, just skip it
00825                     continue
00826                 vec1 = event1[objName]
00827                 vec2 = event2[objName]
00828                 matchedSet, noMatch1Set, noMatch2Set = \
00829                             GenObject.pairEquivalentObjects (vec1, vec2)
00830                 if noMatch1Set or noMatch2Set:
00831                     ## print "No match 1", noMatch1Set
00832                     ## print "No match 2", noMatch2Set
00833                     count1 = len (noMatch1Set)
00834                     count2 = len (noMatch2Set)
00835                     key = (count1, count2)
00836                     countDict = problemDict.\
00837                                 setdefault (objName, {}).\
00838                                 setdefault ('_missing', {})
00839                     if countDict.has_key (key):
00840                         countDict[key] += 1
00841                     else:
00842                         countDict[key] = 1
00843                                 
00844                 # o.k.  Now that we have them matched, let's compare
00845                 # the proper items:
00846                 for pair in matchedSet:
00847                     problems = GenObject.\
00848                                compareTwoItems (vec1[ pair[1 - 1] ],
00849                                                 vec2[ pair[2 - 1] ])
00850                     if problems.keys():
00851                         # pprint.pprint (problems)
00852                         for varName in problems.keys():
00853                             countDict = problemDict.\
00854                                         setdefault (objName, {}).\
00855                                         setdefault ('_var', {})
00856                             if countDict.has_key (varName):
00857                                 countDict[varName] += 1
00858                             else:
00859                                 countDict[varName] = 1
00860                             
00861             ## print "event 1"
00862             ## GenObject.printEvent (event1)
00863             ## print "event 2"
00864             ## GenObject.printEvent (event2)
00865             ## print
00866         return problemDict
00867 
00868 
00869     @staticmethod
00870     def saveTupleAs (chain, rootFile):
00871         """Saves a chain as a GO tree"""
00872         print "saveTupleAs"
00873         rootfile, tree = GenObject.setupOutputTree (rootFile, "goTree")
00874         numEntries = GenObject._kitchenSinkDict[chain]['numEntries']        
00875         for entryIndex in xrange (numEntries):
00876             event = GenObject.loadEventFromTree (chain, entryIndex)            
00877             if GenObject._kitchenSinkDict.get('blur'):
00878                 where = "run %d event %d" % (event['runevent'].run,
00879                                              event['runevent'].event)
00880                 if random.random() < GenObject._kitchenSinkDict.get('blur'):
00881                     # dropping event
00882                     print "Dropping", where
00883                     continue
00884                 GenObject.blurEvent (event,
00885                                      GenObject._kitchenSinkDict['blur'],
00886                                      where)
00887                 # check to see if we should drop the event
00888             if GenObject._kitchenSinkDict.get('printEvent'):
00889                 GenObject.printEvent (event)
00890             GenObject._fillRootObjects (event)
00891             tree.Fill()
00892         tree.Write()
00893         rootfile.Close()
00894 
00895 
00896     @staticmethod
00897     def try1 ():
00898         """A temporary function for development"""
00899         # Set a random seed for 'blurEvents'
00900         if False:
00901             tupleName = "pat"
00902             chain = GenObject.prepareTuple (tupleName,
00903                                             "PatAnalyzerSkeletonSkim.root")
00904         else:
00905             tupleName = "GenObject"
00906             chain = GenObject.prepareTuple (tupleName,
00907                                             "go1.root")
00908         event = {}
00909         GenObject.compareTwoTrees (chain, chain, blur=True)
00910         return
00911     
00912         
00913     ######################
00914     ## Member Functions ##
00915     ######################
00916 
00917 
00918     def __init__ (self, objName):
00919         """Class initializer"""
00920         if not GenObject._objsDict.has_key (objName):# or \
00921             #not GenObject._equivDict.has_key (objName) :
00922             # not good
00923             print "Error: GenObject does not know about object '%s'." % objName
00924             raise RuntimeError, "Failed to create GenObject object."
00925         self._localObjsDict = GenObject._objsDict [objName]
00926         self._objName = objName;
00927         for key, varDict in self._localObjsDict.iteritems():
00928             # if the key starts with an '_', then it is not a
00929             # variable, so don't treat it as one.
00930             if key.startswith ("_"):
00931                 continue
00932             self.setValue (key, varDict['default'])
00933             
00934 
00935     def setValue (self, name, value):
00936         """Wrapper for __setattr___"""
00937         self.__setattr__ (name, value)
00938 
00939     
00940     def getVariableProperty (self, var, key):
00941         """ Returns property assoicated with 'key' for variable 'var'
00942         of object of the same type as 'self'.  Returns 'None' if 'var'
00943         or 'key' is not defined."""
00944         return GenObject._objsDict.get (self._objName,
00945                                         {}).get (var, {}). get (key, None)
00946 
00947 
00948     def __setattr__ (self, name, value):
00949         """Controls setting of values."""
00950         if name.startswith ("_"):
00951             # The internal version. Set anything you want.
00952             object.__setattr__ (self, name, value)
00953         else:
00954             # user version - Make sure this variable has already been
00955 
00956             # defined for this type:
00957             if not self._localObjsDict.has_key (name):
00958                 # this variable has not been defined
00959                 print "Warning: '%s' for class '%s' not setup. Skipping." % \
00960                       (name, self._objName)
00961                 return
00962             varType = self.getVariableProperty (name, 'varType')
00963             # if this is an int, make sure it stays an int
00964             if GenObject.types.int == varType:
00965                 try:
00966                     # This will work with integers, floats, and string
00967                     # representations of integers.
00968                     value = int (value)
00969                 except:
00970                     # This works with string representations of floats
00971                     value = int( float( value ) )
00972             elif GenObject.types.float == varType:
00973                 # Make sure it's a float
00974                 value = float (value)
00975             elif GenObject.types.string == varType:
00976                 # make sure it's a string
00977                 value = str (value)
00978             # if we're still here, set it
00979             object.__setattr__ (self, name, value)
00980 
00981 
00982     def __call__ (self, key):
00983         """Makes object callable"""
00984         return object.__getattribute__ (self, key)
00985 
00986 
00987     def __str__ (self):
00988         """String representation"""
00989         retval = ""
00990         for varName, value in sorted (self.__dict__.iteritems()):
00991             if varName.startswith ('_'): continue
00992             form = self.getVariableProperty (varName, "form")
00993             if form:
00994                 format = "%s:%s  " % (varName, form)
00995                 retval = retval + format % value
00996             else:
00997                 retval = retval + "%s:%s  " % (varName, value)
00998         return retval
00999 

Generated on Tue Jun 9 17:49:43 2009 for CMSSW by  doxygen 1.5.4