6 from FWCore.Utilities.Enumerate
import Enumerate
7 from DataFormats.FWLite
import Events, Handle
16 from functools
import reduce
20 filenameRE = re.compile (
r'.+/Validation/Tools/')
29 def warn (*args, **kwargs):
30 """print out warning with line number and rest of arguments"""
32 frame = inspect.stack()[1]
36 filename = filenameRE.sub (
'', filename)
38 blankLines = kwargs.get(
'blankLines', 0)
40 print '\n' * blankLines
41 spaces = kwargs.get(
'spaces', 0)
45 print "%s (%s): " % (filename, lineNum),
50 print "%s (%s):" % (filename, lineNum)
54 """Infrastruture to define general objects and their attributes."""
60 types = Enumerate (
"float int long string",
"type")
61 _objFunc = Enumerate (
"obj func",
"of")
62 _cppType = dict ( {types.float :
'double',
65 types.string :
'std::string' } )
66 _basicSet = set( [types.float, types.int, types.float,
68 _defaultValue = dict ( {types.float : 0.,
71 types.string :
'""' } )
82 _runEventListDone =
False
83 uselessReturnCode = 1 << 7
88 _nonSpacesRE = re.compile (
r'\S')
89 _colonRE = re.compile (
r'\s*:\s*')
90 _singleColonRE = re.compile (
r'(.+?):(.+)')
91 _doubleColonRE = re.compile (
r'(.+?):(.+?):(.+)')
92 _doublePercentRE = re.compile (
r'%%')
93 _parenRE = re.compile (
r'(.+)\((.*)\)')
94 _spacesRE = re.compile (
r'\s+')
95 _dotRE = re.compile (
r'\s*\.\s*')
96 _commaRE = re.compile (
r'\s*,\s*')
97 _singleQuoteRE = re.compile (
r'^\'(.+)\'$')
98 _doubleQuoteRE = re.compile (
r'^\"(.+)\"$')
99 _bracketRE = re.compile (
r'\[\s*(.+?)\s*\]')
100 _commentRE = re.compile (
r'#.+$')
101 _aliasRE = re.compile (
r'alias=(\S+)', re.IGNORECASE)
102 _labelRE = re.compile (
r'label=(\S+)', re.IGNORECASE)
103 _typeRE = re.compile (
r'type=(\S+)', re.IGNORECASE)
104 _singletonRE = re.compile (
r'singleton', re.IGNORECASE)
105 _typeRE = re.compile (
r'type=(\S+)', re.IGNORECASE)
106 _defaultRE = re.compile (
r'default=(\S+)', re.IGNORECASE)
107 _shortcutRE = re.compile (
r'shortcut=(\S+)', re.IGNORECASE)
108 _precRE = re.compile (
r'prec=(\S+)', re.IGNORECASE)
109 _formRE = re.compile (
r'form=(\S+)', re.IGNORECASE)
110 _nonAlphaRE = re.compile (
r'\W')
111 _percentAsciiRE = re.compile (
r'%([0-9a-fA-F]{2})')
118 def char2ascii (match):
119 return "%%%02x" % ord (match.group(0))
122 def ascii2char (match):
123 return chr( int( match.group(1), 16 ) )
126 def encodeNonAlphanumerics (line):
127 """Use a web like encoding of characters that are non-alphanumeric"""
128 return GenObject._nonAlphaRE.sub( GenObject.char2ascii, line )
131 def decodeNonAlphanumerics (line):
132 """Decode lines encoded with encodeNonAlphanumerics()"""
133 return GenObject._percentAsciiRE.sub( GenObject.ascii2char, line )
137 def addObjectVariable (obj, var, **optionsDict):
138 """ User passes in in object and variable names."""
139 if 'varType' not in optionsDict:
140 optionsDict[
'varType'] = GenObject.types.float
141 varType = optionsDict[
'varType']
142 if not GenObject.types.isValidValue (varType):
143 print "Type '%s' not valid. Skipping (%s, %s, %s)." % \
144 (varType, obj, var, varType)
146 if 'default' not in optionsDict:
147 optionsDict[
'default'] = GenObject._defaultValue[varType]
148 if obj.startswith (
"_")
or var.startswith (
"_"):
149 print "Skipping (%s, %s, %s) because of leading underscore." % \
152 GenObject._objsDict.setdefault (obj, {}).setdefault (var, optionsDict)
156 def getVariableProperty (obj, var, key):
157 """Returns property assoicated with 'key' for variable 'var'
158 of object 'obj'. Returns 'None' if any of the above are not
160 return GenObject._objsDict.get (obj, {}).get (var, {}). get (key,
None)
164 def setEquivExpression (obj, variable, precision):
165 """Adds an equivalence constraint. Must have at least one to
166 compare GO objects."""
167 if obj.startswith (
"_"):
168 print "Skipping (%s, %s) because of leading underscore." % \
171 GenObject._equivDict.setdefault (obj,[]).append ( (variable,
177 """Meant for debugging, but ok if called by user"""
179 pprint.pprint (GenObject._objsDict, indent=4)
181 pprint.pprint (GenObject._equivDict, indent=4)
183 pprint.pprint (GenObject._ntupleDict, indent=4)
185 pprint.pprint (GenObject._tofillDict, indent=4)
186 print "kitchenSink: "
187 pprint.pprint (GenObject._kitchenSinkDict, indent=4)
188 print "rootClassDict"
189 pprint.pprint (GenObject._rootClassDict, indent=4)
194 """Returns a string of hex value of a checksum of input
196 return hex( reduce(
lambda x, y : x + y, map(ord, str) ) )[2:]
200 def rootClassName (objName):
201 """Returns the name of the equivalent Root object"""
202 return "go_" + objName
206 def rootDiffClassName (objName):
207 """Returns the name of the equivalent Root diff object"""
208 return "goDiff_" + objName
212 def rootDiffContClassName (objName):
213 """Returns the name of the equivalent Root diff container
215 return "goDiffCont_" + objName
219 def _setupClassHeader (className, noColon = False):
220 """Returns a string with the class header for a class
222 retval =
"\nclass %s\n{\n public:\n" % className
223 retval +=
" typedef std::vector< %s > Collection;\n\n" % className
226 retval +=
" %s()" % className
228 retval +=
" %s() :\n" % className
233 def _finishClassHeader (className, datadec):
234 """Returns a stringg with the end of a class definition"""
235 retval =
"\n {}\n" + datadec +
"};\n"
236 retval +=
"#ifdef __MAKECINT__\n#pragma link C++ class " + \
237 "vector< %s >+;\n#endif\n\n" % className
242 def _createCppClass (objName):
243 """Returns a string containing the '.C' file necessary to
244 generate a shared object library with dictionary."""
245 if objName
not in GenObject._objsDict:
247 print "Error: GenObject does not know about object '%s'." % objName
248 raise RuntimeError(
"Failed to create C++ class.")
249 className = GenObject.rootClassName (objName)
250 diffName = GenObject.rootDiffClassName (objName)
251 contName = GenObject.rootDiffContClassName (objName)
252 goClass = GenObject._setupClassHeader (className)
253 diffClass = GenObject._setupClassHeader (diffName)
254 contClass = GenObject._setupClassHeader (contName, noColon =
True)
255 goDataDec = diffDataDec = contDataDec =
"\n // data members\n"
257 for key
in sorted( GenObject._objsDict[objName].
keys() ):
258 if key.startswith (
"_"):
continue
259 varTypeList = GenObject._objsDict[objName][key]
260 cppType = GenObject._cppType[ varTypeList[
'varType'] ]
261 default = varTypeList[
'default']
267 goClass +=
" %s (%s)" % (key, default)
268 goDataDec +=
" %s %s;\n" % (cppType, key)
270 goType = varTypeList[
'varType']
271 if goType
in GenObject._basicSet:
273 diffClass +=
" %s (%s),\n" % (key, default)
274 diffDataDec +=
" %s %s;\n" % (cppType, key)
275 if goType == GenObject.types.string:
277 otherKey =
'other_' + key
278 diffClass +=
" %s (%s)" % (otherKey, default)
279 diffDataDec +=
" %s %s;\n" % (cppType, otherKey)
282 deltaKey =
'delta_' + key
283 diffClass +=
" %s (%s)" % (deltaKey, default)
284 diffDataDec +=
" %s %s;\n" % (cppType, deltaKey)
286 raise RuntimeError(
"Shouldn't be here yet.")
289 if GenObject.isSingleton (objName):
291 contDataDec +=
" %s diff;\n" % diffName
292 contDataDec +=
" void setDiff (const %s &rhs)" % diffName + \
296 contDataDec +=
" void clear() {firstOnly.clear(); secondOnly.clear(); diff.clear(); }\n"
297 contDataDec +=
" %s::Collection firstOnly;\n" % className
298 contDataDec +=
" %s::Collection secondOnly;\n" % className
299 contDataDec +=
" %s::Collection diff;\n" % diffName
302 goClass += GenObject._finishClassHeader (className, goDataDec)
303 diffClass += GenObject._finishClassHeader (diffName, diffDataDec)
304 contClass += GenObject._finishClassHeader (contName, contDataDec)
305 if objName ==
'runevent':
309 return goClass + diffClass + contClass
313 def _loadGoRootLibrary ():
314 """Loads Root shared object library associated with all
315 defined GenObjects. Will create library if necessary."""
316 print "Loading GO Root Library"
317 key =
"_loadedLibrary"
318 if GenObject._kitchenSinkDict.get (key):
322 GenObject._kitchenSinkDict[key] =
True
324 sourceCode =
"#include <string>\n#include <vector>\n" \
325 +
"using namespace std;\n"
326 for objClassName
in sorted( GenObject._objsDict.keys() ):
327 sourceCode += GenObject._createCppClass (objClassName)
328 GenObjectRootLibDir =
"genobjectrootlibs"
329 if not os.path.exists (GenObjectRootLibDir):
330 os.mkdir (GenObjectRootLibDir)
331 key = GenObject.checksum( sourceCode )
332 basename =
"%s_%s" % (
"GenObject", key)
333 SO =
"%s/%s_C" % (GenObjectRootLibDir, basename)
334 linuxSO =
"%s.so" % SO
335 windowsSO =
"%s.dll" % SO
336 if not os.path.exists (linuxSO)
and not os.path.exists (windowsSO):
338 filename =
"%s/%s.C" % (GenObjectRootLibDir, basename)
339 if not os.path.exists (filename):
340 print "creating .C file"
341 target = open (filename,
"w")
342 target.write (sourceCode)
345 print "%s exists" % filename
348 ROOT.gSystem.CompileMacro (filename,
"k")
350 print "loading %s" % SO
351 ROOT.gSystem.Load(SO)
356 def _tofillGenObject():
357 """Makes sure that I know how to read root files I made myself"""
358 genObject =
"GenObject"
359 ntupleDict = GenObject._ntupleDict.setdefault (genObject, {})
360 ntupleDict[
'_useChain'] =
True
361 ntupleDict[
'_tree'] =
"goTree"
362 for objName
in GenObject._objsDict.keys():
363 rootObjName = GenObject.rootClassName (objName)
364 if GenObject.isSingleton (objName):
365 ntupleDict[objName] = objName
367 ntupleDict[objName] = objName +
"s"
368 tofillDict = GenObject._tofillDict.\
369 setdefault (genObject, {}).\
370 setdefault (objName, {})
371 for varName
in GenObject._objsDict [objName].
keys():
374 if varName.startswith (
"_"):
376 tofillDict[varName] = [ [(varName, GenObject._objFunc.obj)],
381 def prepareToLoadGenObject():
382 """Makes all necessary preparations to load root files created
384 GenObject._tofillGenObject()
385 GenObject._loadGoRootLibrary()
389 def parseVariableTofill (fillname):
390 """Returns tofill tuple made from string"""
391 parts = GenObject._dotRE.split (fillname)
394 parenMatch = GenObject._parenRE.search (part)
395 mode = GenObject._objFunc.obj
398 part = parenMatch.group (1)
399 mode = GenObject._objFunc.func
401 GenObject._convertStringToParameters \
402 (parenMatch.group (2))
403 partsList.append( (part, mode, parens) )
407 def _fixLostGreaterThans (handle):
408 offset = handle.count (
'<') - handle.count(
'>')
412 print "Huh? Too few '<' for each '>' in handle '%'" % handle
414 return handle +
' >' * offset
418 def loadConfigFile (configFile):
419 """Loads configuration file"""
423 modeEnum = Enumerate (
"none define tofill ntuple",
"mode")
426 config = open (configFile,
'r')
428 raise RuntimeError(
"Can't open configuration '%s'" % configFile)
429 for lineNum, fullLine
in enumerate (config):
430 fullLine = fullLine.strip()
432 line = GenObject._commentRE.sub (
'', fullLine)
434 if not GenObject._nonSpacesRE.search (line):
440 bracketMatch = GenObject._bracketRE.search (line)
443 section = bracketMatch.group(1)
444 words = GenObject._spacesRE.split( section )
446 raise RuntimeError(
"Don't understand line '%s'(%d)" \
447 % (fullLine, lineNum))
452 colonWords = GenObject._colonRE.split (objName)
453 if len (colonWords) > 3:
454 raise RuntimeError(
"Don't understand line '%s'(%d)" \
455 % (fullLine, lineNum))
456 if len (colonWords) == 1:
460 mode = modeEnum.define
462 if GenObject._singletonRE.match (word):
464 objsDict = GenObject._objsDict.\
465 setdefault (objName, {})
466 objsDict[
'_singleton'] =
True
470 print "I don't understand '%s' in section '%s' : %s" \
471 % (word, section, mode)
472 raise RuntimeError(
"Config file parser error '%s'(%d)" \
473 % (fullLine, lineNum))
474 elif len (colonWords) == 2:
478 mode = modeEnum.ntuple
479 ntupleDict = GenObject._ntupleDict.\
480 setdefault (colonWords[0], {})
481 ntupleDict[
'_tree'] = colonWords[1]
486 mode = modeEnum.tofill
487 objName = colonWords [0]
488 tupleName = colonWords [1]
489 tofillName = colonWords [2]
490 ntupleDict = GenObject._ntupleDict.\
491 setdefault (tupleName, {})
492 ntupleDict[objName] = tofillName
495 labelMatch = GenObject._labelRE.search (word)
497 label = tuple( GenObject._commaRE.\
498 split( labelMatch.group (1) ) )
499 ntupleDict.setdefault (
'_label', {}).\
500 setdefault (tofillName,
504 shortcutMatch = GenObject._shortcutRE.search (word)
508 parseVariableTofill ( shortcutMatch.\
510 ntupleDict.setdefault (
'_shortcut', {}).\
511 setdefault (tofillName,
515 typeMatch = GenObject._typeRE.search (word)
519 _fixLostGreaterThans (typeMatch.group(1))
520 handle = Handle( handleString )
521 ntupleDict.setdefault (
'_handle', {}).\
522 setdefault (tofillName,
526 aliasMatch = GenObject._aliasRE.search (word)
528 ntupleDict.setdefault (
'_alias', {}).\
529 setdefault (tofillName,
538 print "I don't understand '%s' in section '%s' : %s" \
539 % (word, section, mode)
540 raise RuntimeError(
"Config file parser error '%s'(%d)" \
541 % (fullLine, lineNum))
547 if modeEnum.none == mode:
549 print "I don't understand line '%s'." % fullLine
550 raise RuntimeError(
"Config file parser error '%s'(%d)" \
551 % (fullLine, lineNum))
552 colonWords = GenObject._colonRE.split (line, 1)
553 if len (colonWords) < 2:
555 print "I don't understand line '%s'." % fullLine
556 raise RuntimeError(
"Config file parser error '%s'(%d)" \
557 % (fullLine, lineNum))
558 varName = colonWords[0]
559 option = colonWords[1]
561 pieces = GenObject._spacesRE.split (option)
564 if modeEnum.define == mode:
569 if varName.startswith(
"-"):
571 if "-equiv" == varName.lower():
573 halves = part.split (
",")
574 if 2 != len (halves):
575 print "Problem with -equiv '%s' in '%s'" % \
577 raise RuntimeError(
"Config file parser error '%s'(%d)" \
578 % (fullLine, lineNum))
580 halves[1] = float (halves[1])
581 if not halves[1] >= 0:
582 print "Problem with -equiv ",\
585 raise RuntimeError(
"Config file parser error '%s'(%d)" \
586 % (fullLine, lineNum))
587 GenObject.setEquivExpression (section,
594 typeMatch = GenObject._typeRE.search (word)
596 GenObject.types.isValidKey (typeMatch.group(1)):
597 varType = typeMatch.group(1).lower()
598 optionsDict[
'varType'] = GenObject.types (varType)
600 defaultMatch = GenObject._defaultRE.search (word)
602 optionsDict[
'default'] = defaultMatch.group(1)
604 precMatch = GenObject._precRE.search (word)
606 optionsDict[
'prec'] = float (precMatch.group (1))
608 formMatch = GenObject._formRE.search (word)
610 form = GenObject._doublePercentRE.\
611 sub (
'%', formMatch.group (1))
612 optionsDict[
'form'] = form
616 print "I don't understand '%s' in section '%s'." \
618 raise RuntimeError(
"Config file parser error '%s'(%d)" \
619 % (fullLine, lineNum))
620 GenObject.addObjectVariable (objName, varName, \
628 fillname, pieces = pieces[0], pieces[1:]
635 print "I don't understand '%s' in section '%s'." \
637 raise RuntimeError(
"Config file parser error '%s'(%d)" \
638 % (fullLine, lineNum))
639 tofillDict = GenObject._tofillDict.\
640 setdefault (tupleName, {}).\
641 setdefault (objName, {})
642 partsList = GenObject.parseVariableTofill (fillname)
643 tofillDict[varName] = [partsList, optionsDict]
645 for objName
in GenObject._objsDict:
647 if not GenObject.isSingleton (objName):
648 GenObject.addObjectVariable (objName,
'index',
649 varType = GenObject.types.int,
654 def changeVariable (tupleName, objName, varName, fillname):
655 """Updates the definition used to go from a Root object to a
656 GenObject. 'tupleName' and 'objName' must already be defined."""
657 parts = GenObject._dotRE.split (fillname)
660 parenMatch = GenObject._parenRE.search (part)
661 mode = GenObject._objFunc.obj
664 part = parenMatch.group (1)
665 mode = GenObject._objFunc.func
667 GenObject._convertStringToParameters \
668 (parenMatch.group (2))
669 partsList.append( (part, mode, parens) )
670 GenObject._tofillDict[tupleName][objName][varName] = [partsList, {}]
675 def evaluateFunction (obj, partsList, debug=False):
676 """Evaluates function described in partsList on obj"""
677 for part
in partsList:
678 if debug: warn (part, spaces=15)
679 obj = getattr (obj, part[0])
680 if debug: warn (obj, spaces=15)
683 if GenObject._objFunc.func == part[1]:
686 if debug: warn (obj, spaces=18)
691 def _genObjectClone (objName, tupleName, obj, index = -1):
692 """Creates a GenObject copy of Root object"""
693 debug = GenObject._kitchenSinkDict.get (
'debug',
False)
694 if objName ==
'runevent':
696 tofillObjDict = GenObject._tofillDict.get(tupleName, {})\
698 genObj = GenObject (objName)
700 if debug: warn (objName, spaces = 9)
701 for genVar, ntDict
in tofillObjDict.iteritems():
702 if debug: warn (genVar, spaces = 12)
704 partsList = ntDict[0]
706 obj = GenObject.evaluateFunction (origObj, partsList, debug)
707 if debug: warn (obj, spaces=12)
708 setattr (genObj, genVar, obj)
711 setattr (genObj,
'index', index)
716 def _rootObjectCopy (goSource, rootTarget):
717 """Copies information from goSourse into Root Object"""
718 objName = goSource._objName
719 for varName
in GenObject._objsDict [objName].
keys():
722 if varName.startswith (
"_"):
724 setattr( rootTarget, varName, goSource (varName) )
728 def _rootObjectClone (obj):
729 """Creates the approprite type of Root object and copies the
730 information into it from the GO object."""
731 objName = obj._objName
732 classObj = GenObject._rootClassDict.get (objName)
734 goName = GenObject.rootClassName (objName)
735 classObj = GenObject._rootClassDict[ goName ]
737 for varName
in GenObject._objsDict [objName].
keys():
738 setattr( rootObj, varName, obj (varName) )
743 def _rootDiffObject (obj1, obj2, rootObj = 0):
744 """Given to GOs, it will create and fill the corresponding
746 objName = obj1._objName
749 diffName = GenObject.rootDiffClassName( objName )
750 rootObj = GenObject._rootClassDict[diffName]()
751 for varName
in GenObject._objsDict [objName].
keys():
752 if varName.startswith (
"_"):
continue
753 goType = GenObject._objsDict[objName][varName][
'varType']
754 if not goType
in GenObject._basicSet:
757 setattr( rootObj, varName, obj1 (varName) )
758 if goType == GenObject.types.string:
760 otherName =
'other_' + varName
761 if obj1 (varName) != obj2 (varName):
763 setattr( rootObj, otherName, obj2 (varName) )
766 setattr( rootObj, otherName,
'' )
769 deltaName =
'delta_' + varName
770 setattr( rootObj, deltaName,
771 obj2 (varName) - obj1 (varName) )
776 def setupOutputTree (outputFile, treeName, treeDescription = "",
777 otherNtupleName =
""):
778 """Opens the output file, loads all of the necessary shared
779 object libraries, and returns the output file and tree. If
780 'otherNtupleName' is given, it will check and make sure that
781 only objects that are defined in it are written out."""
782 rootfile = ROOT.TFile.Open (outputFile,
"recreate")
783 tree = ROOT.TTree (treeName, treeDescription)
784 GenObject._loadGoRootLibrary()
785 for objName
in sorted (GenObject._objsDict.keys()):
786 classname = GenObject.rootClassName (objName)
788 GenObject._rootClassDict[objName] = \
789 getattr (ROOT, classname)
790 if GenObject.isSingleton (objName):
792 obj = GenObject._rootObjectDict[objName] = rootObj()
793 tree.Branch (objName, classname, obj)
799 GenObject._rootObjectDict[objName] = \
800 ROOT.std.vector( rootObj )()
801 branchName = objName +
"s"
802 vecName =
"vector<%s>" % classname
803 tree.Branch( branchName, vecName, vec)
806 return rootfile, tree
810 def setupDiffOutputTree (outputFile, diffName, missingName,
811 diffDescription =
'', missingDescription =
''):
812 """Opens the diff output file, loads all of the necessary
813 shared object libraries, and returns the output file and tree.b"""
814 rootfile = ROOT.TFile.Open (outputFile,
"recreate")
815 GenObject._loadGoRootLibrary()
817 diffTree = ROOT.TTree (diffName, diffDescription)
818 runEventObject = getattr (ROOT,
'go_runevent')()
819 diffTree.Branch (
'runevent',
'go_runevent', runEventObject)
820 GenObject._rootClassDict[
'runevent'] = runEventObject
821 for objName
in sorted (GenObject._objsDict.keys()):
822 if objName ==
'runevent':
continue
823 classname = GenObject.rootClassName (objName)
824 GenObject._rootClassDict[classname] = getattr (ROOT, classname)
825 contName = GenObject.rootDiffContClassName (objName)
826 diffName = GenObject.rootDiffClassName (objName)
827 rootObj = GenObject._rootClassDict[contName] = \
828 getattr (ROOT, contName)
829 GenObject._rootClassDict[diffName] = getattr (ROOT, diffName)
830 obj = GenObject._rootObjectDict[objName] = rootObj()
831 diffTree.Branch (objName, contName, obj)
833 missingTree = ROOT.TTree (missingName, missingDescription)
834 rootRunEventClass = getattr (ROOT,
'go_runevent')
835 firstOnly = GenObject._rootClassDict[
'firstOnly'] = \
836 ROOT.std.vector( rootRunEventClass ) ()
837 secondOnly = GenObject._rootClassDict[
'secondOnly'] = \
838 ROOT.std.vector( rootRunEventClass ) ()
839 missingTree.Branch (
'firstOnly',
'vector<go_runevent>', firstOnly)
840 missingTree.Branch (
'secondOnly',
'vector<go_runevent>', secondOnly)
841 return rootfile, diffTree, missingTree
845 def _fillRootObjects (event):
846 """Fills root objects from GenObject 'event'"""
847 for objName, obj
in sorted (event.iteritems()):
848 if GenObject.isSingleton (objName):
850 GenObject._rootObjectCopy (obj,
851 GenObject._rootObjectDict[objName])
854 vec = GenObject._rootObjectDict[objName]
857 vec.push_back( GenObject._rootObjectClone (goObj) )
861 def _fillRootDiffs (event1, event2):
862 """Fills root diff containers from two GenObject 'event's"""
867 def isSingleton (objName):
868 """Returns true if object is a singleton"""
869 return GenObject._objsDict[objName].
get(
'_singleton')
873 def loadEventFromTree (eventTree, eventIndex,
874 onlyRunEvent =
False):
875 """Loads event information from Root file (as interfaced by
876 'cmstools.EventTree' or 'ROOT.TChain'). Returns a dictionary
877 'event' containing lists of objects or singleton object. If
878 'onlyRunEvent' is et to True, then only run and event number
879 is read in from the tree."""
880 debug = GenObject._kitchenSinkDict.get (
'debug',
False)
881 tupleName = GenObject._kitchenSinkDict[eventTree][
'tupleName']
884 isChain = eventTree.__class__.__name__ ==
'TChain'
887 eventTree.GetEntry (eventIndex)
890 eventTree.to(eventIndex)
891 tofillDict = GenObject._tofillDict.get (tupleName)
892 ntupleDict = GenObject._ntupleDict.get (tupleName)
894 print "Don't know how to fill from '%s' ntuple." % tupleName
896 eventBranchName = ntupleDict[
'runevent']
897 for objName
in tofillDict:
898 branchName = ntupleDict[objName]
899 if onlyRunEvent
and branchName != eventBranchName:
908 objects = getattr (eventTree, branchName)
911 shortcut = ntupleDict.get(
'_shortcut', {}).
get(branchName)
913 objects = GenObject.evaluateFunction (eventTree, shortcut)
916 handle = ntupleDict.get(
'_handle', {}).
get(branchName)
917 label = ntupleDict.get(
'_label' , {}).
get(branchName)
918 if not handle
or not label:
919 raise RuntimeError(
"Missing handle or label for '%s'"\
921 if not eventTree.getByLabel (label, handle):
922 raise RuntimeError(
"not able to get %s for %s" \
923 % (label, branchName))
924 objects = handle.product()
926 if GenObject.isSingleton (objName):
927 event[objName] = GenObject.\
928 _genObjectClone (objName,
933 if debug: warn (objName, spaces = 3)
935 for index, obj
in enumerate (objects):
936 event[objName].
append( GenObject.\
937 _genObjectClone (objName,
950 def printEvent (event):
951 """Prints out event dictionary. Mostly for debugging"""
953 for objName, obj
in sorted (event.iteritems()):
956 if GenObject.isSingleton (objName):
957 print "%s: %s" % (objName, obj)
959 for objName, obj
in sorted (event.iteritems()):
962 if not GenObject.isSingleton (objName):
964 print "%s:" % objName
971 def setAliases (eventTree, tupleName):
972 """runs SetAlias on all saved aliases"""
973 aliases = GenObject._ntupleDict[tupleName].
get(
'_alias', {})
974 for name, alias
in aliases.iteritems():
975 eventTree.SetAlias (name, alias)
979 def changeAlias (tupleName, name, alias):
980 """Updates an alias for an object for a given tuple"""
981 aliasDict = GenObject._ntupleDict[tupleName][
'_alias']
982 if name
not in aliasDict:
983 raise RuntimeError(
"unknown name '%s' in tuple '%s'" % \
985 aliasDict[name] = alias
989 def changeLabel (tupleName, objectName, label):
990 """Updates an label for an object for a given tuple"""
991 labelDict = GenObject._ntupleDict[tupleName][
'_label']
992 if objectName
not in labelDict:
993 raise RuntimeError(
"unknown name '%s' in tuple '%s'" % \
994 (objectName, tupleName))
995 label = tuple( GenObject._commaRE.split( label ) )
996 labelDict[objectName] = label
1000 def prepareTuple (tupleName, files, numEventsWanted = 0):
1001 """Given the tuple name and list of files, returns either a
1002 TChain or EventTree, and number of entries"""
1003 if "GenObject" == tupleName:
1004 GenObject.prepareToLoadGenObject()
1005 if not isinstance (files, list):
1008 ntupleDict = GenObject._ntupleDict[tupleName]
1009 treeName = ntupleDict[
"_tree"]
1010 if ntupleDict.get(
'_useChain'):
1011 chain = ROOT.TChain (treeName)
1012 for filename
in files:
1013 chain.AddFile (filename)
1014 numEntries = chain.GetEntries()
1017 chain = Events (files, forceEvent=
True)
1018 numEntries = chain.size()
1019 chainDict = GenObject._kitchenSinkDict.setdefault (chain, {})
1020 if numEventsWanted
and numEventsWanted < numEntries:
1021 numEntries = numEventsWanted
1022 chainDict[
'numEntries'] = numEntries
1023 chainDict[
'tupleName' ] = tupleName
1028 def getRunEventEntryDict (chain, tupleName, numEntries):
1029 """Returns a dictionary of run, event tuples to entryIndicies"""
1031 for entryIndex
in xrange (numEntries):
1032 event = GenObject.loadEventFromTree (chain,
1034 onlyRunEvent =
True)
1035 runevent = event[
'runevent']
1036 reeDict[ GenObject._re2key (runevent) ] = entryIndex
1043 def _re2key (runevent):
1044 """Given a GO 'runevent' object, returns a sortable key"""
1047 if not GenObject._runEventListDone:
1048 GenObject._runEventListDone =
True
1049 ignoreSet = set( [
'run',
'event'] )
1050 for varName
in sorted (runevent.__dict__.keys()):
1051 if varName.startswith (
'_')
or varName
in ignoreSet:
1053 form = runevent.getVariableProperty (varName,
"form")
1056 GenObject._runEventList.append ((varName, form))
1057 key =
'run:%d event:%d' % (runevent.run, runevent.event)
1058 for items
in GenObject._runEventList:
1060 form =
' %s:%s' % (varName, items[1])
1061 key += form % runevent.getVariableProperty (varName)
1066 def _key2re (key, runevent=None):
1067 """Given a key, returns a GO 'runevent' object"""
1069 runevent = GenObject (
'runevent')
1070 words = GenObject._spacesRE.split (key)
1072 match = GenObject._singleColonRE.search (word)
1077 runevent.__setattr__ (match.group(1), int( match.group(2) ))
1082 def compareRunEventDicts (firstDict, secondDict):
1083 """Compares the keys of the two dicts and returns three sets:
1084 the overlap, first but not second, and second but not first."""
1089 for key
in firstDict.keys():
1090 if key
in secondDict:
1096 for key
in secondDict.keys():
1097 if key
not in firstDict:
1098 secondOnly.add (key)
1100 return overlap, firstOnly, secondOnly
1104 def pairEquivalentObjects (vec1, vec2):
1105 """Finds the equivalent objects in the two vectors"""
1106 len1, len2 = len (vec1), len (vec2)
1107 debug = GenObject._kitchenSinkDict.get (
'debug',
False)
1108 if not len1
or not len2:
1111 noMatch1Set = set( xrange(len1) )
1113 noMatch1Set = set ()
1115 noMatch2Set = set( xrange(len2) )
1117 noMatch2Set = set ()
1118 if debug: warn (
"Nothing found", sapces=6)
1119 return set(), noMatch1Set, noMatch2Set
1120 objName = vec1[0]._objName
1121 equivList = GenObject._equivDict[objName]
1125 if GenObject._kitchenSinkDict.get (
'strictPairing')
or \
1126 equivList == [(
'index', 0)]:
1128 matchedSet = set (zip ( range( min (len1, len2) ),
1129 range( min (len1, len2) ) ) )
1133 noMatch1Set = set (range(len2, len1 + 1))
1138 noMatch2Set = set (range(len1, len2 + 1))
1141 return matchedSet, noMatch1Set, noMatch2Set
1156 for index1
in xrange (len1):
1159 for index2
in xrange (len2):
1163 for equiv
in equivList:
1164 var, precision = equiv[0], equiv[1]
1169 value = abs (val1 - val2) / precision
1178 objList.append( (total, index2) )
1180 firstDict[index1] = objList
1183 for index2
in xrange (len2):
1186 for index1
in xrange (len1):
1190 for equiv
in equivList:
1191 var, precision = equiv[0], equiv[1]
1196 value = abs (val2 - val1) / precision
1205 objList.append( (total, index1) )
1207 secondDict[index2] = objList
1212 firstDictKeys = sorted (firstDict.keys())
1213 for index1
in firstDictKeys:
1214 list1 = firstDict[index1]
1218 noMatch1Set.add (index1)
1224 list2 = secondDict.get (index2, [])
1225 if len(list2)
and list2[0][1] == index1:
1226 matchedSet.add( (index1, index2) )
1228 del firstDict[index1]
1229 del secondDict[index2]
1232 noMatch1Set.add (index1)
1233 noMatch2Set = set( secondDict.keys() )
1234 return matchedSet, noMatch1Set, noMatch2Set
1238 def compareTwoItems (item1, item2):
1239 """Compares all of the variables making sure they are the same
1240 on the two objects."""
1241 objName = item1._objName
1243 relative = GenObject._kitchenSinkDict.get (
'relative',
False)
1244 for varName
in GenObject._objsDict[objName].
keys():
1245 prec = item1.getVariableProperty (varName,
'prec')
1249 val1 = item1(varName)
1250 val2 = item2(varName)
1251 numerator = 2 * abs (val1 - val2)
1252 denominator =
abs(val1) +
abs(val2)
1257 value = numerator / denominator
1260 problems[varName] = value
1262 value =
abs( item1(varName) - item2(varName) )
1265 problems[varName] = value
1268 if item1(varName) != item2(varName):
1270 val1, val2 = item1(varName), item2(varName)
1272 val1, val2 = val2, val1
1273 problems[varName] =
"%s != %s" % (val1, val2)
1279 def blurEvent (event, value, where = ""):
1280 """For debugging purposes only. Will deliberately change
1281 values of first tree to verify that script is correctly
1282 finding problems."""
1283 for objName
in sorted (event.keys()):
1284 if "runevent" == objName:
1287 if GenObject.isSingleton (objName):
1291 for obj
in event[objName]:
1293 for varName
in GenObject._objsDict[objName].
keys():
1294 if isinstance (obj.__dict__[varName], str):
1297 randNumber = random.random()
1299 if randNumber < GenObject._kitchenSinkDict[
'blurRate']:
1300 print " %s: changing '%s' of '%s:%d'" \
1301 % (where, varName, obj._objName, count)
1304 obj.__dict__[varName] += value
1308 def compareTwoTrees (chain1, chain2, **kwargs):
1309 """Given all of the necessary information, this routine will
1310 go through and compare two trees making sure they are
1311 'identical' within requested precision. If 'diffOutputName'
1312 is passed in, a root file with a diffTree and missingTree will
1314 print "Comparing Two Trees"
1315 diffOutputName = kwargs.get (
'diffOutputName')
1316 tupleName1 = GenObject._kitchenSinkDict[chain1][
'tupleName']
1317 numEntries1 = GenObject._kitchenSinkDict[chain1][
'numEntries']
1318 tupleName2 = GenObject._kitchenSinkDict[chain2][
'tupleName']
1319 numEntries2 = GenObject._kitchenSinkDict[chain2][
'numEntries']
1320 debug = GenObject._kitchenSinkDict.get (
'debug',
False)
1321 ree1 = GenObject.getRunEventEntryDict (chain1, tupleName1, numEntries1)
1322 ree2 = GenObject.getRunEventEntryDict (chain2, tupleName2, numEntries2)
1323 overlap, firstOnly, secondOnly = \
1324 GenObject.compareRunEventDicts (ree1, ree2)
1326 rootfile, diffTree, missingTree = \
1327 GenObject.setupDiffOutputTree (diffOutputName,
1331 vec = GenObject._rootClassDict[
'firstOnly']
1332 for key
in firstOnly:
1333 runevent = GenObject._key2re (key)
1334 vec.push_back( GenObject._rootObjectClone( runevent ) )
1336 vec = GenObject._rootClassDict[
'secondOnly']
1337 for key
in secondOnly:
1338 runevent = GenObject._key2re (key)
1339 vec.push_back( GenObject._rootObjectClone( runevent ) )
1343 resultsDict.setdefault (
'_runevent', {})[
'firstOnly'] = \
1346 resultsDict.setdefault (
'_runevent', {})[
'secondOnly'] = \
1348 resultsDict[
'eventsCompared'] = len (overlap)
1349 for reTuple
in sorted(overlap):
1353 GenObject._key2re (reTuple,
1354 GenObject._rootClassDict[
'runevent'])
1355 if debug: warn (
'event1', blankLines = 3)
1356 event1 = GenObject.loadEventFromTree (chain1, ree1 [reTuple])
1357 if debug: warn (
'event2', blankLines = 3)
1358 event2 = GenObject.loadEventFromTree (chain2, ree2 [reTuple])
1359 if GenObject._kitchenSinkDict.get(
'printEvent'):
1361 GenObject.printEvent (event1)
1363 GenObject.printEvent (event2)
1364 if GenObject._kitchenSinkDict.get(
'blur'):
1366 GenObject.blurEvent (event1,
1367 GenObject._kitchenSinkDict[
'blur'],
1369 for objName
in sorted (event1.keys()):
1370 if "runevent" == objName:
1373 if not GenObject._equivDict.get (objName):
1377 if GenObject.isSingleton (objName):
1384 rootObj = GenObject._rootObjectDict[objName]
1386 vec1 = event1[objName]
1387 vec2 = event2[objName]
1388 matchedSet, noMatch1Set, noMatch2Set = \
1389 GenObject.pairEquivalentObjects (vec1, vec2)
1390 if noMatch1Set
or noMatch2Set:
1393 count1 = len (noMatch1Set)
1394 count2 = len (noMatch2Set)
1395 key = (count1, count2)
1396 countDict = resultsDict.\
1397 setdefault (objName, {}).\
1398 setdefault (
'_missing', {})
1399 if key
in countDict:
1406 for index
in sorted(
list(noMatch1Set)):
1407 goObj = vec1 [index]
1408 rootObj.firstOnly.push_back ( GenObject.\
1412 for index
in sorted(
list(noMatch2Set)):
1413 goObj = vec2 [index]
1414 rootObj.secondOnly.push_back ( GenObject.\
1419 for pair
in sorted(
list(matchedSet)):
1421 rootDiffObj = GenObject._rootDiffObject \
1422 ( vec1[ pair[1 - 1] ],
1423 vec2[ pair[2 - 1] ] )
1424 rootObj.diff.push_back ( rootDiffObj )
1425 problems = GenObject.\
1426 compareTwoItems (vec1[ pair[1 - 1] ],
1427 vec2[ pair[2 - 1] ])
1430 for varName
in problems.keys():
1431 countDict = resultsDict.\
1432 setdefault (objName, {}).\
1433 setdefault (
'_var', {})
1434 if varName
in countDict:
1435 countDict[varName] += 1
1437 countDict[varName] = 1
1438 key =
'count_%s' % objName
1439 if key
not in resultsDict:
1440 resultsDict[key] = 0
1441 resultsDict[key] += len (matchedSet)
1459 def saveTupleAs (chain, rootFile):
1460 """Saves a chain as a GO tree"""
1462 rootfile, tree = GenObject.setupOutputTree (rootFile,
"goTree")
1463 numEntries = GenObject._kitchenSinkDict[chain][
'numEntries']
1464 for entryIndex
in xrange (numEntries):
1465 event = GenObject.loadEventFromTree (chain, entryIndex)
1466 if GenObject._kitchenSinkDict.get(
'blur'):
1467 where =
"run %d event %d" % (event[
'runevent'].run,
1468 event[
'runevent'].event)
1469 if random.random() < GenObject._kitchenSinkDict.get(
'blur'):
1471 print "Dropping", where
1473 GenObject.blurEvent (event,
1474 GenObject._kitchenSinkDict[
'blur'],
1477 if GenObject._kitchenSinkDict.get(
'printEvent'):
1478 GenObject.printEvent (event)
1479 GenObject._fillRootObjects (event)
1486 def setGlobalFlag (key, value):
1487 """Sets a global flag in _kitchenSinkDict"""
1488 GenObject._kitchenSinkDict [key] = value
1492 def printTuple (chain):
1493 """Prints out all events to stdout"""
1494 numEntries = GenObject._kitchenSinkDict[chain][
'numEntries']
1495 debug = GenObject._kitchenSinkDict.get (
'debug',
False)
1496 if debug: warn (numEntries)
1497 for entryIndex
in xrange (numEntries):
1498 if debug: warn (entryIndex, spaces=3)
1499 event = GenObject.loadEventFromTree (chain, entryIndex)
1500 GenObject.printEvent (event)
1501 if debug:
warn(spaces=3)
1504 def _convertStringToParameters (string):
1505 """Convert comma-separated string into a python list of
1506 parameters. Currently only understands strings, floats, and
1509 words = GenObject._commaRE.split (string)
1513 match = GenObject._singleQuoteRE.search (word)
1515 retval.append (match.group (1))
1517 match = GenObject._doubleQuoteRE.search (word)
1519 retval.append (match.group (1))
1534 raise RuntimeError(
"Unknown parameter '%s'." % word)
1543 def __init__ (self, objName):
1544 """Class initializer"""
1545 if objName
not in GenObject._objsDict:
1548 print "Error: GenObject does not know about object '%s'." % objName
1549 raise RuntimeError(
"Failed to create GenObject object.")
1550 self._localObjsDict = GenObject._objsDict [objName]
1551 self._objName = objName;
1552 for key, varDict
in self._localObjsDict.iteritems():
1555 if key.startswith (
"_"):
1557 self.setValue (key, varDict[
'default'])
1561 """Wrapper for __setattr___"""
1562 self.__setattr__ (name, value)
1565 def getVariableProperty (self, var, key):
1566 """ Returns property assoicated with 'key' for variable 'var'
1567 of object of the same type as 'self'. Returns 'None' if 'var'
1568 or 'key' is not defined."""
1569 return GenObject._objsDict.get (self._objName,
1570 {}).get (var, {}). get (key,
None)
1573 def __setattr__ (self, name, value):
1574 """Controls setting of values."""
1575 if name.startswith (
"_"):
1577 object.__setattr__ (self, name, value)
1582 if name
not in self._localObjsDict:
1584 print "Warning: '%s' for class '%s' not setup. Skipping." % \
1585 (name, self._objName)
1587 varType = self.getVariableProperty (name,
'varType')
1589 if GenObject.types.int == varType:
1596 value = int( float( value ) )
1597 elif GenObject.types.long == varType:
1601 value = long (value)
1604 value = long( float( value ) )
1605 elif GenObject.types.float == varType:
1607 value = float (value)
1608 elif GenObject.types.string == varType:
1612 object.__setattr__ (self, name, value)
1616 """Makes object callable"""
1617 return object.__getattribute__ (self, key)
1621 """String representation"""
1623 for varName, value
in sorted (self.__dict__.iteritems()):
1624 if varName.startswith (
'_'):
continue
1625 form = self.getVariableProperty (varName,
"form")
1627 format =
"%s:%s " % (varName, form)
1628 retval = retval + format % value
1630 retval = retval +
"%s:%s " % (varName, value)
boost::dynamic_bitset append(const boost::dynamic_bitset<> &bs1, const boost::dynamic_bitset<> &bs2)
this method takes two bitsets bs1 and bs2 and returns result of bs2 appended to the end of bs1 ...
bool setValue(Container &, const reco::JetBaseRef &, const JetExtendedData &)
associate jet with value. Returns false and associate nothing if jet is already associated ...
Abs< T >::type abs(const T &t)
T get(const Candidate &c)
How EventSelector::AcceptEvent() decides whether to accept an event for output otherwise it is excluding the probing of A single or multiple positive and the trigger will pass if any such matching triggers are PASS or EXCEPTION[A criterion thatmatches no triggers at all is detected and causes a throw.] A single negative with an expectation of appropriate bit checking in the decision and the trigger will pass if any such matching triggers are FAIL or EXCEPTION A wildcarded negative criterion that matches more than one trigger in the trigger list("!*","!HLTx*"if it matches 2 triggers or more) will accept the event if all the matching triggers are FAIL.It will reject the event if any of the triggers are PASS or EXCEPTION(this matches the behavior of"!*"before the partial wildcard feature was incorporated).Triggers which are in the READY state are completely ignored.(READY should never be returned since the trigger paths have been run