00001
00002
00003
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
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 = {}
00033 _equivDict = {}
00034 _ntupleDict = {}
00035 _tofillDict = {}
00036 _rootObjectDict = {}
00037
00038 _rootClassDict = {}
00039
00040 _kitchenSinkDict = {}
00041
00042
00043
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
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
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
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
00158 return
00159
00160 GenObject._kitchenSinkDict[key] = True
00161
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
00207
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
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
00256
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
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
00273
00274 mode = modeEnum.define
00275 for word in pieces:
00276 if re.match (r'singleton', word, re.IGNORECASE):
00277
00278 objsDict = GenObject._objsDict.setdefault (objName, {})
00279 objsDict['_singleton'] = True
00280 continue
00281
00282
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
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
00299
00300
00301 if varName.startswith("-"):
00302
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
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
00345
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
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
00368
00369 optionsDict = {}
00370 for word in pieces:
00371
00372
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
00390 for genVar, ntDict in tofillObjDict.iteritems():
00391 partsList = ntDict[0]
00392 for part in partsList:
00393
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
00408
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
00442 obj = GenObject._rootObjectDict[objName] = rootObj()
00443 tree.Branch (objName, classname, obj)
00444 else:
00445
00446
00447
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
00456
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
00466 GenObject._rootObjectCopy (obj,
00467 GenObject._rootObjectDict[objName])
00468 else:
00469
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
00493 isChain = eventTree.__class__.__name__ == 'TChain'
00494 if isChain:
00495
00496 eventTree.GetEntry (eventIndex)
00497 else:
00498
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
00510 continue
00511
00512 if not branchName:
00513
00514 continue
00515 if isChain:
00516 objects = getattr (eventTree, branchName)
00517 else:
00518 objects = rootEvent.getProduct (branchName)
00519
00520 if GenObject.isSingleton (objName):
00521 event[objName] = GenObject.\
00522 _genObjectClone (objName,
00523 tupleName,
00524 objects)
00525 continue
00526
00527 event[objName] = []
00528 for obj in objects:
00529 event[objName].append( GenObject.\
00530 _genObjectClone (objName,
00531 tupleName,
00532 obj) )
00533
00534
00535 return event
00536
00537
00538 @staticmethod
00539 def printEvent (event):
00540 """Prints out event dictionary. Mostly for debugging"""
00541
00542 for objName, obj in sorted (event.iteritems()):
00543
00544
00545 if GenObject.isSingleton (objName):
00546 print "%s: %s" % (objName, obj)
00547
00548 for objName, obj in sorted (event.iteritems()):
00549
00550
00551 if not GenObject.isSingleton (objName):
00552
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
00575 files = files[0:1]
00576 else:
00577
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
00586 if not ntupleDict.get('_useChain'):
00587
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
00617 for key in firstDict.keys():
00618 if secondDict.has_key (key):
00619 overlap.add (key)
00620 else:
00621 firstOnly.add (key)
00622
00623
00624 for key in secondDict.keys():
00625 if not firstDict.has_key (key):
00626 secondOnly.add (key)
00627
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
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
00651
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
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
00678
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
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
00705
00706 matchedSet = set()
00707 noMatch1Set = set()
00708 for index1 in firstDict.keys():
00709 list1 = firstDict[index1]
00710
00711 if not len (list1):
00712
00713 noMatch1Set.add (index1)
00714 continue
00715
00716 best1 = list1[0]
00717 index2 = best1[1]
00718
00719 list2 = secondDict.get (index2, [])
00720 if len(list2) and list2[0][1] == index1:
00721 matchedSet.add( (index1, index2) )
00722
00723 del secondDict[index2]
00724 else:
00725
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
00741 value = abs( item1(varName) - item2(varName) )
00742 if value > prec:
00743
00744 problems[varName] = value
00745 else:
00746
00747 if item1(varName) != item2(varName):
00748
00749 val1, val2 = item1(varName), item2(varName)
00750 if val1 > val2:
00751 val1, val2 = val2, val1
00752 problems[varName] = "%s != %s" % (val1, val2)
00753
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
00762 continue
00763 if GenObject.isSingleton (objName):
00764
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
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
00793 problemDict = {}
00794 if firstOnly:
00795
00796 problemDict.setdefault ('_runevent', {})['firstOnly'] = \
00797 len (firstOnly)
00798 if secondOnly:
00799
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
00818 continue
00819 if not GenObject._equivDict.get (objName):
00820
00821
00822 continue
00823 if GenObject.isSingleton (objName):
00824
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
00832
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
00845
00846 for pair in matchedSet:
00847 problems = GenObject.\
00848 compareTwoItems (vec1[ pair[1 - 1] ],
00849 vec2[ pair[2 - 1] ])
00850 if problems.keys():
00851
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
00862
00863
00864
00865
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
00882 print "Dropping", where
00883 continue
00884 GenObject.blurEvent (event,
00885 GenObject._kitchenSinkDict['blur'],
00886 where)
00887
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
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
00915
00916
00917
00918 def __init__ (self, objName):
00919 """Class initializer"""
00920 if not GenObject._objsDict.has_key (objName):
00921
00922
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
00929
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
00952 object.__setattr__ (self, name, value)
00953 else:
00954
00955
00956
00957 if not self._localObjsDict.has_key (name):
00958
00959 print "Warning: '%s' for class '%s' not setup. Skipping." % \
00960 (name, self._objName)
00961 return
00962 varType = self.getVariableProperty (name, 'varType')
00963
00964 if GenObject.types.int == varType:
00965 try:
00966
00967
00968 value = int (value)
00969 except:
00970
00971 value = int( float( value ) )
00972 elif GenObject.types.float == varType:
00973
00974 value = float (value)
00975 elif GenObject.types.string == varType:
00976
00977 value = str (value)
00978
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