CMS 3D CMS Logo

/data/doxygen/doxygen-1.7.3/gen/CMSSW_4_2_8/src/Validation/Tools/python/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.Utilities.Enumerate import Enumerate
00007 from DataFormats.FWLite import Events, Handle
00008 import re
00009 import os
00010 import copy
00011 import pprint
00012 import random
00013 import sys
00014 import inspect
00015 import ROOT
00016 ROOT.gROOT.SetBatch()
00017 
00018 # regex for reducing 'warn()' filenames
00019 filenameRE = re.compile (r'.+/Validation/Tools/')
00020 # Whether warn() should print anythingg
00021 quietWarn = False
00022 
00023 def setQuietWarn (quiet = True):
00024     global quietWarn
00025     quietWarn = quiet
00026 
00027 
00028 def warn (*args, **kwargs):
00029     """print out warning with line number and rest of arguments"""
00030     if quietWarn: return
00031     frame = inspect.stack()[1]
00032     filename = frame[1]
00033     lineNum  = frame[2]
00034     #print filename, filenameRE
00035     filename = filenameRE.sub ('', filename)
00036     #print "after '%s'" % filename
00037     blankLines = kwargs.get('blankLines', 0)
00038     if blankLines:
00039         print '\n' * blankLines
00040     spaces = kwargs.get('spaces', 0)
00041     if spaces:
00042         print ' ' * spaces,
00043     if len (args):
00044         print "%s (%s): " % (filename, lineNum),
00045         for arg in args:
00046             print arg,
00047         print
00048     else:
00049         print "%s (%s):" % (filename, lineNum)
00050 
00051 
00052 class GenObject (object):
00053     """Infrastruture to define general objects and their attributes."""
00054 
00055     ########################
00056     ## Static Member Data ##
00057     ########################
00058 
00059     types              = Enumerate ("float int long string", "type")
00060     _objFunc           = Enumerate ("obj func", "of")
00061     _cppType           = dict ( {types.float  : 'double',
00062                                  types.int    : 'int',
00063                                  types.long   : 'long',
00064                                  types.string : 'std::string' } )
00065     _basicSet          = set( [types.float, types.int, types.float,
00066                                types.string] )
00067     _defaultValue      = dict ( {types.float  : 0.,
00068                                  types.int    : 0,
00069                                  types.long   : 0L,
00070                                  types.string : '""' } )
00071     _objsDict          = {} # info about GenObjects
00072     _equivDict         = {} # hold info about 'equivalent' muons
00073     _ntupleDict        = {} # information about different ntuples
00074     _tofillDict        = {} # information on how to fill from different ntuples
00075     _rootObjectDict    = {} # hold objects and stl::vectors to objects
00076                             # hooked up to a root tree
00077     _rootClassDict     = {} # holds classes (not instances) associated with
00078                             # a given GenObject
00079     _kitchenSinkDict   = {} # dictionary that holds everything else...
00080     _runEventList      = []
00081     _runEventListDone  = False
00082     uselessReturnCode  = 1 << 7 # pick a unique return code
00083     
00084     ####################
00085     ## Compile Regexs ##
00086     ####################
00087     _nonSpacesRE      = re.compile (r'\S')
00088     _colonRE          = re.compile (r'\s*:\s*')
00089     _singleColonRE    = re.compile (r'(.+?):(.+)')
00090     _doubleColonRE    = re.compile (r'(.+?):(.+?):(.+)')
00091     _doublePercentRE  = re.compile (r'%%')    
00092     _parenRE          = re.compile (r'(.+)\((.*)\)')
00093     _spacesRE         = re.compile (r'\s+')
00094     _dotRE            = re.compile (r'\s*\.\s*')
00095     _commaRE          = re.compile (r'\s*,\s*')
00096     _singleQuoteRE    = re.compile (r'^\'(.+)\'$')
00097     _doubleQuoteRE    = re.compile (r'^\"(.+)\"$')
00098     _bracketRE        = re.compile (r'\[\s*(.+?)\s*\]')
00099     _commentRE        = re.compile (r'#.+$')
00100     _aliasRE          = re.compile (r'alias=(\S+)',    re.IGNORECASE)
00101     _labelRE          = re.compile (r'label=(\S+)',    re.IGNORECASE)
00102     _typeRE           = re.compile (r'type=(\S+)',     re.IGNORECASE)
00103     _singletonRE      = re.compile (r'singleton',      re.IGNORECASE)
00104     _typeRE           = re.compile (r'type=(\S+)',     re.IGNORECASE)
00105     _defaultRE        = re.compile (r'default=(\S+)',  re.IGNORECASE)
00106     _shortcutRE       = re.compile (r'shortcut=(\S+)', re.IGNORECASE)
00107     _precRE           = re.compile (r'prec=(\S+)',     re.IGNORECASE)
00108     _formRE           = re.compile (r'form=(\S+)',     re.IGNORECASE)
00109     _nonAlphaRE       = re.compile (r'\W')
00110     _percentAsciiRE   = re.compile (r'%([0-9a-fA-F]{2})')
00111     
00112     #############################
00113     ## Static Member Functions ##
00114     #############################
00115 
00116     @staticmethod
00117     def char2ascii (match):
00118         return "%%%02x" % ord (match.group(0))
00119 
00120     @staticmethod
00121     def ascii2char (match):
00122         return chr( int( match.group(1), 16 ) )
00123 
00124     @staticmethod
00125     def encodeNonAlphanumerics (line):
00126         """Use a web like encoding of characters that are non-alphanumeric"""
00127         return GenObject._nonAlphaRE.sub( GenObject.char2ascii, line )
00128 
00129     @staticmethod
00130     def decodeNonAlphanumerics (line):
00131         """Decode lines encoded with encodeNonAlphanumerics()"""
00132         return GenObject._percentAsciiRE.sub( GenObject.ascii2char, line )
00133         
00134 
00135     @staticmethod
00136     def addObjectVariable (obj, var, **optionsDict):
00137         """ User passes in in object and variable names."""
00138         if not optionsDict.has_key ('varType'):
00139             optionsDict['varType'] = GenObject.types.float
00140         varType = optionsDict['varType']
00141         if not GenObject.types.isValidValue (varType):
00142             print "Type '%s' not valid.  Skipping (%s, %s, %s)." % \
00143                   (varType, obj, var, varType)
00144             return
00145         if not optionsDict.has_key ('default'):
00146             optionsDict['default'] = GenObject._defaultValue[varType]
00147         if obj.startswith ("_") or var.startswith ("_"):
00148             print "Skipping (%s, %s, %s) because of leading underscore." % \
00149                   (obj, var, varType)
00150             return
00151         GenObject._objsDict.setdefault (obj, {}).setdefault (var, optionsDict)
00152 
00153 
00154     @staticmethod
00155     def getVariableProperty (obj, var, key):
00156         """Returns property assoicated with 'key' for variable 'var'
00157         of object 'obj'.  Returns 'None' if any of the above are not
00158         defined."""
00159         return GenObject._objsDict.get (obj, {}).get (var, {}). get (key, None)
00160 
00161 
00162     @staticmethod
00163     def setEquivExpression (obj, variable, precision):
00164         """Adds an equivalence constraint.  Must have at least one to
00165         compare GO objects."""
00166         if obj.startswith ("_"):
00167             print "Skipping (%s, %s) because of leading underscore." % \
00168                   (obj, expression)
00169             return
00170         GenObject._equivDict.setdefault (obj,[]).append ( (variable,
00171                                                            precision) )
00172         
00173     
00174     @staticmethod
00175     def printGlobal():
00176         """Meant for debugging, but ok if called by user"""
00177         print "objs: "
00178         pprint.pprint (GenObject._objsDict,        indent=4)
00179         print "equiv: "                            
00180         pprint.pprint (GenObject._equivDict,       indent=4)
00181         print "ntuple: "                           
00182         pprint.pprint (GenObject._ntupleDict,      indent=4)
00183         print "tofill: "                           
00184         pprint.pprint (GenObject._tofillDict,      indent=4)
00185         print "kitchenSink: "
00186         pprint.pprint (GenObject._kitchenSinkDict, indent=4)
00187         print "rootClassDict"
00188         pprint.pprint (GenObject._rootClassDict,   indent=4)
00189 
00190 
00191     @staticmethod
00192     def checksum (str):
00193         """Returns a string of hex value of a checksum of input
00194         string."""
00195         return hex( reduce( lambda x, y : x + y, map(ord, str) ) )[2:]
00196 
00197 
00198     @staticmethod
00199     def rootClassName (objName):
00200         """Returns the name of the equivalent Root object"""
00201         return "go_" + objName
00202 
00203 
00204     @staticmethod
00205     def rootDiffClassName (objName):
00206         """Returns the name of the equivalent Root diff object"""
00207         return "goDiff_" + objName
00208 
00209 
00210     @staticmethod
00211     def rootDiffContClassName (objName):
00212         """Returns the name of the equivalent Root diff container
00213         object"""
00214         return "goDiffCont_" + objName
00215 
00216 
00217     @staticmethod
00218     def _setupClassHeader (className, noColon = False):
00219         """Returns a string with the class header for a class
00220         'classname'"""
00221         retval  = "\nclass %s\n{\n  public:\n" % className
00222         retval += "      typedef std::vector< %s > Collection;\n\n" % className
00223         # constructor
00224         if noColon:
00225             retval += "      %s()" % className
00226         else:
00227             retval += "      %s() :\n" % className
00228         return retval
00229 
00230 
00231     @staticmethod
00232     def _finishClassHeader (className, datadec):
00233         """Returns a stringg with the end of a class definition"""
00234         retval  = "\n      {}\n" + datadec + "};\n"
00235         retval += "#ifdef __MAKECINT__\n#pragma link C++ class " + \
00236                  "vector< %s >+;\n#endif\n\n" % className
00237         return retval
00238 
00239 
00240     @staticmethod
00241     def _createCppClass (objName):
00242         """Returns a string containing the '.C' file necessary to
00243         generate a shared object library with dictionary."""
00244         if not GenObject._objsDict.has_key (objName):
00245             # not good
00246             print "Error: GenObject does not know about object '%s'." % objName
00247             raise RuntimeError, "Failed to create C++ class."
00248         className   = GenObject.rootClassName (objName)
00249         diffName    = GenObject.rootDiffClassName (objName)
00250         contName    = GenObject.rootDiffContClassName (objName)
00251         goClass     = GenObject._setupClassHeader (className)
00252         diffClass   = GenObject._setupClassHeader (diffName)
00253         contClass   = GenObject._setupClassHeader (contName, noColon = True)
00254         goDataDec   = diffDataDec = contDataDec = "\n      // data members\n"
00255         first = True
00256         for key in sorted( GenObject._objsDict[objName].keys() ):
00257             if key.startswith ("_"): continue
00258             varTypeList = GenObject._objsDict[objName][key]
00259             cppType = GenObject._cppType[ varTypeList['varType'] ]
00260             default = varTypeList['default']
00261             if first:
00262                 first = False
00263             else:
00264                 goClass   += ",\n"
00265                 diffClass += ',\n'
00266             goClass   += "         %s (%s)" % (key, default)
00267             goDataDec += "      %s %s;\n" % (cppType, key)
00268             # is this a basic class?
00269             goType = varTypeList['varType']
00270             if goType in GenObject._basicSet:
00271                 # basic type
00272                 diffClass   += "         %s (%s),\n" % (key, default)
00273                 diffDataDec += "      %s %s;\n" % (cppType, key)
00274                 if goType == GenObject.types.string:
00275                     # string
00276                     otherKey = 'other_' + key
00277                     diffClass   += "         %s (%s)" % (otherKey, default)
00278                     diffDataDec += "      %s %s;\n" % (cppType, otherKey)
00279                 else:
00280                     # float, long, or int
00281                     deltaKey = 'delta_' + key
00282                     diffClass   += "         %s (%s)" % (deltaKey, default)
00283                     diffDataDec += "      %s %s;\n" % (cppType, deltaKey)
00284             else:
00285                 raise RuntimeError, "Shouldn't be here yet."
00286             # definition
00287         # do contClass
00288         if GenObject.isSingleton (objName):
00289             # singleton
00290             contDataDec += "      %s diff;\n" % diffName
00291             contDataDec += "      void setDiff (const %s &rhs)" % diffName + \
00292                            " { diff = rhs; }\n"
00293         else:
00294             # vector of objects
00295             contDataDec += "      void clear() {firstOnly.clear(); secondOnly.clear(); diff.clear(); }\n"
00296             contDataDec += "      %s::Collection firstOnly;\n"  % className
00297             contDataDec += "      %s::Collection secondOnly;\n" % className
00298             contDataDec += "      %s::Collection diff;\n"       % diffName
00299             # give me a way to clear them all at once
00300         # Finish off the classes
00301         goClass   += GenObject._finishClassHeader (className, goDataDec)
00302         diffClass += GenObject._finishClassHeader (diffName,  diffDataDec)
00303         contClass += GenObject._finishClassHeader (contName,  contDataDec)
00304         if objName == 'runevent':
00305             # we don't want a diff class for this
00306             diffClass = ''
00307             contClass = ''
00308         return goClass + diffClass + contClass
00309 
00310 
00311     @staticmethod
00312     def _loadGoRootLibrary ():
00313         """Loads Root shared object library associated with all
00314         defined GenObjects. Will create library if necessary."""
00315         print "Loading GO Root Library"
00316         key = "_loadedLibrary"        
00317         if GenObject._kitchenSinkDict.get (key):
00318             # Already done, don't do it again:
00319             return
00320         # Mark it as done
00321         GenObject._kitchenSinkDict[key] = True
00322         # Generate source code
00323         sourceCode = "#include <string>\n#include <vector>\n" \
00324                      + "using namespace std;\n"
00325         for objClassName in sorted( GenObject._objsDict.keys() ):
00326             sourceCode += GenObject._createCppClass (objClassName)
00327         GenObjectRootLibDir = "genobjectrootlibs"
00328         if not os.path.exists (GenObjectRootLibDir):
00329             os.mkdir (GenObjectRootLibDir)
00330         key = GenObject.checksum( sourceCode )
00331         basename = "%s_%s" % ("GenObject", key)
00332         SO = "%s/%s_C" % (GenObjectRootLibDir, basename)
00333         linuxSO = "%s.so" % SO
00334         windowsSO = "%s.dll" % SO
00335         if not os.path.exists (linuxSO) and not os.path.exists (windowsSO):
00336             print "creating SO"
00337             filename = "%s/%s.C" % (GenObjectRootLibDir, basename)
00338             if not os.path.exists (filename):
00339                 print "creating .C file"
00340                 target = open (filename, "w")
00341                 target.write (sourceCode)
00342                 target.close()
00343             else:
00344                 print "%s exists" % filename
00345             ## command = "echo .L %s+ | root.exe -b" % filename
00346             ## os.system (command)
00347             ROOT.gSystem.CompileMacro (filename, "k")
00348         else:
00349             print "loading %s" % SO
00350             ROOT.gSystem.Load(SO)
00351         return
00352 
00353 
00354     @staticmethod
00355     def _tofillGenObject():
00356         """Makes sure that I know how to read root files I made myself"""
00357         genObject = "GenObject"
00358         ntupleDict = GenObject._ntupleDict.setdefault (genObject, {})
00359         ntupleDict['_useChain'] = True
00360         ntupleDict['_tree'] = "goTree"
00361         for objName in GenObject._objsDict.keys():
00362             rootObjName = GenObject.rootClassName (objName)
00363             if GenObject.isSingleton (objName):
00364                 ntupleDict[objName] = objName
00365             else:
00366                 ntupleDict[objName] = objName + "s"
00367             tofillDict = GenObject._tofillDict.\
00368                          setdefault (genObject, {}).\
00369                          setdefault (objName, {})
00370             for varName in GenObject._objsDict [objName].keys():
00371                 # if the key starts with an '_', then it is not a
00372                 # variable, so don't treat it as one.
00373                 if varName.startswith ("_"):
00374                     continue
00375                 tofillDict[varName] = [ [(varName, GenObject._objFunc.obj)],
00376                                         {}]
00377 
00378 
00379     @staticmethod
00380     def prepareToLoadGenObject():
00381         """Makes all necessary preparations to load root files created
00382         by GenObject."""
00383         GenObject._tofillGenObject()
00384         GenObject._loadGoRootLibrary()
00385 
00386 
00387     @staticmethod
00388     def parseVariableTofill (fillname):
00389         """Returns tofill tuple made from string"""
00390         parts = GenObject._dotRE.split (fillname)
00391         partsList = []
00392         for part in parts:
00393             parenMatch = GenObject._parenRE.search (part)
00394             mode   = GenObject._objFunc.obj
00395             parens = []
00396             if parenMatch:
00397                 part   = parenMatch.group (1)
00398                 mode   = GenObject._objFunc.func
00399                 parens = \
00400                        GenObject._convertStringToParameters \
00401                        (parenMatch.group (2))
00402             partsList.append(  (part, mode, parens) )
00403         return partsList
00404 
00405     @staticmethod
00406     def _fixLostGreaterThans (handle):
00407         offset = handle.count ('<') - handle.count('>')
00408         if not offset:
00409             return handle
00410         if offset < 0:
00411             print "Huh?  Too few '<' for each '>' in handle '%'" % handle
00412             return handle
00413         return handle + ' >' * offset
00414 
00415 
00416     @staticmethod
00417     def loadConfigFile (configFile):
00418         """Loads configuration file"""
00419         objName    = ""
00420         tupleName  = ""
00421         tofillName = ""
00422         modeEnum   = Enumerate ("none define tofill ntuple", "mode")
00423         mode       = modeEnum.none
00424         try:
00425             config = open (configFile, 'r')
00426         except:
00427             raise RuntimeError, "Can't open configuration '%s'" % configFile
00428         for lineNum, fullLine in enumerate (config):
00429             fullLine = fullLine.strip()
00430             # get rid of comments
00431             line = GenObject._commentRE.sub ('', fullLine)
00432             # Is there anything on this line?
00433             if not GenObject._nonSpacesRE.search (line):
00434                 # Nothing to see here folks.  Keep moving....
00435                 continue
00436             ###################
00437             ## Bracket Match ##
00438             ###################
00439             bracketMatch = GenObject._bracketRE.search (line)
00440             if bracketMatch:
00441                 # a header
00442                 section = bracketMatch.group(1)
00443                 words = GenObject._spacesRE.split( section )
00444                 if len (words) < 1:
00445                     raise RuntimeError, "Don't understand line '%s'(%d)" \
00446                           % (fullLine, lineNum)
00447                 # The first word is the object name
00448                 # reset the rest of the list
00449                 objName = words[0]
00450                 words = words[1:]
00451                 colonWords = GenObject._colonRE.split (objName)
00452                 if len (colonWords) > 3:
00453                     raise RuntimeError, "Don't understand line '%s'(%d)" \
00454                           % (fullLine, lineNum)
00455                 if len (colonWords) == 1:
00456                     ##########################
00457                     ## GenObject Definition ##
00458                     ##########################
00459                     mode = modeEnum.define
00460                     for word in words:
00461                         if GenObject._singletonRE.match (word):
00462                             #GenObject._singletonSet.add (objName)
00463                             objsDict = GenObject._objsDict.\
00464                                        setdefault (objName, {})
00465                             objsDict['_singleton'] = True
00466                             continue
00467                         # If we're still here, then we didn't have a valid
00468                         # option.  Complain vociferously
00469                         print "I don't understand '%s' in section '%s' : %s" \
00470                               % (word, section, mode)
00471                         raise RuntimeError, \
00472                               "Config file parser error '%s'(%d)" \
00473                               % (fullLine, lineNum)
00474                 elif len (colonWords) == 2:
00475                     #######################
00476                     ## Ntuple Definition ##
00477                     #######################
00478                     mode = modeEnum.ntuple
00479                     ntupleDict = GenObject._ntupleDict.\
00480                                 setdefault (colonWords[0], {})
00481                     ntupleDict['_tree'] = colonWords[1]
00482                 else:
00483                     ##########################
00484                     ## Object 'tofill' Info ##
00485                     ##########################
00486                     mode = modeEnum.tofill
00487                     objName    = colonWords [0]
00488                     tupleName  = colonWords [1]
00489                     tofillName = colonWords [2]
00490                     ntupleDict = GenObject._ntupleDict.\
00491                                  setdefault (tupleName, {})
00492                     ntupleDict[objName] = tofillName
00493                     for word in words:
00494                         # label
00495                         labelMatch = GenObject._labelRE.search (word)
00496                         if labelMatch:
00497                             label = tuple( GenObject._commaRE.\
00498                                            split(  labelMatch.group (1) ) )
00499                             ntupleDict.setdefault ('_label', {}).\
00500                                                   setdefault (tofillName,
00501                                                               label)
00502                             continue
00503                         # shortcut
00504                         shortcutMatch = GenObject._shortcutRE.search (word)
00505                         if shortcutMatch:
00506                             shortcutFill = \
00507                                          GenObject.\
00508                                          parseVariableTofill ( shortcutMatch.\
00509                                                                group(1) )
00510                             ntupleDict.setdefault ('_shortcut', {}).\
00511                                                   setdefault (tofillName,
00512                                                               shortcutFill)
00513                             continue
00514                         # type/handle
00515                         typeMatch = GenObject._typeRE.search (word)
00516                         if typeMatch:
00517                             handleString = \
00518                                          GenObject.\
00519                                          _fixLostGreaterThans (typeMatch.group(1))
00520                             handle = Handle( handleString )
00521                             ntupleDict.setdefault ('_handle', {}).\
00522                                                   setdefault (tofillName,
00523                                                               handle)
00524                             continue
00525                         # alias 
00526                         aliasMatch = GenObject._aliasRE.search (word)
00527                         if aliasMatch:
00528                             ntupleDict.setdefault ('_alias', {}).\
00529                                                   setdefault (tofillName,
00530                                                               aliasMatch.\
00531                                                               group(1))
00532                             continue
00533                         # is this a lost '<'
00534                         if word == '>':
00535                             continue
00536                         # If we're still here, then we didn't have a valid
00537                         # option.  Complain vociferously
00538                         print "I don't understand '%s' in section '%s' : %s" \
00539                               % (word, section, mode)
00540                         raise RuntimeError, \
00541                               "Config file parser error '%s'(%d)" \
00542                               % (fullLine, lineNum)
00543             ##############
00544             ## Variable ##
00545             ##############
00546             else:
00547                 # a variable
00548                 if modeEnum.none == mode:
00549                     # Poorly formatted 'section' tag
00550                     print "I don't understand line '%s'." % fullLine
00551                     raise RuntimeError, \
00552                           "Config file parser error '%s'(%d)" \
00553                           % (fullLine, lineNum)
00554                 colonWords = GenObject._colonRE.split (line, 1)
00555                 if len (colonWords) < 2:
00556                     # Poorly formatted 'section' tag
00557                     print "I don't understand line '%s'." % fullLine
00558                     raise RuntimeError, \
00559                           "Config file parser error '%s'(%d)" \
00560                           % (fullLine, lineNum)
00561                 varName = colonWords[0]
00562                 option  = colonWords[1]
00563                 if option:
00564                     pieces = GenObject._spacesRE.split (option)
00565                 else:
00566                     pieces = []
00567                 if modeEnum.define == mode:
00568                     #########################
00569                     ## Variable Definition ##
00570                     #########################
00571                     # is this a variable or an option?
00572                     if varName.startswith("-"):
00573                         # this is an option
00574                         if "-equiv" == varName.lower():
00575                             for part in pieces:
00576                                 halves = part.split (",")
00577                                 if 2 != len (halves):
00578                                     print "Problem with -equiv '%s' in '%s'" % \
00579                                           (part, section)
00580                                     raise RuntimeError, \
00581                                           "Config file parser error '%s'(%d)" \
00582                                           % (fullLine, lineNum)
00583                                 if halves[1]:
00584                                     halves[1] = float (halves[1])
00585                                     if not halves[1] >= 0:
00586                                         print "Problem with -equiv ",\
00587                                               "'%s' in '%s'" % \
00588                                               (part, section)
00589                                         raise RuntimeError, \
00590                                               "Config file parser error '%s'(%d)" \
00591                                               % (fullLine, lineNum)
00592                                 GenObject.setEquivExpression (section,
00593                                                               halves[0],
00594                                                               halves[1])
00595                         continue
00596                     # If we're here, then this is a variable
00597                     optionsDict = {}
00598                     for word in pieces:
00599                         typeMatch = GenObject._typeRE.search (word)
00600                         if typeMatch and \
00601                                GenObject.types.isValidKey (typeMatch.group(1)):
00602                             varType = typeMatch.group(1).lower()
00603                             optionsDict['varType'] = GenObject.types (varType)
00604                             continue
00605                         defaultMatch = GenObject._defaultRE.search (word)
00606                         if defaultMatch:
00607                             optionsDict['default'] = defaultMatch.group(1)
00608                             continue
00609                         precMatch = GenObject._precRE.search (word)
00610                         if precMatch:
00611                             optionsDict['prec'] = float (precMatch.group (1))
00612                             continue
00613                         formMatch = GenObject._formRE.search (word)
00614                         if formMatch:
00615                             form = GenObject._doublePercentRE.\
00616                                    sub ('%', formMatch.group (1))
00617                             optionsDict['form'] = form
00618                             continue
00619                         # If we're still here, then we didn't have a valid
00620                         # option.  Complain vociferously
00621                         print "I don't understand '%s' in section '%s'." \
00622                               % (word, option)
00623                         raise RuntimeError, \
00624                               "Config file parser error '%s'(%d)" \
00625                               % (fullLine, lineNum)
00626                     GenObject.addObjectVariable (objName, varName, \
00627                                                  **optionsDict)
00628                 else: # if modeEnum.define != mode
00629                     ############################
00630                     ## Variable 'tofill' Info ##
00631                     ############################
00632                     if len (pieces) < 1:
00633                         continue
00634                     fillname, pieces = pieces[0], pieces[1:]
00635                     # I don't yet have any options available here, but
00636                     # I'm keeping the code here for when I add them.
00637                     optionsDict = {}
00638                     for word in pieces:
00639                         # If we're still here, then we didn't have a valid
00640                         # option.  Complain vociferously
00641                         print "I don't understand '%s' in section '%s'." \
00642                               % (word, option)
00643                         raise RuntimeError, \
00644                               "Config file parser error '%s'(%d)" \
00645                               % (fullLine, lineNum)
00646                     tofillDict = GenObject._tofillDict.\
00647                                  setdefault (tupleName, {}).\
00648                                  setdefault (objName, {})
00649                     partsList = GenObject.parseVariableTofill (fillname)
00650                     tofillDict[varName] = [partsList, optionsDict]
00651         # for line
00652         for objName in GenObject._objsDict:
00653             # if this isn't a singleton, add 'index' as a variable
00654             if not GenObject.isSingleton (objName):
00655                 GenObject.addObjectVariable (objName, 'index',
00656                                              varType = GenObject.types.int,
00657                                              form = '%3d')
00658 
00659 
00660     @staticmethod
00661     def changeVariable (tupleName, objName, varName, fillname):
00662         """Updates the definition used to go from a Root object to a
00663         GenObject.  'tupleName' and 'objName' must already be defined."""
00664         parts = GenObject._dotRE.split (fillname)
00665         partsList = []
00666         for part in parts:
00667             parenMatch = GenObject._parenRE.search (part)
00668             mode   = GenObject._objFunc.obj
00669             parens = []
00670             if parenMatch:
00671                 part   = parenMatch.group (1)
00672                 mode   = GenObject._objFunc.func
00673                 parens = \
00674                        GenObject._convertStringToParameters \
00675                        (parenMatch.group (2))
00676             partsList.append(  (part, mode, parens) )
00677         GenObject._tofillDict[tupleName][objName][varName] = [partsList, {}]
00678 
00679 
00680 
00681     @staticmethod
00682     def evaluateFunction (obj, partsList, debug=False):
00683         """Evaluates function described in partsList on obj"""
00684         for part in partsList:
00685             if debug: warn (part, spaces=15)
00686             obj = getattr (obj, part[0])
00687             if debug: warn (obj, spaces=15)
00688             # if this is a function instead of a data member, make
00689             # sure you call it with its arguments:
00690             if GenObject._objFunc.func == part[1]:
00691                 # Arguments are stored as a list in part[2]
00692                 obj = obj (*part[2])
00693                 if debug: warn (obj, spaces=18)
00694         return obj
00695 
00696 
00697     @staticmethod
00698     def _genObjectClone (objName, tupleName, obj, index = -1):
00699         """Creates a GenObject copy of Root object"""
00700         debug = GenObject._kitchenSinkDict.get ('debug', False)
00701         if objName == 'runevent':
00702             debug = False
00703         tofillObjDict = GenObject._tofillDict.get(tupleName, {})\
00704                         .get(objName, {})
00705         genObj = GenObject (objName)
00706         origObj = obj
00707         if debug: warn (objName, spaces = 9)
00708         for genVar, ntDict in tofillObjDict.iteritems():
00709             if debug: warn (genVar, spaces = 12)
00710             # lets work our way down the list
00711             partsList = ntDict[0]
00712             # start off with the original object
00713             obj = GenObject.evaluateFunction (origObj, partsList, debug)
00714             if debug: warn (obj, spaces=12)
00715             setattr (genObj, genVar, obj)
00716         # Do I need to store the index of this object?
00717         if index >= 0:
00718             setattr (genObj, 'index', index)
00719         return genObj
00720 
00721 
00722     @staticmethod
00723     def _rootObjectCopy (goSource, rootTarget):
00724         """Copies information from goSourse into Root Object"""
00725         objName = goSource._objName
00726         for varName in GenObject._objsDict [objName].keys():
00727             # if the key starts with an '_', then it is not a
00728             # variable, so don't treat it as one.
00729             if varName.startswith ("_"):
00730                 continue
00731             setattr( rootTarget, varName, goSource (varName) )
00732         
00733         
00734     @staticmethod
00735     def _rootObjectClone (obj):
00736         """Creates the approprite type of Root object and copies the
00737         information into it from the GO object."""
00738         objName = obj._objName
00739         classObj = GenObject._rootClassDict.get (objName)
00740         if not classObj:
00741             goName = GenObject.rootClassName (objName)
00742             classObj = GenObject._rootClassDict[ goName ]
00743         rootObj = classObj()
00744         for varName in GenObject._objsDict [objName].keys():
00745             setattr( rootObj, varName, obj (varName) )
00746         return rootObj
00747 
00748 
00749     @staticmethod
00750     def _rootDiffObject (obj1, obj2, rootObj = 0):
00751         """Given to GOs, it will create and fill the corresponding
00752         root diff object"""
00753         objName = obj1._objName
00754         # if we don't already have a root object, create one
00755         if not rootObj:
00756             diffName = GenObject.rootDiffClassName( objName )
00757             rootObj = GenObject._rootClassDict[diffName]()
00758         for varName in GenObject._objsDict [objName].keys():
00759             if varName.startswith ("_"): continue
00760             goType = GenObject._objsDict[objName][varName]['varType']
00761             if not goType in GenObject._basicSet:
00762                 # not yet
00763                 continue
00764             setattr( rootObj, varName, obj1 (varName) )            
00765             if  goType == GenObject.types.string:
00766                 # string
00767                 otherName = 'other_' + varName
00768                 if obj1 (varName) != obj2 (varName):
00769                     # don't agree
00770                     setattr( rootObj, otherName, obj2 (varName) )
00771                 else:
00772                     # agree
00773                     setattr( rootObj, otherName, '' )
00774             else:
00775                 # float, long, or int
00776                 deltaName = 'delta_' + varName
00777                 setattr( rootObj, deltaName,
00778                          obj2 (varName) - obj1 (varName) )
00779         return rootObj
00780 
00781 
00782     @staticmethod
00783     def setupOutputTree (outputFile, treeName, treeDescription = "",
00784                          otherNtupleName = ""):
00785         """Opens the output file, loads all of the necessary shared
00786         object libraries, and returns the output file and tree.  If
00787         'otherNtupleName' is given, it will check and make sure that
00788         only objects that are defined in it are written out."""
00789         rootfile = ROOT.TFile.Open (outputFile, "recreate")
00790         tree = ROOT.TTree (treeName, treeDescription)
00791         GenObject._loadGoRootLibrary()
00792         for objName in sorted (GenObject._objsDict.keys()):
00793             classname = GenObject.rootClassName (objName)
00794             rootObj = \
00795                     GenObject._rootClassDict[objName] = \
00796                     getattr (ROOT, classname)
00797             if GenObject.isSingleton (objName):
00798                 # singleton object
00799                 obj = GenObject._rootObjectDict[objName] = rootObj()
00800                 tree.Branch (objName, classname, obj)
00801             else:
00802                 # vector of objects - PLEASE don't forget the '()' on
00803                 # the end of the declaration.  Without this, you are
00804                 # defining a type, not instantiating an object.
00805                 vec = \
00806                     GenObject._rootObjectDict[objName] = \
00807                     ROOT.std.vector( rootObj )()
00808                 branchName = objName + "s"
00809                 vecName = "vector<%s>" % classname
00810                 tree.Branch( branchName, vecName, vec)
00811             # end else if isSingleton
00812         # end for objName
00813         return rootfile, tree
00814 
00815 
00816     @staticmethod
00817     def setupDiffOutputTree (outputFile, diffName, missingName,
00818                              diffDescription = '', missingDescription = ''):
00819         """Opens the diff output file, loads all of the necessary
00820         shared object libraries, and returns the output file and tree.b"""
00821         rootfile = ROOT.TFile.Open (outputFile, "recreate")
00822         GenObject._loadGoRootLibrary()
00823         # diff tree
00824         diffTree = ROOT.TTree (diffName, diffDescription)
00825         runEventObject = getattr (ROOT, 'go_runevent')()
00826         diffTree.Branch ('runevent', 'go_runevent', runEventObject)
00827         GenObject._rootClassDict['runevent'] = runEventObject
00828         for objName in sorted (GenObject._objsDict.keys()):
00829             if objName == 'runevent': continue
00830             classname = GenObject.rootClassName (objName)
00831             GenObject._rootClassDict[classname] = getattr (ROOT, classname)
00832             contName = GenObject.rootDiffContClassName (objName)
00833             diffName = GenObject.rootDiffClassName (objName)
00834             rootObj = GenObject._rootClassDict[contName] = \
00835                     getattr (ROOT, contName)
00836             GenObject._rootClassDict[diffName] = getattr (ROOT, diffName)
00837             obj = GenObject._rootObjectDict[objName] = rootObj()
00838             diffTree.Branch (objName, contName, obj)
00839         # missing tree
00840         missingTree = ROOT.TTree (missingName, missingDescription)
00841         rootRunEventClass = getattr (ROOT, 'go_runevent')
00842         firstOnly  = GenObject._rootClassDict['firstOnly'] = \
00843                      ROOT.std.vector( rootRunEventClass ) ()
00844         secondOnly = GenObject._rootClassDict['secondOnly'] = \
00845                      ROOT.std.vector( rootRunEventClass ) ()
00846         missingTree.Branch ('firstOnly',  'vector<go_runevent>', firstOnly) 
00847         missingTree.Branch ('secondOnly', 'vector<go_runevent>', secondOnly) 
00848         return rootfile, diffTree, missingTree
00849 
00850 
00851     @staticmethod
00852     def _fillRootObjects (event):
00853         """Fills root objects from GenObject 'event'"""
00854         for objName, obj in sorted (event.iteritems()):
00855             if GenObject.isSingleton (objName):
00856                 # Just one
00857                 GenObject._rootObjectCopy (obj,
00858                                            GenObject._rootObjectDict[objName])
00859             else:
00860                 # a vector
00861                 vec = GenObject._rootObjectDict[objName]
00862                 vec.clear()
00863                 for goObj in obj:
00864                     vec.push_back( GenObject._rootObjectClone (goObj) )
00865 
00866 
00867     @staticmethod
00868     def _fillRootDiffs (event1, event2):
00869         """Fills root diff containers from two GenObject 'event's"""
00870         
00871 
00872 
00873     @staticmethod
00874     def isSingleton (objName):
00875         """Returns true if object is a singleton"""
00876         return GenObject._objsDict[objName].get('_singleton')
00877 
00878 
00879     @staticmethod
00880     def loadEventFromTree (eventTree, eventIndex,
00881                            onlyRunEvent  = False):
00882         """Loads event information from Root file (as interfaced by
00883         'cmstools.EventTree' or 'ROOT.TChain').  Returns a dictionary
00884         'event' containing lists of objects or singleton object.  If
00885         'onlyRunEvent' is et to True, then only run and event number
00886         is read in from the tree."""
00887         debug     = GenObject._kitchenSinkDict.get ('debug', False)
00888         tupleName = GenObject._kitchenSinkDict[eventTree]['tupleName']
00889         event = {}
00890         # is this a cint tree
00891         isChain = eventTree.__class__.__name__ == 'TChain'
00892         if isChain:
00893             # This means that 'eventTree' is a ROOT.TChain
00894             eventTree.GetEntry (eventIndex)
00895         else:
00896             # This means that 'eventTree' is a FWLite Events
00897             eventTree.to(eventIndex)
00898         tofillDict = GenObject._tofillDict.get (tupleName)
00899         ntupleDict = GenObject._ntupleDict.get (tupleName)
00900         if not tofillDict:
00901             print "Don't know how to fill from '%s' ntuple." % tupleName
00902             return
00903         eventBranchName = ntupleDict['runevent']
00904         for objName in tofillDict:
00905             branchName = ntupleDict[objName]
00906             if onlyRunEvent and branchName != eventBranchName:
00907                 # not now
00908                 continue
00909             # Have we been given 'tofill' info for this object?
00910             if not branchName:
00911                 # guess not
00912                 continue
00913             if isChain:
00914                 # Root TChain
00915                 objects = getattr (eventTree, branchName)
00916             else:
00917                 # FWLite
00918                 shortcut = ntupleDict.get('_shortcut', {}).get(branchName)
00919                 if shortcut:
00920                     objects = GenObject.evaluateFunction (eventTree, shortcut)
00921                 else:
00922                     eventTree.toBegin()
00923                     handle = ntupleDict.get('_handle', {}).get(branchName)
00924                     label  = ntupleDict.get('_label' , {}).get(branchName)
00925                     if not handle or not label:
00926                         raise RuntimeError, "Missing handle or label for '%s'"\
00927                               % branchName
00928                     if not eventTree.getByLabel (label, handle):
00929                         raise RuntimeError, "not able to get %s for %s" \
00930                               % (label, branchName)
00931                     objects = handle.product()
00932             # is this a singleton?
00933             if GenObject.isSingleton (objName):
00934                 event[objName] = GenObject.\
00935                                  _genObjectClone (objName,
00936                                                   tupleName,
00937                                                   objects)
00938                 continue
00939             # if we're here then we have a vector of items
00940             if debug: warn (objName, spaces = 3)
00941             event[objName] = []
00942             for index, obj in enumerate (objects):
00943                 event[objName].append( GenObject.\
00944                                        _genObjectClone (objName,
00945                                                         tupleName,
00946                                                         obj,
00947                                                         index) )
00948             del objects
00949             # end for obj        
00950         ## if not isChain:
00951         ##     del rootEvent
00952         # end for objName
00953         return event
00954 
00955 
00956     @staticmethod
00957     def printEvent (event):
00958         """Prints out event dictionary.  Mostly for debugging"""
00959         # Print out all singletons first
00960         for objName, obj in sorted (event.iteritems()):
00961             #obj = event[objName]
00962             # is this a singleton?
00963             if GenObject.isSingleton (objName):
00964                 print "%s: %s" % (objName, obj)
00965         # Now print out all vectors
00966         for objName, obj in sorted (event.iteritems()):
00967             #obj = event[objName]
00968             # is this a singleton?
00969             if not GenObject.isSingleton (objName):
00970                 # o.k. obj is a vector
00971                 print "%s:" % objName
00972                 for single in obj:
00973                     print "  ", single
00974         print
00975 
00976 
00977     @staticmethod
00978     def setAliases (eventTree, tupleName):
00979         """runs SetAlias on all saved aliases"""
00980         aliases = GenObject._ntupleDict[tupleName].get('_alias', {})
00981         for name, alias in aliases.iteritems():
00982             eventTree.SetAlias (name, alias)
00983 
00984 
00985     @staticmethod
00986     def changeAlias (tupleName, name, alias):
00987         """Updates an alias for an object for a given tuple"""
00988         aliasDict = GenObject._ntupleDict[tupleName]['_alias']
00989         if not aliasDict.has_key (name):
00990             raise RuntimeError, "unknown name '%s' in tuple '%s'" % \
00991                   (name, tupleName)
00992         aliasDict[name] = alias
00993 
00994 
00995     @staticmethod
00996     def changeLabel (tupleName, objectName, label):
00997         """Updates an label for an object for a given tuple"""
00998         labelDict = GenObject._ntupleDict[tupleName]['_label']
00999         if not labelDict.has_key (objectName):
01000             raise RuntimeError, "unknown name '%s' in tuple '%s'" % \
01001                   (objectName, tupleName)
01002         label = tuple( GenObject._commaRE.split( label ) )
01003         labelDict[objectName] = label
01004 
01005 
01006     @staticmethod
01007     def prepareTuple (tupleName, files, numEventsWanted = 0):
01008         """Given the tuple name and list of files, returns either a
01009         TChain or EventTree, and number of entries"""
01010         if "GenObject" == tupleName:
01011             GenObject.prepareToLoadGenObject()            
01012         if not isinstance (files, list):
01013             # If this isn't a list, make it one
01014             files = [files]
01015             ntupleDict = GenObject._ntupleDict[tupleName]
01016         treeName = ntupleDict["_tree"]
01017         if ntupleDict.get('_useChain'):
01018             chain = ROOT.TChain (treeName)
01019             for filename in files:
01020                 chain.AddFile (filename)
01021                 numEntries = chain.GetEntries()
01022         # Are we using a chain or EventTree here?
01023         else:
01024             chain = Events (files, forceEvent=True)
01025             numEntries = chain.size()
01026         chainDict = GenObject._kitchenSinkDict.setdefault (chain, {})
01027         if numEventsWanted and numEventsWanted < numEntries:
01028             numEntries = numEventsWanted
01029         chainDict['numEntries'] = numEntries
01030         chainDict['tupleName' ] = tupleName
01031         return chain
01032 
01033 
01034     @staticmethod
01035     def getRunEventEntryDict (chain, tupleName, numEntries):
01036         """Returns a dictionary of run, event tuples to entryIndicies"""
01037         reeDict = {}
01038         for entryIndex in xrange (numEntries):
01039             event = GenObject.loadEventFromTree (chain,
01040                                                  entryIndex,
01041                                                  onlyRunEvent = True)
01042             runevent = event['runevent']
01043             reeDict[ GenObject._re2key (runevent) ] = entryIndex
01044             #reeDict[ "one two three" ] = entryIndex
01045             del event
01046         return reeDict
01047 
01048 
01049     @staticmethod
01050     def _re2key (runevent):
01051         """Given a GO 'runevent' object, returns a sortable key"""
01052         # if we don't know how to make this object yet, let's figure
01053         # it out
01054         if not GenObject._runEventListDone:
01055             GenObject._runEventListDone = True
01056             ignoreSet = set( ['run', 'event'] )
01057             for varName in sorted (runevent.__dict__.keys()):
01058                 if varName.startswith ('_') or varName in ignoreSet:
01059                     continue
01060                 form = runevent.getVariableProperty (varName, "form")
01061                 if not form:
01062                     form = '%s'                
01063                 GenObject._runEventList.append ((varName, form))
01064         key = 'run:%d event:%d' % (runevent.run, runevent.event)
01065         for items in GenObject._runEventList:
01066             varName = items[0]
01067             form    = ' %s:%s' % (varName, items[1])
01068             key += form % runevent.getVariableProperty (varName)
01069         return key
01070 
01071 
01072     @staticmethod
01073     def _key2re (key, runevent=None):
01074         """Given a key, returns a GO 'runevent' object"""
01075         if not runevent:
01076             runevent = GenObject ('runevent')
01077         words = GenObject._spacesRE.split (key)
01078         for word in words:
01079             match = GenObject._singleColonRE.search (word)
01080             if match:
01081                 # for now, I'm assuming everything in the runevent
01082                 # tuple is an integer.  If this isn't the case, I'll
01083                 # have to come back and be more clever here.
01084                 runevent.__setattr__ (match.group(1), int( match.group(2) ))
01085         return runevent
01086                                      
01087 
01088     @staticmethod
01089     def compareRunEventDicts (firstDict, secondDict):
01090         """Compares the keys of the two dicts and returns three sets:
01091         the overlap, first but not second, and second but not first."""
01092         overlap    = set()
01093         firstOnly  = set()
01094         secondOnly = set()
01095         # loop over the keys of the first dict and compare to second dict
01096         for key in firstDict.keys():
01097             if secondDict.has_key (key):
01098                 overlap.add (key)
01099             else:
01100                 firstOnly.add (key)
01101         # now loop over keys of second dict and only check for missing
01102         # entries in first dict
01103         for key in secondDict.keys():
01104             if not firstDict.has_key (key):
01105                 secondOnly.add (key)
01106         # All done
01107         return overlap, firstOnly, secondOnly
01108 
01109 
01110     @staticmethod
01111     def pairEquivalentObjects (vec1, vec2):
01112         """Finds the equivalent objects in the two vectors"""
01113         len1, len2 = len (vec1), len (vec2)
01114         debug = GenObject._kitchenSinkDict.get ('debug', False)        
01115         if not len1 or not len2:
01116             # Nothing to see here folks.  Keep moving.
01117             if len1:
01118                 noMatch1Set = set( xrange(len1) )
01119             else:
01120                 noMatch1Set = set ()
01121             if len2:
01122                 noMatch2Set = set( xrange(len2) )
01123             else:
01124                 noMatch2Set = set ()
01125             if debug: warn ("Nothing found", sapces=6)
01126             return set(), noMatch1Set, noMatch2Set
01127         objName = vec1[0]._objName
01128         equivList = GenObject._equivDict[objName]
01129         firstDict = {}
01130         secondDict = {}
01131         # let's see if we're only using 'index' and nothing else
01132         if GenObject._kitchenSinkDict.get ('strictPairing') or \
01133                equivList == [('index', 0)]:
01134             # we're only matching on index, nothing else matters
01135             matchedSet = set (zip ( range( min (len1, len2) ),
01136                                     range( min (len1, len2) ) ) )
01137             if len1 > len2:
01138                 # since main pairing goes from 0..len2-1, we now want
01139                 # to go from len2..len1 inclusive
01140                 noMatch1Set = set (range(len2, len1 + 1))
01141             else:
01142                 noMatch1Set = set()
01143             if len2 > len1:
01144                 # same logic as above
01145                 noMatch2Set = set (range(len1, len2 + 1))
01146             else:
01147                 noMatch2Set = set()
01148             return matchedSet, noMatch1Set, noMatch2Set
01149         ##  # If we're still here, that means that we aren't matching on
01150         ##  # just index.  Instead of jumping to O(N^2), let's assume that
01151         ##  # both branches have everything in order and try to pair like
01152         ##  # that.  Anything not paired will be checked in a third pass.
01153         ##  unpairedFirst  = []
01154         ##  unpairedSecond = []
01155         ##  for index in xrange( min (len1, len2) ):
01156         ##      obj1 = vec1[index1]
01157         ##      total = 0.
01158         ##      obj2 = vec2[index2]
01159         ##      ok = True
01160         
01161         # First, look for vec2 objects that are equivalent to a
01162         # given vec1 object.
01163         for index1 in xrange (len1):
01164             objList = []
01165             obj1 = vec1[index1]
01166             for index2 in xrange (len2):
01167                 total = 0.
01168                 obj2 = vec2[index2]
01169                 ok = True
01170                 for equiv in equivList:
01171                     var, precision = equiv[0], equiv[1]
01172                     val1 = obj1 (var)
01173                     val2 = obj2 (var)
01174                     # Do we check equality or a precision
01175                     if precision:
01176                         value = abs (val1 - val2) / precision
01177                         if value >= 1.:
01178                             ok = False
01179                             break
01180                         total += value ** 2
01181                     elif val1 != val2:
01182                         ok = False
01183                         break
01184                 if ok:
01185                     objList.append( (total, index2) )
01186             objList.sort()
01187             firstDict[index1] = objList
01188         # Now do the same thing, but this time look for vec1 objects
01189         # that are equivalent to a given vec2 object
01190         for index2 in xrange (len2):
01191             objList = []
01192             obj2 = vec2[index2]
01193             for index1 in xrange (len1):
01194                 total = 0.
01195                 obj1 = vec1[index1]
01196                 ok = True
01197                 for equiv in equivList:
01198                     var, precision = equiv[0], equiv[1]
01199                     val2 = obj2 (var)
01200                     val1 = obj1 (var)
01201                     # Do we check equality or a precision
01202                     if precision:
01203                         value = abs (val2 - val1) / precision
01204                         if value > 1.:
01205                             ok = False
01206                             break
01207                         total += value ** 2
01208                     elif val2 != val1:
01209                         ok = False
01210                         break
01211                 if ok:
01212                     objList.append( (total, index1) )
01213             objList.sort()
01214             secondDict[index2] = objList
01215         # O.k. Now that we have the candidate matches, lets see who is
01216         # really matched.
01217         matchedSet = set()
01218         noMatch1Set = set()
01219         firstDictKeys = sorted (firstDict.keys())
01220         for index1 in firstDictKeys:
01221             list1 = firstDict[index1]
01222             # do I have a match?
01223             if not len (list1):
01224                 # no match
01225                 noMatch1Set.add (index1)
01226                 continue
01227             # we've got at least one match
01228             best1 = list1[0]
01229             index2 = best1[1]
01230             # Does this one match me?
01231             list2 = secondDict.get (index2, [])
01232             if len(list2) and list2[0][1] == index1:
01233                 matchedSet.add( (index1, index2) )
01234                 # get rid of the 2nd key hash
01235                 del firstDict[index1]
01236                 del secondDict[index2]
01237             else:
01238                 # no match
01239                 noMatch1Set.add (index1)
01240         noMatch2Set = set( secondDict.keys() )
01241         return matchedSet, noMatch1Set, noMatch2Set
01242 
01243 
01244     @staticmethod
01245     def compareTwoItems (item1, item2):
01246         """Compares all of the variables making sure they are the same
01247         on the two objects."""
01248         objName = item1._objName
01249         problems = {}
01250         relative = GenObject._kitchenSinkDict.get ('relative', False)
01251         for varName in GenObject._objsDict[objName].keys():
01252             prec = item1.getVariableProperty (varName, 'prec')
01253             if prec:
01254                 # we want to check within a precision
01255                 if relative:
01256                     val1 = item1(varName)
01257                     val2 = item2(varName)
01258                     numerator = 2 * abs (val1 - val2)
01259                     denominator = abs(val1) + abs(val2)
01260                     if not denominator:
01261                         # both are exactly zero, so there's no
01262                         # disagreement here.
01263                         continue
01264                     value = numerator / denominator
01265                     if value > prec:
01266                         # we've got a problem
01267                         problems[varName] = value                    
01268                 else:
01269                     value = abs( item1(varName) - item2(varName) )
01270                     if value > prec:
01271                         # we've got a problem
01272                         problems[varName] = value
01273             else:
01274                 # we want to check equality
01275                 if item1(varName) != item2(varName):
01276                     # we have a problem.  sort the values
01277                     val1, val2 = item1(varName), item2(varName)
01278                     if val1 > val2:
01279                         val1, val2 = val2, val1
01280                     problems[varName] = "%s != %s" % (val1, val2)
01281         # end for
01282         return problems
01283 
01284 
01285     @staticmethod
01286     def blurEvent (event, value, where = ""):
01287         """For debugging purposes only.  Will deliberately change
01288         values of first tree to verify that script is correctly
01289         finding problems."""
01290         for objName in sorted (event.keys()):
01291             if "runevent" == objName:
01292                 # runevent is a special case.  We don't compare these
01293                 continue
01294             if GenObject.isSingleton (objName):
01295                 # I'll add this in later.  For now, just skip it
01296                 continue
01297             count = 0
01298             for obj in event[objName]:
01299                 count += 1
01300                 for varName in GenObject._objsDict[objName].keys():
01301                     if isinstance (obj.__dict__[varName], str):
01302                         # don't bother
01303                         continue
01304                     randNumber = random.random()
01305                     #print "rN", randNumber
01306                     if randNumber < GenObject._kitchenSinkDict['blurRate']:
01307                         print "  %s: changing '%s' of '%s:%d'" \
01308                               % (where, varName, obj._objName, count)
01309                         ## print "objdict", obj.__dict__.get(varName), ':',\
01310                         ##       value
01311                         obj.__dict__[varName] += value
01312 
01313 
01314     @staticmethod
01315     def compareTwoTrees (chain1, chain2, **kwargs):
01316         """Given all of the necessary information, this routine will
01317         go through and compare two trees making sure they are
01318         'identical' within requested precision.  If 'diffOutputName'
01319         is passed in, a root file with a diffTree and missingTree will
01320         be produced."""
01321         print "Comparing Two Trees"
01322         diffOutputName = kwargs.get ('diffOutputName')
01323         tupleName1  = GenObject._kitchenSinkDict[chain1]['tupleName']
01324         numEntries1 = GenObject._kitchenSinkDict[chain1]['numEntries']
01325         tupleName2  = GenObject._kitchenSinkDict[chain2]['tupleName']
01326         numEntries2 = GenObject._kitchenSinkDict[chain2]['numEntries']
01327         debug       = GenObject._kitchenSinkDict.get ('debug', False)
01328         ree1 = GenObject.getRunEventEntryDict (chain1, tupleName1, numEntries1)
01329         ree2 = GenObject.getRunEventEntryDict (chain2, tupleName2, numEntries2)
01330         overlap, firstOnly, secondOnly = \
01331                  GenObject.compareRunEventDicts (ree1, ree2)
01332         if diffOutputName:
01333             rootfile, diffTree, missingTree = \
01334                       GenObject.setupDiffOutputTree (diffOutputName,
01335                                                      'diffTree',
01336                                                      'missingTree')
01337             if firstOnly:
01338                 vec = GenObject._rootClassDict['firstOnly']
01339                 for key in firstOnly:
01340                     runevent = GenObject._key2re (key)
01341                     vec.push_back( GenObject._rootObjectClone( runevent ) )
01342             if secondOnly:
01343                 vec = GenObject._rootClassDict['secondOnly']
01344                 for key in secondOnly:
01345                     runevent = GenObject._key2re (key)
01346                     vec.push_back( GenObject._rootObjectClone( runevent ) )
01347             missingTree.Fill()
01348         resultsDict = {}
01349         if firstOnly:
01350             resultsDict.setdefault ('_runevent', {})['firstOnly'] = \
01351                                    len (firstOnly)
01352         if secondOnly:
01353             resultsDict.setdefault ('_runevent', {})['secondOnly'] = \
01354                                    len (secondOnly)
01355         resultsDict['eventsCompared'] = len (overlap)
01356         for reTuple in sorted(overlap):
01357             # if we are filling the diff tree, then save the run and
01358             # event information.
01359             if diffOutputName:
01360                 GenObject._key2re (reTuple,
01361                                    GenObject._rootClassDict['runevent'])
01362             if debug: warn ('event1', blankLines = 3)
01363             event1 = GenObject.loadEventFromTree (chain1, ree1 [reTuple])
01364             if debug: warn ('event2', blankLines = 3)
01365             event2 = GenObject.loadEventFromTree (chain2, ree2 [reTuple])
01366             if GenObject._kitchenSinkDict.get('printEvent'):
01367                 print "event1:"
01368                 GenObject.printEvent (event1)
01369                 print "event2:"
01370                 GenObject.printEvent (event2)
01371             if GenObject._kitchenSinkDict.get('blur'):
01372                 where = reTuple
01373                 GenObject.blurEvent (event1,
01374                                      GenObject._kitchenSinkDict['blur'],
01375                                      where)
01376             for objName in sorted (event1.keys()):
01377                 if "runevent" == objName:
01378                     # runevent is a special case.  We don't compare these
01379                     continue
01380                 if not GenObject._equivDict.get (objName):
01381                     # we don't know how to compare these objects, so
01382                     # skip them.
01383                     continue
01384                 if GenObject.isSingleton (objName):
01385                     # I'll add this in later.  For now, just skip it
01386                     print "singleton"
01387                     continue
01388                 # Get ready to calculate root diff object if necessary
01389                 rootObj = 0
01390                 if diffOutputName:
01391                     rootObj = GenObject._rootObjectDict[objName]
01392                     rootObj.clear()
01393                 vec1 = event1[objName]
01394                 vec2 = event2[objName]
01395                 matchedSet, noMatch1Set, noMatch2Set = \
01396                             GenObject.pairEquivalentObjects (vec1, vec2)
01397                 if noMatch1Set or noMatch2Set:
01398                     ## print "No match 1", noMatch1Set
01399                     ## print "No match 2", noMatch2Set
01400                     count1 = len (noMatch1Set)
01401                     count2 = len (noMatch2Set)
01402                     key = (count1, count2)
01403                     countDict = resultsDict.\
01404                                 setdefault (objName, {}).\
01405                                 setdefault ('_missing', {})
01406                     if countDict.has_key (key):
01407                         countDict[key] += 1
01408                     else:
01409                         countDict[key] = 1
01410                     # should be calculating root diff objects
01411                     if diffOutputName:
01412                         # first set
01413                         for index in sorted(list(noMatch1Set)):
01414                             goObj = vec1 [index]
01415                             rootObj.firstOnly.push_back ( GenObject.\
01416                                                           _rootObjectClone \
01417                                                           (goObj) )
01418                         # second set
01419                         for index in sorted(list(noMatch2Set)):
01420                             goObj = vec2 [index]
01421                             rootObj.secondOnly.push_back ( GenObject.\
01422                                                           _rootObjectClone \
01423                                                            (goObj) )
01424                 # o.k.  Now that we have them matched, let's compare
01425                 # the proper items:                
01426                 for pair in sorted(list(matchedSet)):
01427                     if diffOutputName:
01428                         rootDiffObj = GenObject._rootDiffObject \
01429                                       ( vec1[ pair[1 - 1] ],
01430                                         vec2[ pair[2 - 1] ] ) 
01431                         rootObj.diff.push_back ( rootDiffObj )
01432                     problems = GenObject.\
01433                                compareTwoItems (vec1[ pair[1 - 1] ],
01434                                                 vec2[ pair[2 - 1] ])
01435                     if problems.keys():
01436                         # pprint.pprint (problems)
01437                         for varName in problems.keys():
01438                             countDict = resultsDict.\
01439                                         setdefault (objName, {}).\
01440                                         setdefault ('_var', {})
01441                             if countDict.has_key (varName):
01442                                 countDict[varName] += 1
01443                             else:
01444                                 countDict[varName] = 1
01445                 key = 'count_%s' % objName
01446                 if not resultsDict.has_key (key):
01447                     resultsDict[key] = 0
01448                 resultsDict[key] += len (matchedSet)
01449                 # try cleaning up
01450                 del vec1
01451                 del vec2
01452             # end for objName        
01453             if diffOutputName:
01454                 diffTree.Fill()
01455             del event1
01456             del event2
01457         # end for overlap
01458         if diffOutputName:
01459             diffTree.Write()
01460             missingTree.Write()
01461             rootfile.Close()
01462         return resultsDict
01463 
01464 
01465     @staticmethod
01466     def saveTupleAs (chain, rootFile):
01467         """Saves a chain as a GO tree"""
01468         print "saveTupleAs"
01469         rootfile, tree = GenObject.setupOutputTree (rootFile, "goTree")
01470         numEntries = GenObject._kitchenSinkDict[chain]['numEntries']        
01471         for entryIndex in xrange (numEntries):
01472             event = GenObject.loadEventFromTree (chain, entryIndex)            
01473             if GenObject._kitchenSinkDict.get('blur'):
01474                 where = "run %d event %d" % (event['runevent'].run,
01475                                              event['runevent'].event)
01476                 if random.random() < GenObject._kitchenSinkDict.get('blur'):
01477                     # dropping event
01478                     print "Dropping", where
01479                     continue
01480                 GenObject.blurEvent (event,
01481                                      GenObject._kitchenSinkDict['blur'],
01482                                      where)
01483                 # check to see if we should drop the event
01484             if GenObject._kitchenSinkDict.get('printEvent'):
01485                 GenObject.printEvent (event)
01486             GenObject._fillRootObjects (event)
01487             tree.Fill()
01488         tree.Write()
01489         rootfile.Close()
01490 
01491 
01492     @staticmethod
01493     def setGlobalFlag (key, value):
01494         """Sets a global flag in _kitchenSinkDict"""
01495         GenObject._kitchenSinkDict [key] = value
01496 
01497 
01498     @staticmethod
01499     def printTuple (chain):
01500         """Prints out all events to stdout"""
01501         numEntries = GenObject._kitchenSinkDict[chain]['numEntries']
01502         debug = GenObject._kitchenSinkDict.get ('debug', False)
01503         if debug: warn (numEntries)
01504         for entryIndex in xrange (numEntries):
01505             if debug: warn (entryIndex, spaces=3)
01506             event = GenObject.loadEventFromTree (chain, entryIndex)            
01507             GenObject.printEvent (event)
01508             if debug: warn(spaces=3)
01509 
01510     @staticmethod
01511     def _convertStringToParameters (string):
01512         """Convert comma-separated string into a python list of
01513         parameters.  Currently only understands strings, floats,  and
01514         integers."""
01515         retval = []        
01516         words = GenObject._commaRE.split (string)
01517         for word in words:
01518             if not len (word):
01519                 continue
01520             match = GenObject._singleQuoteRE.search (word)
01521             if match:
01522                 retval.append (match.group (1))
01523                 continue
01524             match = GenObject._doubleQuoteRE.search (word)
01525             if match:
01526                 retval.append (match.group (1))
01527                 continue
01528             try:
01529                 val = int (word)
01530                 retval.append (val)
01531                 continue
01532             except:
01533                 pass
01534             try:
01535                 val = float (word)
01536                 retval.append (val)
01537                 continue
01538             except:
01539                 pass
01540             # if we're still here, we've got a problem
01541             raise RuntimeError, "Unknown parameter '%s'." % word
01542         return retval
01543 
01544         
01545     ######################
01546     ## Member Functions ##
01547     ######################
01548 
01549 
01550     def __init__ (self, objName):
01551         """Class initializer"""
01552         if not GenObject._objsDict.has_key (objName):# or \
01553             #not GenObject._equivDict.has_key (objName) :
01554             # not good
01555             print "Error: GenObject does not know about object '%s'." % objName
01556             raise RuntimeError, "Failed to create GenObject object."
01557         self._localObjsDict = GenObject._objsDict [objName]
01558         self._objName = objName;
01559         for key, varDict in self._localObjsDict.iteritems():
01560             # if the key starts with an '_', then it is not a
01561             # variable, so don't treat it as one.
01562             if key.startswith ("_"):
01563                 continue
01564             self.setValue (key, varDict['default'])
01565             
01566 
01567     def setValue (self, name, value):
01568         """Wrapper for __setattr___"""
01569         self.__setattr__ (name, value)
01570 
01571     
01572     def getVariableProperty (self, var, key):
01573         """ Returns property assoicated with 'key' for variable 'var'
01574         of object of the same type as 'self'.  Returns 'None' if 'var'
01575         or 'key' is not defined."""
01576         return GenObject._objsDict.get (self._objName,
01577                                         {}).get (var, {}). get (key, None)
01578 
01579 
01580     def __setattr__ (self, name, value):
01581         """Controls setting of values."""
01582         if name.startswith ("_"):
01583             # The internal version. Set anything you want.
01584             object.__setattr__ (self, name, value)
01585         else:
01586             # user version - Make sure this variable has already been
01587 
01588             # defined for this type:
01589             if not self._localObjsDict.has_key (name):
01590                 # this variable has not been defined
01591                 print "Warning: '%s' for class '%s' not setup. Skipping." % \
01592                       (name, self._objName)
01593                 return
01594             varType = self.getVariableProperty (name, 'varType')
01595             # if this is an int, make sure it stays an int
01596             if GenObject.types.int == varType:
01597                 try:
01598                     # This will work with integers, floats, and string
01599                     # representations of integers.
01600                     value = int (value)
01601                 except:
01602                     # This works with string representations of floats
01603                     value = int( float( value ) )
01604             elif GenObject.types.long == varType:
01605                 try:
01606                     # This will work with integers, floats, and string
01607                     # representations of integers.
01608                     value = long (value)
01609                 except:
01610                     # This works with string representations of floats
01611                     value = long( float( value ) )
01612             elif GenObject.types.float == varType:
01613                 # Make sure it's a float
01614                 value = float (value)
01615             elif GenObject.types.string == varType:
01616                 # make sure it's a string
01617                 value = str (value)
01618             # if we're still here, set it
01619             object.__setattr__ (self, name, value)
01620 
01621 
01622     def __call__ (self, key):
01623         """Makes object callable"""
01624         return object.__getattribute__ (self, key)
01625 
01626 
01627     def __str__ (self):
01628         """String representation"""
01629         retval = ""
01630         for varName, value in sorted (self.__dict__.iteritems()):
01631             if varName.startswith ('_'): continue
01632             form = self.getVariableProperty (varName, "form")
01633             if form:
01634                 format = "%s:%s  " % (varName, form)
01635                 retval = retval + format % value
01636             else:
01637                 retval = retval + "%s:%s  " % (varName, value)
01638         return retval
01639