1 from __future__
import print_function
7 from builtins
import range
8 from FWCore.Utilities.Enumerate
import Enumerate
9 from DataFormats.FWLite
import Events, Handle
18 from functools
import reduce
22 filenameRE = re.compile (
r'.+/Validation/Tools/')
31 def warn (*args, **kwargs):
32 """print out warning with line number and rest of arguments"""
34 frame = inspect.stack()[1]
38 filename = filenameRE.sub (
'', filename)
40 blankLines = kwargs.get(
'blankLines', 0)
42 print(
'\n' * blankLines)
43 spaces = kwargs.get(
'spaces', 0)
45 print(
' ' * spaces, end=
' ')
47 print(
"%s (%s): " % (filename, lineNum), end=
' ')
52 print(
"%s (%s):" % (filename, lineNum))
56 """Infrastruture to define general objects and their attributes."""
62 types = Enumerate (
"float int long string",
"type")
63 _objFunc = Enumerate (
"obj func",
"of")
64 _cppType = dict ( {types.float :
'double',
67 types.string :
'std::string' } )
68 _basicSet = set( [types.float, types.int, types.float,
70 _defaultValue = dict ( {types.float : 0.,
73 types.string :
'""' } )
84 _runEventListDone =
False
85 uselessReturnCode = 1 << 7
90 _nonSpacesRE = re.compile (
r'\S')
91 _colonRE = re.compile (
r'\s*:\s*')
92 _singleColonRE = re.compile (
r'(.+?):(.+)')
93 _doubleColonRE = re.compile (
r'(.+?):(.+?):(.+)')
94 _doublePercentRE = re.compile (
r'%%')
95 _parenRE = re.compile (
r'(.+)\((.*)\)')
96 _spacesRE = re.compile (
r'\s+')
97 _dotRE = re.compile (
r'\s*\.\s*')
98 _commaRE = re.compile (
r'\s*,\s*')
99 _singleQuoteRE = re.compile (
r'^\'(.+)\'$')
100 _doubleQuoteRE = re.compile (
r'^\"(.+)\"$')
101 _bracketRE = re.compile (
r'\[\s*(.+?)\s*\]')
102 _commentRE = re.compile (
r'#.+$')
103 _aliasRE = re.compile (
r'alias=(\S+)', re.IGNORECASE)
104 _labelRE = re.compile (
r'label=(\S+)', re.IGNORECASE)
105 _typeRE = re.compile (
r'type=(\S+)', re.IGNORECASE)
106 _singletonRE = re.compile (
r'singleton', re.IGNORECASE)
107 _typeRE = re.compile (
r'type=(\S+)', re.IGNORECASE)
108 _defaultRE = re.compile (
r'default=(\S+)', re.IGNORECASE)
109 _shortcutRE = re.compile (
r'shortcut=(\S+)', re.IGNORECASE)
110 _precRE = re.compile (
r'prec=(\S+)', re.IGNORECASE)
111 _formRE = re.compile (
r'form=(\S+)', re.IGNORECASE)
112 _nonAlphaRE = re.compile (
r'\W')
113 _percentAsciiRE = re.compile (
r'%([0-9a-fA-F]{2})')
120 def char2ascii (match):
121 return "%%%02x" % ord (match.group(0))
124 def ascii2char (match):
125 return chr( int( match.group(1), 16 ) )
128 def encodeNonAlphanumerics (line):
129 """Use a web like encoding of characters that are non-alphanumeric"""
130 return GenObject._nonAlphaRE.sub( GenObject.char2ascii, line )
133 def decodeNonAlphanumerics (line):
134 """Decode lines encoded with encodeNonAlphanumerics()"""
135 return GenObject._percentAsciiRE.sub( GenObject.ascii2char, line )
139 def addObjectVariable (obj, var, **optionsDict):
140 """ User passes in in object and variable names."""
141 if 'varType' not in optionsDict:
142 optionsDict[
'varType'] = GenObject.types.float
143 varType = optionsDict[
'varType']
144 if not GenObject.types.isValidValue (varType):
145 print(
"Type '%s' not valid. Skipping (%s, %s, %s)." % \
146 (varType, obj, var, varType))
148 if 'default' not in optionsDict:
149 optionsDict[
'default'] = GenObject._defaultValue[varType]
150 if obj.startswith (
"_")
or var.startswith (
"_"):
151 print(
"Skipping (%s, %s, %s) because of leading underscore." % \
154 GenObject._objsDict.setdefault (obj, {}).setdefault (var, optionsDict)
158 def getVariableProperty (obj, var, key):
159 """Returns property assoicated with 'key' for variable 'var'
160 of object 'obj'. Returns 'None' if any of the above are not
162 return GenObject._objsDict.get (obj, {}).get (var, {}). get (key,
None)
166 def setEquivExpression (obj, variable, precision):
167 """Adds an equivalence constraint. Must have at least one to
168 compare GO objects."""
169 if obj.startswith (
"_"):
170 print(
"Skipping (%s, %s) because of leading underscore." % \
173 GenObject._equivDict.setdefault (obj,[]).append ( (variable,
179 """Meant for debugging, but ok if called by user"""
181 pprint.pprint (GenObject._objsDict, indent=4)
183 pprint.pprint (GenObject._equivDict, indent=4)
185 pprint.pprint (GenObject._ntupleDict, indent=4)
187 pprint.pprint (GenObject._tofillDict, indent=4)
188 print(
"kitchenSink: ")
189 pprint.pprint (GenObject._kitchenSinkDict, indent=4)
190 print(
"rootClassDict")
191 pprint.pprint (GenObject._rootClassDict, indent=4)
196 """Returns a string of hex value of a checksum of input
198 return hex( reduce(
lambda x, y : x + y, map(ord, str) ) )[2:]
202 def rootClassName (objName):
203 """Returns the name of the equivalent Root object"""
204 return "go_" + objName
208 def rootDiffClassName (objName):
209 """Returns the name of the equivalent Root diff object"""
210 return "goDiff_" + objName
214 def rootDiffContClassName (objName):
215 """Returns the name of the equivalent Root diff container
217 return "goDiffCont_" + objName
221 def _setupClassHeader (className, noColon = False):
222 """Returns a string with the class header for a class
224 retval =
"\nclass %s\n{\n public:\n" % className
225 retval +=
" typedef std::vector< %s > Collection;\n\n" % className
228 retval +=
" %s()" % className
230 retval +=
" %s() :\n" % className
235 def _finishClassHeader (className, datadec):
236 """Returns a stringg with the end of a class definition"""
237 retval =
"\n {}\n" + datadec +
"};\n"
238 retval +=
"#ifdef __MAKECINT__\n#pragma link C++ class " + \
239 "vector< %s >+;\n#endif\n\n" % className
244 def _createCppClass (objName):
245 """Returns a string containing the '.C' file necessary to
246 generate a shared object library with dictionary."""
247 if objName
not in GenObject._objsDict:
249 print(
"Error: GenObject does not know about object '%s'." % objName)
250 raise RuntimeError(
"Failed to create C++ class.")
251 className = GenObject.rootClassName (objName)
252 diffName = GenObject.rootDiffClassName (objName)
253 contName = GenObject.rootDiffContClassName (objName)
254 goClass = GenObject._setupClassHeader (className)
255 diffClass = GenObject._setupClassHeader (diffName)
256 contClass = GenObject._setupClassHeader (contName, noColon =
True)
257 goDataDec = diffDataDec = contDataDec =
"\n // data members\n"
259 for key
in sorted( GenObject._objsDict[objName].
keys() ):
260 if key.startswith (
"_"):
continue
261 varTypeList = GenObject._objsDict[objName][key]
262 cppType = GenObject._cppType[ varTypeList[
'varType'] ]
263 default = varTypeList[
'default']
269 goClass +=
" %s (%s)" % (key, default)
270 goDataDec +=
" %s %s;\n" % (cppType, key)
272 goType = varTypeList[
'varType']
273 if goType
in GenObject._basicSet:
275 diffClass +=
" %s (%s),\n" % (key, default)
276 diffDataDec +=
" %s %s;\n" % (cppType, key)
277 if goType == GenObject.types.string:
279 otherKey =
'other_' + key
280 diffClass +=
" %s (%s)" % (otherKey, default)
281 diffDataDec +=
" %s %s;\n" % (cppType, otherKey)
284 deltaKey =
'delta_' + key
285 diffClass +=
" %s (%s)" % (deltaKey, default)
286 diffDataDec +=
" %s %s;\n" % (cppType, deltaKey)
288 raise RuntimeError(
"Shouldn't be here yet.")
291 if GenObject.isSingleton (objName):
293 contDataDec +=
" %s diff;\n" % diffName
294 contDataDec +=
" void setDiff (const %s &rhs)" % diffName + \
298 contDataDec +=
" void clear() {firstOnly.clear(); secondOnly.clear(); diff.clear(); }\n"
299 contDataDec +=
" %s::Collection firstOnly;\n" % className
300 contDataDec +=
" %s::Collection secondOnly;\n" % className
301 contDataDec +=
" %s::Collection diff;\n" % diffName
304 goClass += GenObject._finishClassHeader (className, goDataDec)
305 diffClass += GenObject._finishClassHeader (diffName, diffDataDec)
306 contClass += GenObject._finishClassHeader (contName, contDataDec)
307 if objName ==
'runevent':
311 return goClass + diffClass + contClass
315 def _loadGoRootLibrary ():
316 """Loads Root shared object library associated with all
317 defined GenObjects. Will create library if necessary."""
318 print(
"Loading GO Root Library")
319 key =
"_loadedLibrary"
320 if GenObject._kitchenSinkDict.get (key):
324 GenObject._kitchenSinkDict[key] =
True
326 sourceCode =
"#include <string>\n#include <vector>\n" \
327 +
"using namespace std;\n"
328 for objClassName
in sorted( GenObject._objsDict.keys() ):
329 sourceCode += GenObject._createCppClass (objClassName)
330 GenObjectRootLibDir =
"genobjectrootlibs"
331 if not os.path.exists (GenObjectRootLibDir):
332 os.mkdir (GenObjectRootLibDir)
333 key = GenObject.checksum( sourceCode )
334 basename =
"%s_%s" % (
"GenObject", key)
335 SO =
"%s/%s_C" % (GenObjectRootLibDir, basename)
336 linuxSO =
"%s.so" % SO
337 windowsSO =
"%s.dll" % SO
338 if not os.path.exists (linuxSO)
and not os.path.exists (windowsSO):
340 filename =
"%s/%s.C" % (GenObjectRootLibDir, basename)
341 if not os.path.exists (filename):
342 print(
"creating .C file")
343 target = open (filename,
"w")
344 target.write (sourceCode)
347 print(
"%s exists" % filename)
350 ROOT.gSystem.CompileMacro (filename,
"k")
352 print(
"loading %s" % SO)
353 ROOT.gSystem.Load(SO)
358 def _tofillGenObject():
359 """Makes sure that I know how to read root files I made myself"""
360 genObject =
"GenObject"
361 ntupleDict = GenObject._ntupleDict.setdefault (genObject, {})
362 ntupleDict[
'_useChain'] =
True
363 ntupleDict[
'_tree'] =
"goTree"
364 for objName
in GenObject._objsDict.keys():
365 rootObjName = GenObject.rootClassName (objName)
366 if GenObject.isSingleton (objName):
367 ntupleDict[objName] = objName
369 ntupleDict[objName] = objName +
"s"
370 tofillDict = GenObject._tofillDict.\
371 setdefault (genObject, {}).\
372 setdefault (objName, {})
373 for varName
in GenObject._objsDict [objName].
keys():
376 if varName.startswith (
"_"):
378 tofillDict[varName] = [ [(varName, GenObject._objFunc.obj)],
383 def prepareToLoadGenObject():
384 """Makes all necessary preparations to load root files created
386 GenObject._tofillGenObject()
387 GenObject._loadGoRootLibrary()
391 def parseVariableTofill (fillname):
392 """Returns tofill tuple made from string"""
393 parts = GenObject._dotRE.split (fillname)
396 parenMatch = GenObject._parenRE.search (part)
397 mode = GenObject._objFunc.obj
400 part = parenMatch.group (1)
401 mode = GenObject._objFunc.func
403 GenObject._convertStringToParameters \
404 (parenMatch.group (2))
405 partsList.append( (part, mode, parens) )
409 def _fixLostGreaterThans (handle):
410 offset = handle.count (
'<') - handle.count(
'>')
414 print(
"Huh? Too few '<' for each '>' in handle '%'" % handle)
416 return handle +
' >' * offset
420 def loadConfigFile (configFile):
421 """Loads configuration file"""
425 modeEnum = Enumerate (
"none define tofill ntuple",
"mode")
428 config = open (configFile,
'r')
430 raise RuntimeError(
"Can't open configuration '%s'" % configFile)
431 for lineNum, fullLine
in enumerate (config):
432 fullLine = fullLine.strip()
434 line = GenObject._commentRE.sub (
'', fullLine)
436 if not GenObject._nonSpacesRE.search (line):
442 bracketMatch = GenObject._bracketRE.search (line)
445 section = bracketMatch.group(1)
446 words = GenObject._spacesRE.split( section )
448 raise RuntimeError(
"Don't understand line '%s'(%d)" \
449 % (fullLine, lineNum))
454 colonWords = GenObject._colonRE.split (objName)
455 if len (colonWords) > 3:
456 raise RuntimeError(
"Don't understand line '%s'(%d)" \
457 % (fullLine, lineNum))
458 if len (colonWords) == 1:
462 mode = modeEnum.define
464 if GenObject._singletonRE.match (word):
466 objsDict = GenObject._objsDict.\
467 setdefault (objName, {})
468 objsDict[
'_singleton'] =
True
472 print(
"I don't understand '%s' in section '%s' : %s" \
473 % (word, section, mode))
474 raise RuntimeError(
"Config file parser error '%s'(%d)" \
475 % (fullLine, lineNum))
476 elif len (colonWords) == 2:
480 mode = modeEnum.ntuple
481 ntupleDict = GenObject._ntupleDict.\
482 setdefault (colonWords[0], {})
483 ntupleDict[
'_tree'] = colonWords[1]
488 mode = modeEnum.tofill
489 objName = colonWords [0]
490 tupleName = colonWords [1]
491 tofillName = colonWords [2]
492 ntupleDict = GenObject._ntupleDict.\
493 setdefault (tupleName, {})
494 ntupleDict[objName] = tofillName
497 labelMatch = GenObject._labelRE.search (word)
499 label = tuple( GenObject._commaRE.\
500 split( labelMatch.group (1) ) )
501 ntupleDict.setdefault (
'_label', {}).\
502 setdefault (tofillName,
506 shortcutMatch = GenObject._shortcutRE.search (word)
510 parseVariableTofill ( shortcutMatch.\
512 ntupleDict.setdefault (
'_shortcut', {}).\
513 setdefault (tofillName,
517 typeMatch = GenObject._typeRE.search (word)
521 _fixLostGreaterThans (typeMatch.group(1))
522 handle = Handle( handleString )
523 ntupleDict.setdefault (
'_handle', {}).\
524 setdefault (tofillName,
528 aliasMatch = GenObject._aliasRE.search (word)
530 ntupleDict.setdefault (
'_alias', {}).\
531 setdefault (tofillName,
540 print(
"I don't understand '%s' in section '%s' : %s" \
541 % (word, section, mode))
542 raise RuntimeError(
"Config file parser error '%s'(%d)" \
543 % (fullLine, lineNum))
549 if modeEnum.none == mode:
551 print(
"I don't understand line '%s'." % fullLine)
552 raise RuntimeError(
"Config file parser error '%s'(%d)" \
553 % (fullLine, lineNum))
554 colonWords = GenObject._colonRE.split (line, 1)
555 if len (colonWords) < 2:
557 print(
"I don't understand line '%s'." % fullLine)
558 raise RuntimeError(
"Config file parser error '%s'(%d)" \
559 % (fullLine, lineNum))
560 varName = colonWords[0]
561 option = colonWords[1]
563 pieces = GenObject._spacesRE.split (option)
566 if modeEnum.define == mode:
571 if varName.startswith(
"-"):
573 if "-equiv" == varName.lower():
575 halves = part.split (
",")
576 if 2 != len (halves):
577 print(
"Problem with -equiv '%s' in '%s'" % \
579 raise RuntimeError(
"Config file parser error '%s'(%d)" \
580 % (fullLine, lineNum))
582 halves[1] = float (halves[1])
583 if not halves[1] >= 0:
584 print(
"Problem with -equiv ",\
587 raise RuntimeError(
"Config file parser error '%s'(%d)" \
588 % (fullLine, lineNum))
589 GenObject.setEquivExpression (section,
596 typeMatch = GenObject._typeRE.search (word)
598 GenObject.types.isValidKey (typeMatch.group(1)):
599 varType = typeMatch.group(1).lower()
600 optionsDict[
'varType'] = GenObject.types (varType)
602 defaultMatch = GenObject._defaultRE.search (word)
604 optionsDict[
'default'] = defaultMatch.group(1)
606 precMatch = GenObject._precRE.search (word)
608 optionsDict[
'prec'] = float (precMatch.group (1))
610 formMatch = GenObject._formRE.search (word)
612 form = GenObject._doublePercentRE.\
613 sub (
'%', formMatch.group (1))
614 optionsDict[
'form'] = form
618 print(
"I don't understand '%s' in section '%s'." \
620 raise RuntimeError(
"Config file parser error '%s'(%d)" \
621 % (fullLine, lineNum))
622 GenObject.addObjectVariable (objName, varName, \
630 fillname, pieces = pieces[0], pieces[1:]
637 print(
"I don't understand '%s' in section '%s'." \
639 raise RuntimeError(
"Config file parser error '%s'(%d)" \
640 % (fullLine, lineNum))
641 tofillDict = GenObject._tofillDict.\
642 setdefault (tupleName, {}).\
643 setdefault (objName, {})
644 partsList = GenObject.parseVariableTofill (fillname)
645 tofillDict[varName] = [partsList, optionsDict]
647 for objName
in GenObject._objsDict:
649 if not GenObject.isSingleton (objName):
650 GenObject.addObjectVariable (objName,
'index',
651 varType = GenObject.types.int,
656 def changeVariable (tupleName, objName, varName, fillname):
657 """Updates the definition used to go from a Root object to a
658 GenObject. 'tupleName' and 'objName' must already be defined."""
659 parts = GenObject._dotRE.split (fillname)
662 parenMatch = GenObject._parenRE.search (part)
663 mode = GenObject._objFunc.obj
666 part = parenMatch.group (1)
667 mode = GenObject._objFunc.func
669 GenObject._convertStringToParameters \
670 (parenMatch.group (2))
671 partsList.append( (part, mode, parens) )
672 GenObject._tofillDict[tupleName][objName][varName] = [partsList, {}]
677 def evaluateFunction (obj, partsList, debug=False):
678 """Evaluates function described in partsList on obj"""
679 for part
in partsList:
680 if debug: warn (part, spaces=15)
681 obj = getattr (obj, part[0])
682 if debug: warn (obj, spaces=15)
685 if GenObject._objFunc.func == part[1]:
688 if debug: warn (obj, spaces=18)
693 def _genObjectClone (objName, tupleName, obj, index = -1):
694 """Creates a GenObject copy of Root object"""
695 debug = GenObject._kitchenSinkDict.get (
'debug',
False)
696 if objName ==
'runevent':
698 tofillObjDict = GenObject._tofillDict.get(tupleName, {})\
700 genObj = GenObject (objName)
702 if debug: warn (objName, spaces = 9)
703 for genVar, ntDict
in tofillObjDict.items():
704 if debug: warn (genVar, spaces = 12)
706 partsList = ntDict[0]
708 obj = GenObject.evaluateFunction (origObj, partsList, debug)
709 if debug: warn (obj, spaces=12)
710 setattr (genObj, genVar, obj)
713 setattr (genObj,
'index', index)
718 def _rootObjectCopy (goSource, rootTarget):
719 """Copies information from goSourse into Root Object"""
720 objName = goSource._objName
721 for varName
in GenObject._objsDict [objName].
keys():
724 if varName.startswith (
"_"):
726 setattr( rootTarget, varName, goSource (varName) )
730 def _rootObjectClone (obj):
731 """Creates the approprite type of Root object and copies the
732 information into it from the GO object."""
733 objName = obj._objName
734 classObj = GenObject._rootClassDict.get (objName)
736 goName = GenObject.rootClassName (objName)
737 classObj = GenObject._rootClassDict[ goName ]
739 for varName
in GenObject._objsDict [objName].
keys():
740 setattr( rootObj, varName, obj (varName) )
745 def _rootDiffObject (obj1, obj2, rootObj = 0):
746 """Given to GOs, it will create and fill the corresponding
748 objName = obj1._objName
751 diffName = GenObject.rootDiffClassName( objName )
752 rootObj = GenObject._rootClassDict[diffName]()
753 for varName
in GenObject._objsDict [objName].
keys():
754 if varName.startswith (
"_"):
continue
755 goType = GenObject._objsDict[objName][varName][
'varType']
756 if not goType
in GenObject._basicSet:
759 setattr( rootObj, varName, obj1 (varName) )
760 if goType == GenObject.types.string:
762 otherName =
'other_' + varName
763 if obj1 (varName) != obj2 (varName):
765 setattr( rootObj, otherName, obj2 (varName) )
768 setattr( rootObj, otherName,
'' )
771 deltaName =
'delta_' + varName
772 setattr( rootObj, deltaName,
773 obj2 (varName) - obj1 (varName) )
778 def setupOutputTree (outputFile, treeName, treeDescription = "",
779 otherNtupleName =
""):
780 """Opens the output file, loads all of the necessary shared
781 object libraries, and returns the output file and tree. If
782 'otherNtupleName' is given, it will check and make sure that
783 only objects that are defined in it are written out."""
784 rootfile = ROOT.TFile.Open (outputFile,
"recreate")
785 tree = ROOT.TTree (treeName, treeDescription)
786 GenObject._loadGoRootLibrary()
787 for objName
in sorted (GenObject._objsDict.keys()):
788 classname = GenObject.rootClassName (objName)
790 GenObject._rootClassDict[objName] = \
791 getattr (ROOT, classname)
792 if GenObject.isSingleton (objName):
794 obj = GenObject._rootObjectDict[objName] = rootObj()
795 tree.Branch (objName, classname, obj)
801 GenObject._rootObjectDict[objName] = \
802 ROOT.std.vector( rootObj )()
803 branchName = objName +
"s"
804 vecName =
"vector<%s>" % classname
805 tree.Branch( branchName, vecName, vec)
808 return rootfile, tree
812 def setupDiffOutputTree (outputFile, diffName, missingName,
813 diffDescription =
'', missingDescription =
''):
814 """Opens the diff output file, loads all of the necessary
815 shared object libraries, and returns the output file and tree.b"""
816 rootfile = ROOT.TFile.Open (outputFile,
"recreate")
817 GenObject._loadGoRootLibrary()
819 diffTree = ROOT.TTree (diffName, diffDescription)
820 runEventObject = getattr (ROOT,
'go_runevent')()
821 diffTree.Branch (
'runevent',
'go_runevent', runEventObject)
822 GenObject._rootClassDict[
'runevent'] = runEventObject
823 for objName
in sorted (GenObject._objsDict.keys()):
824 if objName ==
'runevent':
continue
825 classname = GenObject.rootClassName (objName)
826 GenObject._rootClassDict[classname] = getattr (ROOT, classname)
827 contName = GenObject.rootDiffContClassName (objName)
828 diffName = GenObject.rootDiffClassName (objName)
829 rootObj = GenObject._rootClassDict[contName] = \
830 getattr (ROOT, contName)
831 GenObject._rootClassDict[diffName] = getattr (ROOT, diffName)
832 obj = GenObject._rootObjectDict[objName] = rootObj()
833 diffTree.Branch (objName, contName, obj)
835 missingTree = ROOT.TTree (missingName, missingDescription)
836 rootRunEventClass = getattr (ROOT,
'go_runevent')
837 firstOnly = GenObject._rootClassDict[
'firstOnly'] = \
838 ROOT.std.vector( rootRunEventClass ) ()
839 secondOnly = GenObject._rootClassDict[
'secondOnly'] = \
840 ROOT.std.vector( rootRunEventClass ) ()
841 missingTree.Branch (
'firstOnly',
'vector<go_runevent>', firstOnly)
842 missingTree.Branch (
'secondOnly',
'vector<go_runevent>', secondOnly)
843 return rootfile, diffTree, missingTree
847 def _fillRootObjects (event):
848 """Fills root objects from GenObject 'event'"""
849 for objName, obj
in sorted (event.items()):
850 if GenObject.isSingleton (objName):
852 GenObject._rootObjectCopy (obj,
853 GenObject._rootObjectDict[objName])
856 vec = GenObject._rootObjectDict[objName]
859 vec.push_back( GenObject._rootObjectClone (goObj) )
863 def _fillRootDiffs (event1, event2):
864 """Fills root diff containers from two GenObject 'event's"""
869 def isSingleton (objName):
870 """Returns true if object is a singleton"""
871 return GenObject._objsDict[objName].get(
'_singleton')
875 def loadEventFromTree (eventTree, eventIndex,
876 onlyRunEvent =
False):
877 """Loads event information from Root file (as interfaced by
878 'cmstools.EventTree' or 'ROOT.TChain'). Returns a dictionary
879 'event' containing lists of objects or singleton object. If
880 'onlyRunEvent' is et to True, then only run and event number
881 is read in from the tree."""
882 debug = GenObject._kitchenSinkDict.get (
'debug',
False)
883 tupleName = GenObject._kitchenSinkDict[eventTree][
'tupleName']
886 isChain = eventTree.__class__.__name__ ==
'TChain'
889 eventTree.GetEntry (eventIndex)
892 eventTree.to(eventIndex)
893 tofillDict = GenObject._tofillDict.get (tupleName)
894 ntupleDict = GenObject._ntupleDict.get (tupleName)
896 print(
"Don't know how to fill from '%s' ntuple." % tupleName)
898 eventBranchName = ntupleDict[
'runevent']
899 for objName
in tofillDict:
900 branchName = ntupleDict[objName]
901 if onlyRunEvent
and branchName != eventBranchName:
910 objects = getattr (eventTree, branchName)
913 shortcut = ntupleDict.get(
'_shortcut', {}).get(branchName)
915 objects = GenObject.evaluateFunction (eventTree, shortcut)
918 handle = ntupleDict.get(
'_handle', {}).get(branchName)
919 label = ntupleDict.get(
'_label' , {}).get(branchName)
920 if not handle
or not label:
921 raise RuntimeError(
"Missing handle or label for '%s'"\
923 if not eventTree.getByLabel (label, handle):
924 raise RuntimeError(
"not able to get %s for %s" \
925 % (label, branchName))
926 objects = handle.product()
928 if GenObject.isSingleton (objName):
929 event[objName] = GenObject.\
930 _genObjectClone (objName,
935 if debug: warn (objName, spaces = 3)
937 for index, obj
in enumerate (objects):
938 event[objName].
append( GenObject.\
939 _genObjectClone (objName,
952 def printEvent (event):
953 """Prints out event dictionary. Mostly for debugging"""
955 for objName, obj
in sorted (event.items()):
958 if GenObject.isSingleton (objName):
959 print(
"%s: %s" % (objName, obj))
961 for objName, obj
in sorted (event.items()):
964 if not GenObject.isSingleton (objName):
966 print(
"%s:" % objName)
973 def setAliases (eventTree, tupleName):
974 """runs SetAlias on all saved aliases"""
975 aliases = GenObject._ntupleDict[tupleName].get(
'_alias', {})
976 for name, alias
in aliases.items():
977 eventTree.SetAlias (name, alias)
981 def changeAlias (tupleName, name, alias):
982 """Updates an alias for an object for a given tuple"""
983 aliasDict = GenObject._ntupleDict[tupleName][
'_alias']
984 if name
not in aliasDict:
985 raise RuntimeError(
"unknown name '%s' in tuple '%s'" % \
987 aliasDict[name] = alias
991 def changeLabel (tupleName, objectName, label):
992 """Updates an label for an object for a given tuple"""
993 labelDict = GenObject._ntupleDict[tupleName][
'_label']
994 if objectName
not in labelDict:
995 raise RuntimeError(
"unknown name '%s' in tuple '%s'" % \
996 (objectName, tupleName))
997 label = tuple( GenObject._commaRE.split( label ) )
998 labelDict[objectName] = label
1002 def prepareTuple (tupleName, files, numEventsWanted = 0):
1003 """Given the tuple name and list of files, returns either a
1004 TChain or EventTree, and number of entries"""
1005 if "GenObject" == tupleName:
1006 GenObject.prepareToLoadGenObject()
1007 if not isinstance (files, list):
1010 ntupleDict = GenObject._ntupleDict[tupleName]
1011 treeName = ntupleDict[
"_tree"]
1012 if ntupleDict.get(
'_useChain'):
1013 chain = ROOT.TChain (treeName)
1014 for filename
in files:
1015 chain.AddFile (filename)
1016 numEntries = chain.GetEntries()
1019 chain = Events (files, forceEvent=
True)
1020 numEntries = chain.size()
1021 chainDict = GenObject._kitchenSinkDict.setdefault (chain, {})
1022 if numEventsWanted
and numEventsWanted < numEntries:
1023 numEntries = numEventsWanted
1024 chainDict[
'numEntries'] = numEntries
1025 chainDict[
'tupleName' ] = tupleName
1030 def getRunEventEntryDict (chain, tupleName, numEntries):
1031 """Returns a dictionary of run, event tuples to entryIndicies"""
1033 for entryIndex
in range (numEntries):
1034 event = GenObject.loadEventFromTree (chain,
1036 onlyRunEvent =
True)
1037 runevent = event[
'runevent']
1038 reeDict[ GenObject._re2key (runevent) ] = entryIndex
1045 def _re2key (runevent):
1046 """Given a GO 'runevent' object, returns a sortable key"""
1049 if not GenObject._runEventListDone:
1050 GenObject._runEventListDone =
True
1051 ignoreSet = set( [
'run',
'event'] )
1052 for varName
in sorted (runevent.__dict__.keys()):
1053 if varName.startswith (
'_')
or varName
in ignoreSet:
1055 form = runevent.getVariableProperty (varName,
"form")
1058 GenObject._runEventList.append ((varName, form))
1059 key =
'run:%d event:%d' % (runevent.run, runevent.event)
1060 for items
in GenObject._runEventList:
1062 form =
' %s:%s' % (varName, items[1])
1063 key += form % runevent.getVariableProperty (varName)
1068 def _key2re (key, runevent=None):
1069 """Given a key, returns a GO 'runevent' object"""
1071 runevent = GenObject (
'runevent')
1072 words = GenObject._spacesRE.split (key)
1074 match = GenObject._singleColonRE.search (word)
1079 runevent.__setattr__ (match.group(1), int( match.group(2) ))
1084 def compareRunEventDicts (firstDict, secondDict):
1085 """Compares the keys of the two dicts and returns three sets:
1086 the overlap, first but not second, and second but not first."""
1091 for key
in firstDict.keys():
1092 if key
in secondDict:
1098 for key
in secondDict.keys():
1099 if key
not in firstDict:
1100 secondOnly.add (key)
1102 return overlap, firstOnly, secondOnly
1106 def pairEquivalentObjects (vec1, vec2):
1107 """Finds the equivalent objects in the two vectors"""
1108 len1, len2 = len (vec1), len (vec2)
1109 debug = GenObject._kitchenSinkDict.get (
'debug',
False)
1110 if not len1
or not len2:
1113 noMatch1Set = set(
range(len1) )
1115 noMatch1Set = set ()
1117 noMatch2Set = set(
range(len2) )
1119 noMatch2Set = set ()
1120 if debug: warn (
"Nothing found", sapces=6)
1121 return set(), noMatch1Set, noMatch2Set
1122 objName = vec1[0]._objName
1123 equivList = GenObject._equivDict[objName]
1127 if GenObject._kitchenSinkDict.get (
'strictPairing')
or \
1128 equivList == [(
'index', 0)]:
1130 matchedSet = set (zip ( list(
range( min (len1, len2))),
1131 list(
range( min (len1, len2))) ) )
1135 noMatch1Set = set (
range(len2, len1 + 1))
1140 noMatch2Set = set (
range(len1, len2 + 1))
1143 return matchedSet, noMatch1Set, noMatch2Set
1158 for index1
in range (len1):
1161 for index2
in range (len2):
1165 for equiv
in equivList:
1166 var, precision = equiv[0], equiv[1]
1171 value = abs (val1 - val2) / precision
1180 objList.append( (total, index2) )
1182 firstDict[index1] = objList
1185 for index2
in range (len2):
1188 for index1
in range (len1):
1192 for equiv
in equivList:
1193 var, precision = equiv[0], equiv[1]
1198 value = abs (val2 - val1) / precision
1207 objList.append( (total, index1) )
1209 secondDict[index2] = objList
1214 firstDictKeys = sorted (firstDict.keys())
1215 for index1
in firstDictKeys:
1216 list1 = firstDict[index1]
1220 noMatch1Set.add (index1)
1226 list2 = secondDict.get (index2, [])
1227 if len(list2)
and list2[0][1] == index1:
1228 matchedSet.add( (index1, index2) )
1230 del firstDict[index1]
1231 del secondDict[index2]
1234 noMatch1Set.add (index1)
1235 noMatch2Set = set( secondDict.keys() )
1236 return matchedSet, noMatch1Set, noMatch2Set
1240 def compareTwoItems (item1, item2):
1241 """Compares all of the variables making sure they are the same
1242 on the two objects."""
1243 objName = item1._objName
1245 relative = GenObject._kitchenSinkDict.get (
'relative',
False)
1246 for varName
in GenObject._objsDict[objName].
keys():
1247 prec = item1.getVariableProperty (varName,
'prec')
1251 val1 = item1(varName)
1252 val2 = item2(varName)
1253 numerator = 2 * abs (val1 - val2)
1254 denominator =
abs(val1) +
abs(val2)
1259 value = numerator / denominator
1262 problems[varName] = value
1264 value =
abs( item1(varName) - item2(varName) )
1267 problems[varName] = value
1270 if item1(varName) != item2(varName):
1272 val1, val2 = item1(varName), item2(varName)
1274 val1, val2 = val2, val1
1275 problems[varName] =
"%s != %s" % (val1, val2)
1281 def blurEvent (event, value, where = ""):
1282 """For debugging purposes only. Will deliberately change
1283 values of first tree to verify that script is correctly
1284 finding problems."""
1285 for objName
in sorted (event.keys()):
1286 if "runevent" == objName:
1289 if GenObject.isSingleton (objName):
1293 for obj
in event[objName]:
1295 for varName
in GenObject._objsDict[objName].
keys():
1296 if isinstance (obj.__dict__[varName], str):
1299 randNumber = random.random()
1301 if randNumber < GenObject._kitchenSinkDict[
'blurRate']:
1302 print(
" %s: changing '%s' of '%s:%d'" \
1303 % (where, varName, obj._objName, count))
1306 obj.__dict__[varName] += value
1310 def compareTwoTrees (chain1, chain2, **kwargs):
1311 """Given all of the necessary information, this routine will
1312 go through and compare two trees making sure they are
1313 'identical' within requested precision. If 'diffOutputName'
1314 is passed in, a root file with a diffTree and missingTree will
1316 print(
"Comparing Two Trees")
1317 diffOutputName = kwargs.get (
'diffOutputName')
1318 tupleName1 = GenObject._kitchenSinkDict[chain1][
'tupleName']
1319 numEntries1 = GenObject._kitchenSinkDict[chain1][
'numEntries']
1320 tupleName2 = GenObject._kitchenSinkDict[chain2][
'tupleName']
1321 numEntries2 = GenObject._kitchenSinkDict[chain2][
'numEntries']
1322 debug = GenObject._kitchenSinkDict.get (
'debug',
False)
1323 ree1 = GenObject.getRunEventEntryDict (chain1, tupleName1, numEntries1)
1324 ree2 = GenObject.getRunEventEntryDict (chain2, tupleName2, numEntries2)
1325 overlap, firstOnly, secondOnly = \
1326 GenObject.compareRunEventDicts (ree1, ree2)
1328 rootfile, diffTree, missingTree = \
1329 GenObject.setupDiffOutputTree (diffOutputName,
1333 vec = GenObject._rootClassDict[
'firstOnly']
1334 for key
in firstOnly:
1335 runevent = GenObject._key2re (key)
1336 vec.push_back( GenObject._rootObjectClone( runevent ) )
1338 vec = GenObject._rootClassDict[
'secondOnly']
1339 for key
in secondOnly:
1340 runevent = GenObject._key2re (key)
1341 vec.push_back( GenObject._rootObjectClone( runevent ) )
1345 resultsDict.setdefault (
'_runevent', {})[
'firstOnly'] = \
1348 resultsDict.setdefault (
'_runevent', {})[
'secondOnly'] = \
1350 resultsDict[
'eventsCompared'] = len (overlap)
1351 for reTuple
in sorted(overlap):
1355 GenObject._key2re (reTuple,
1356 GenObject._rootClassDict[
'runevent'])
1357 if debug: warn (
'event1', blankLines = 3)
1358 event1 = GenObject.loadEventFromTree (chain1, ree1 [reTuple])
1359 if debug: warn (
'event2', blankLines = 3)
1360 event2 = GenObject.loadEventFromTree (chain2, ree2 [reTuple])
1361 if GenObject._kitchenSinkDict.get(
'printEvent'):
1363 GenObject.printEvent (event1)
1365 GenObject.printEvent (event2)
1366 if GenObject._kitchenSinkDict.get(
'blur'):
1368 GenObject.blurEvent (event1,
1369 GenObject._kitchenSinkDict[
'blur'],
1371 for objName
in sorted (event1.keys()):
1372 if "runevent" == objName:
1375 if not GenObject._equivDict.get (objName):
1379 if GenObject.isSingleton (objName):
1386 rootObj = GenObject._rootObjectDict[objName]
1388 vec1 = event1[objName]
1389 vec2 = event2[objName]
1390 matchedSet, noMatch1Set, noMatch2Set = \
1391 GenObject.pairEquivalentObjects (vec1, vec2)
1392 if noMatch1Set
or noMatch2Set:
1395 count1 = len (noMatch1Set)
1396 count2 = len (noMatch2Set)
1397 key = (count1, count2)
1398 countDict = resultsDict.\
1399 setdefault (objName, {}).\
1400 setdefault (
'_missing', {})
1401 if key
in countDict:
1408 for index
in sorted(list(noMatch1Set)):
1409 goObj = vec1 [index]
1410 rootObj.firstOnly.push_back ( GenObject.\
1414 for index
in sorted(list(noMatch2Set)):
1415 goObj = vec2 [index]
1416 rootObj.secondOnly.push_back ( GenObject.\
1421 for pair
in sorted(list(matchedSet)):
1423 rootDiffObj = GenObject._rootDiffObject \
1424 ( vec1[ pair[1 - 1] ],
1425 vec2[ pair[2 - 1] ] )
1426 rootObj.diff.push_back ( rootDiffObj )
1427 problems = GenObject.\
1428 compareTwoItems (vec1[ pair[1 - 1] ],
1429 vec2[ pair[2 - 1] ])
1432 for varName
in problems.keys():
1433 countDict = resultsDict.\
1434 setdefault (objName, {}).\
1435 setdefault (
'_var', {})
1436 if varName
in countDict:
1437 countDict[varName] += 1
1439 countDict[varName] = 1
1440 key =
'count_%s' % objName
1441 if key
not in resultsDict:
1442 resultsDict[key] = 0
1443 resultsDict[key] += len (matchedSet)
1461 def saveTupleAs (chain, rootFile):
1462 """Saves a chain as a GO tree"""
1463 print(
"saveTupleAs")
1464 rootfile, tree = GenObject.setupOutputTree (rootFile,
"goTree")
1465 numEntries = GenObject._kitchenSinkDict[chain][
'numEntries']
1466 for entryIndex
in range (numEntries):
1467 event = GenObject.loadEventFromTree (chain, entryIndex)
1468 if GenObject._kitchenSinkDict.get(
'blur'):
1469 where =
"run %d event %d" % (event[
'runevent'].run,
1470 event[
'runevent'].event)
1471 if random.random() < GenObject._kitchenSinkDict.get(
'blur'):
1473 print(
"Dropping", where)
1475 GenObject.blurEvent (event,
1476 GenObject._kitchenSinkDict[
'blur'],
1479 if GenObject._kitchenSinkDict.get(
'printEvent'):
1480 GenObject.printEvent (event)
1481 GenObject._fillRootObjects (event)
1488 def setGlobalFlag (key, value):
1489 """Sets a global flag in _kitchenSinkDict"""
1490 GenObject._kitchenSinkDict [key] = value
1494 def printTuple (chain):
1495 """Prints out all events to stdout"""
1496 numEntries = GenObject._kitchenSinkDict[chain][
'numEntries']
1497 debug = GenObject._kitchenSinkDict.get (
'debug',
False)
1498 if debug: warn (numEntries)
1499 for entryIndex
in range (numEntries):
1500 if debug: warn (entryIndex, spaces=3)
1501 event = GenObject.loadEventFromTree (chain, entryIndex)
1502 GenObject.printEvent (event)
1503 if debug:
warn(spaces=3)
1506 def _convertStringToParameters (string):
1507 """Convert comma-separated string into a python3 list of
1508 parameters. Currently only understands strings, floats, and
1511 words = GenObject._commaRE.split (string)
1515 match = GenObject._singleQuoteRE.search (word)
1517 retval.append (match.group (1))
1519 match = GenObject._doubleQuoteRE.search (word)
1521 retval.append (match.group (1))
1536 raise RuntimeError(
"Unknown parameter '%s'." % word)
1546 """Class initializer"""
1547 if objName
not in GenObject._objsDict:
1550 print(
"Error: GenObject does not know about object '%s'." % objName)
1551 raise RuntimeError(
"Failed to create GenObject object.")
1552 self._localObjsDict = GenObject._objsDict [objName]
1553 self._objName = objName;
1554 for key, varDict
in self._localObjsDict.items():
1557 if key.startswith (
"_"):
1559 self.setValue (key, varDict[
'default'])
1563 """Wrapper for __setattr___"""
1564 self.__setattr__ (name, value)
1567 def getVariableProperty (self, var, key):
1568 """ Returns property assoicated with 'key' for variable 'var'
1569 of object of the same type as 'self'. Returns 'None' if 'var'
1570 or 'key' is not defined."""
1571 return GenObject._objsDict.get (self._objName,
1572 {}).get (var, {}). get (key,
None)
1575 def __setattr__ (self, name, value):
1576 """Controls setting of values."""
1577 if name.startswith (
"_"):
1579 object.__setattr__ (self, name, value)
1584 if name
not in self._localObjsDict:
1586 print(
"Warning: '%s' for class '%s' not setup. Skipping." % \
1587 (name, self._objName))
1589 varType = self.getVariableProperty (name,
'varType')
1591 if GenObject.types.int == varType:
1598 value = int( float( value ) )
1599 elif GenObject.types.long == varType:
1603 value = long (value)
1606 value = long( float( value ) )
1607 elif GenObject.types.float == varType:
1609 value = float (value)
1610 elif GenObject.types.string == varType:
1614 object.__setattr__ (self, name, value)
1617 def __call__ (self, key):
1618 """Makes object callable"""
1619 return object.__getattribute__ (self, key)
1623 """String representation"""
1625 for varName, value
in sorted (self.__dict__.items()):
1626 if varName.startswith (
'_'):
continue
1627 form = self.getVariableProperty (varName,
"form")
1629 format =
"%s:%s " % (varName, form)
1630 retval = retval + format % value
1632 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 ...
const uint16_t range(const Frame &aFrame)
void print(TMatrixD &m, const char *label=nullptr, bool mathematicaFormat=false)
Abs< T >::type abs(const T &t)