CMS 3D CMS Logo

GenObject.py
Go to the documentation of this file.
1 from __future__ import print_function
2 ## Note: Please do not use or modify any data or functions with a
3 ## leading underscore. If you "mess" with the internal structure,
4 ## the classes may not function as intended.
5 
6 
7 from builtins import range
8 from FWCore.Utilities.Enumerate import Enumerate
9 from DataFormats.FWLite import Events, Handle
10 import re
11 import os
12 import copy
13 import pprint
14 import random
15 import sys
16 import inspect
17 import ROOT
18 import six
19 from functools import reduce
20 ROOT.gROOT.SetBatch()
21 
22 # regex for reducing 'warn()' filenames
23 filenameRE = re.compile (r'.+/Validation/Tools/')
24 # Whether warn() should print anythingg
25 quietWarn = False
26 
27 def setQuietWarn (quiet = True):
28  global quietWarn
29  quietWarn = quiet
30 
31 
32 def warn (*args, **kwargs):
33  """print out warning with line number and rest of arguments"""
34  if quietWarn: return
35  frame = inspect.stack()[1]
36  filename = frame[1]
37  lineNum = frame[2]
38  #print filename, filenameRE
39  filename = filenameRE.sub ('', filename)
40  #print "after '%s'" % filename
41  blankLines = kwargs.get('blankLines', 0)
42  if blankLines:
43  print('\n' * blankLines)
44  spaces = kwargs.get('spaces', 0)
45  if spaces:
46  print(' ' * spaces, end=' ')
47  if len (args):
48  print("%s (%s): " % (filename, lineNum), end=' ')
49  for arg in args:
50  print(arg, end=' ')
51  print()
52  else:
53  print("%s (%s):" % (filename, lineNum))
54 
55 
56 class GenObject (object):
57  """Infrastruture to define general objects and their attributes."""
58 
59  ########################
60  ## Static Member Data ##
61  ########################
62 
63  types = Enumerate ("float int long string", "type")
64  _objFunc = Enumerate ("obj func", "of")
65  _cppType = dict ( {types.float : 'double',
66  types.int : 'int',
67  types.long : 'long',
68  types.string : 'std::string' } )
69  _basicSet = set( [types.float, types.int, types.float,
70  types.string] )
71  _defaultValue = dict ( {types.float : 0.,
72  types.int : 0,
73  types.long : 0,
74  types.string : '""' } )
75  _objsDict = {} # info about GenObjects
76  _equivDict = {} # hold info about 'equivalent' muons
77  _ntupleDict = {} # information about different ntuples
78  _tofillDict = {} # information on how to fill from different ntuples
79  _rootObjectDict = {} # hold objects and stl::vectors to objects
80  # hooked up to a root tree
81  _rootClassDict = {} # holds classes (not instances) associated with
82  # a given GenObject
83  _kitchenSinkDict = {} # dictionary that holds everything else...
84  _runEventList = []
85  _runEventListDone = False
86  uselessReturnCode = 1 << 7 # pick a unique return code
87 
88  ####################
89  ## Compile Regexs ##
90  ####################
91  _nonSpacesRE = re.compile (r'\S')
92  _colonRE = re.compile (r'\s*:\s*')
93  _singleColonRE = re.compile (r'(.+?):(.+)')
94  _doubleColonRE = re.compile (r'(.+?):(.+?):(.+)')
95  _doublePercentRE = re.compile (r'%%')
96  _parenRE = re.compile (r'(.+)\((.*)\)')
97  _spacesRE = re.compile (r'\s+')
98  _dotRE = re.compile (r'\s*\.\s*')
99  _commaRE = re.compile (r'\s*,\s*')
100  _singleQuoteRE = re.compile (r'^\'(.+)\'$')
101  _doubleQuoteRE = re.compile (r'^\"(.+)\"$')
102  _bracketRE = re.compile (r'\[\s*(.+?)\s*\]')
103  _commentRE = re.compile (r'#.+$')
104  _aliasRE = re.compile (r'alias=(\S+)', re.IGNORECASE)
105  _labelRE = re.compile (r'label=(\S+)', re.IGNORECASE)
106  _typeRE = re.compile (r'type=(\S+)', re.IGNORECASE)
107  _singletonRE = re.compile (r'singleton', re.IGNORECASE)
108  _typeRE = re.compile (r'type=(\S+)', re.IGNORECASE)
109  _defaultRE = re.compile (r'default=(\S+)', re.IGNORECASE)
110  _shortcutRE = re.compile (r'shortcut=(\S+)', re.IGNORECASE)
111  _precRE = re.compile (r'prec=(\S+)', re.IGNORECASE)
112  _formRE = re.compile (r'form=(\S+)', re.IGNORECASE)
113  _nonAlphaRE = re.compile (r'\W')
114  _percentAsciiRE = re.compile (r'%([0-9a-fA-F]{2})')
115 
116  #############################
117  ## Static Member Functions ##
118  #############################
119 
120  @staticmethod
121  def char2ascii (match):
122  return "%%%02x" % ord (match.group(0))
123 
124  @staticmethod
125  def ascii2char (match):
126  return chr( int( match.group(1), 16 ) )
127 
128  @staticmethod
130  """Use a web like encoding of characters that are non-alphanumeric"""
131  return GenObject._nonAlphaRE.sub( GenObject.char2ascii, line )
132 
133  @staticmethod
135  """Decode lines encoded with encodeNonAlphanumerics()"""
136  return GenObject._percentAsciiRE.sub( GenObject.ascii2char, line )
137 
138 
139  @staticmethod
140  def addObjectVariable (obj, var, **optionsDict):
141  """ User passes in in object and variable names."""
142  if 'varType' not in optionsDict:
143  optionsDict['varType'] = GenObject.types.float
144  varType = optionsDict['varType']
145  if not GenObject.types.isValidValue (varType):
146  print("Type '%s' not valid. Skipping (%s, %s, %s)." % \
147  (varType, obj, var, varType))
148  return
149  if 'default' not in optionsDict:
150  optionsDict['default'] = GenObject._defaultValue[varType]
151  if obj.startswith ("_") or var.startswith ("_"):
152  print("Skipping (%s, %s, %s) because of leading underscore." % \
153  (obj, var, varType))
154  return
155  GenObject._objsDict.setdefault (obj, {}).setdefault (var, optionsDict)
156 
157 
158  @staticmethod
159  def getVariableProperty (obj, var, key):
160  """Returns property assoicated with 'key' for variable 'var'
161  of object 'obj'. Returns 'None' if any of the above are not
162  defined."""
163  return GenObject._objsDict.get (obj, {}).get (var, {}). get (key, None)
164 
165 
166  @staticmethod
167  def setEquivExpression (obj, variable, precision):
168  """Adds an equivalence constraint. Must have at least one to
169  compare GO objects."""
170  if obj.startswith ("_"):
171  print("Skipping (%s, %s) because of leading underscore." % \
172  (obj, expression))
173  return
174  GenObject._equivDict.setdefault (obj,[]).append ( (variable,
175  precision) )
176 
177 
178  @staticmethod
179  def printGlobal():
180  """Meant for debugging, but ok if called by user"""
181  print("objs: ")
182  pprint.pprint (GenObject._objsDict, indent=4)
183  print("equiv: ")
184  pprint.pprint (GenObject._equivDict, indent=4)
185  print("ntuple: ")
186  pprint.pprint (GenObject._ntupleDict, indent=4)
187  print("tofill: ")
188  pprint.pprint (GenObject._tofillDict, indent=4)
189  print("kitchenSink: ")
190  pprint.pprint (GenObject._kitchenSinkDict, indent=4)
191  print("rootClassDict")
192  pprint.pprint (GenObject._rootClassDict, indent=4)
193 
194 
195  @staticmethod
196  def checksum (str):
197  """Returns a string of hex value of a checksum of input
198  string."""
199  return hex( reduce( lambda x, y : x + y, map(ord, str) ) )[2:]
200 
201 
202  @staticmethod
203  def rootClassName (objName):
204  """Returns the name of the equivalent Root object"""
205  return "go_" + objName
206 
207 
208  @staticmethod
209  def rootDiffClassName (objName):
210  """Returns the name of the equivalent Root diff object"""
211  return "goDiff_" + objName
212 
213 
214  @staticmethod
215  def rootDiffContClassName (objName):
216  """Returns the name of the equivalent Root diff container
217  object"""
218  return "goDiffCont_" + objName
219 
220 
221  @staticmethod
222  def _setupClassHeader (className, noColon = False):
223  """Returns a string with the class header for a class
224  'classname'"""
225  retval = "\nclass %s\n{\n public:\n" % className
226  retval += " typedef std::vector< %s > Collection;\n\n" % className
227  # constructor
228  if noColon:
229  retval += " %s()" % className
230  else:
231  retval += " %s() :\n" % className
232  return retval
233 
234 
235  @staticmethod
236  def _finishClassHeader (className, datadec):
237  """Returns a stringg with the end of a class definition"""
238  retval = "\n {}\n" + datadec + "};\n"
239  retval += "#ifdef __MAKECINT__\n#pragma link C++ class " + \
240  "vector< %s >+;\n#endif\n\n" % className
241  return retval
242 
243 
244  @staticmethod
245  def _createCppClass (objName):
246  """Returns a string containing the '.C' file necessary to
247  generate a shared object library with dictionary."""
248  if objName not in GenObject._objsDict:
249  # not good
250  print("Error: GenObject does not know about object '%s'." % objName)
251  raise RuntimeError("Failed to create C++ class.")
252  className = GenObject.rootClassName (objName)
253  diffName = GenObject.rootDiffClassName (objName)
254  contName = GenObject.rootDiffContClassName (objName)
255  goClass = GenObject._setupClassHeader (className)
256  diffClass = GenObject._setupClassHeader (diffName)
257  contClass = GenObject._setupClassHeader (contName, noColon = True)
258  goDataDec = diffDataDec = contDataDec = "\n // data members\n"
259  first = True
260  for key in sorted( GenObject._objsDict[objName].keys() ):
261  if key.startswith ("_"): continue
262  varTypeList = GenObject._objsDict[objName][key]
263  cppType = GenObject._cppType[ varTypeList['varType'] ]
264  default = varTypeList['default']
265  if first:
266  first = False
267  else:
268  goClass += ",\n"
269  diffClass += ',\n'
270  goClass += " %s (%s)" % (key, default)
271  goDataDec += " %s %s;\n" % (cppType, key)
272  # is this a basic class?
273  goType = varTypeList['varType']
274  if goType in GenObject._basicSet:
275  # basic type
276  diffClass += " %s (%s),\n" % (key, default)
277  diffDataDec += " %s %s;\n" % (cppType, key)
278  if goType == GenObject.types.string:
279  # string
280  otherKey = 'other_' + key
281  diffClass += " %s (%s)" % (otherKey, default)
282  diffDataDec += " %s %s;\n" % (cppType, otherKey)
283  else:
284  # float, long, or int
285  deltaKey = 'delta_' + key
286  diffClass += " %s (%s)" % (deltaKey, default)
287  diffDataDec += " %s %s;\n" % (cppType, deltaKey)
288  else:
289  raise RuntimeError("Shouldn't be here yet.")
290  # definition
291  # do contClass
292  if GenObject.isSingleton (objName):
293  # singleton
294  contDataDec += " %s diff;\n" % diffName
295  contDataDec += " void setDiff (const %s &rhs)" % diffName + \
296  " { diff = rhs; }\n"
297  else:
298  # vector of objects
299  contDataDec += " void clear() {firstOnly.clear(); secondOnly.clear(); diff.clear(); }\n"
300  contDataDec += " %s::Collection firstOnly;\n" % className
301  contDataDec += " %s::Collection secondOnly;\n" % className
302  contDataDec += " %s::Collection diff;\n" % diffName
303  # give me a way to clear them all at once
304  # Finish off the classes
305  goClass += GenObject._finishClassHeader (className, goDataDec)
306  diffClass += GenObject._finishClassHeader (diffName, diffDataDec)
307  contClass += GenObject._finishClassHeader (contName, contDataDec)
308  if objName == 'runevent':
309  # we don't want a diff class for this
310  diffClass = ''
311  contClass = ''
312  return goClass + diffClass + contClass
313 
314 
315  @staticmethod
317  """Loads Root shared object library associated with all
318  defined GenObjects. Will create library if necessary."""
319  print("Loading GO Root Library")
320  key = "_loadedLibrary"
321  if GenObject._kitchenSinkDict.get (key):
322  # Already done, don't do it again:
323  return
324  # Mark it as done
325  GenObject._kitchenSinkDict[key] = True
326  # Generate source code
327  sourceCode = "#include <string>\n#include <vector>\n" \
328  + "using namespace std;\n"
329  for objClassName in sorted( GenObject._objsDict.keys() ):
330  sourceCode += GenObject._createCppClass (objClassName)
331  GenObjectRootLibDir = "genobjectrootlibs"
332  if not os.path.exists (GenObjectRootLibDir):
333  os.mkdir (GenObjectRootLibDir)
334  key = GenObject.checksum( sourceCode )
335  basename = "%s_%s" % ("GenObject", key)
336  SO = "%s/%s_C" % (GenObjectRootLibDir, basename)
337  linuxSO = "%s.so" % SO
338  windowsSO = "%s.dll" % SO
339  if not os.path.exists (linuxSO) and not os.path.exists (windowsSO):
340  print("creating SO")
341  filename = "%s/%s.C" % (GenObjectRootLibDir, basename)
342  if not os.path.exists (filename):
343  print("creating .C file")
344  target = open (filename, "w")
345  target.write (sourceCode)
346  target.close()
347  else:
348  print("%s exists" % filename)
349  ## command = "echo .L %s+ | root.exe -b" % filename
350  ## os.system (command)
351  ROOT.gSystem.CompileMacro (filename, "k")
352  else:
353  print("loading %s" % SO)
354  ROOT.gSystem.Load(SO)
355  return
356 
357 
358  @staticmethod
360  """Makes sure that I know how to read root files I made myself"""
361  genObject = "GenObject"
362  ntupleDict = GenObject._ntupleDict.setdefault (genObject, {})
363  ntupleDict['_useChain'] = True
364  ntupleDict['_tree'] = "goTree"
365  for objName in GenObject._objsDict.keys():
366  rootObjName = GenObject.rootClassName (objName)
367  if GenObject.isSingleton (objName):
368  ntupleDict[objName] = objName
369  else:
370  ntupleDict[objName] = objName + "s"
371  tofillDict = GenObject._tofillDict.\
372  setdefault (genObject, {}).\
373  setdefault (objName, {})
374  for varName in GenObject._objsDict [objName].keys():
375  # if the key starts with an '_', then it is not a
376  # variable, so don't treat it as one.
377  if varName.startswith ("_"):
378  continue
379  tofillDict[varName] = [ [(varName, GenObject._objFunc.obj)],
380  {}]
381 
382 
383  @staticmethod
385  """Makes all necessary preparations to load root files created
386  by GenObject."""
387  GenObject._tofillGenObject()
388  GenObject._loadGoRootLibrary()
389 
390 
391  @staticmethod
392  def parseVariableTofill (fillname):
393  """Returns tofill tuple made from string"""
394  parts = GenObject._dotRE.split (fillname)
395  partsList = []
396  for part in parts:
397  parenMatch = GenObject._parenRE.search (part)
398  mode = GenObject._objFunc.obj
399  parens = []
400  if parenMatch:
401  part = parenMatch.group (1)
402  mode = GenObject._objFunc.func
403  parens = \
404  GenObject._convertStringToParameters \
405  (parenMatch.group (2))
406  partsList.append( (part, mode, parens) )
407  return partsList
408 
409  @staticmethod
410  def _fixLostGreaterThans (handle):
411  offset = handle.count ('<') - handle.count('>')
412  if not offset:
413  return handle
414  if offset < 0:
415  print("Huh? Too few '<' for each '>' in handle '%'" % handle)
416  return handle
417  return handle + ' >' * offset
418 
419 
420  @staticmethod
421  def loadConfigFile (configFile):
422  """Loads configuration file"""
423  objName = ""
424  tupleName = ""
425  tofillName = ""
426  modeEnum = Enumerate ("none define tofill ntuple", "mode")
427  mode = modeEnum.none
428  try:
429  config = open (configFile, 'r')
430  except:
431  raise RuntimeError("Can't open configuration '%s'" % configFile)
432  for lineNum, fullLine in enumerate (config):
433  fullLine = fullLine.strip()
434  # get rid of comments
435  line = GenObject._commentRE.sub ('', fullLine)
436  # Is there anything on this line?
437  if not GenObject._nonSpacesRE.search (line):
438  # Nothing to see here folks. Keep moving....
439  continue
440  ###################
441  ## Bracket Match ##
442  ###################
443  bracketMatch = GenObject._bracketRE.search (line)
444  if bracketMatch:
445  # a header
446  section = bracketMatch.group(1)
447  words = GenObject._spacesRE.split( section )
448  if len (words) < 1:
449  raise RuntimeError("Don't understand line '%s'(%d)" \
450  % (fullLine, lineNum))
451  # The first word is the object name
452  # reset the rest of the list
453  objName = words[0]
454  words = words[1:]
455  colonWords = GenObject._colonRE.split (objName)
456  if len (colonWords) > 3:
457  raise RuntimeError("Don't understand line '%s'(%d)" \
458  % (fullLine, lineNum))
459  if len (colonWords) == 1:
460  ##########################
461  ## GenObject Definition ##
462  ##########################
463  mode = modeEnum.define
464  for word in words:
465  if GenObject._singletonRE.match (word):
466  #GenObject._singletonSet.add (objName)
467  objsDict = GenObject._objsDict.\
468  setdefault (objName, {})
469  objsDict['_singleton'] = True
470  continue
471  # If we're still here, then we didn't have a valid
472  # option. Complain vociferously
473  print("I don't understand '%s' in section '%s' : %s" \
474  % (word, section, mode))
475  raise RuntimeError("Config file parser error '%s'(%d)" \
476  % (fullLine, lineNum))
477  elif len (colonWords) == 2:
478  #######################
479  ## Ntuple Definition ##
480  #######################
481  mode = modeEnum.ntuple
482  ntupleDict = GenObject._ntupleDict.\
483  setdefault (colonWords[0], {})
484  ntupleDict['_tree'] = colonWords[1]
485  else:
486  ##########################
487  ## Object 'tofill' Info ##
488  ##########################
489  mode = modeEnum.tofill
490  objName = colonWords [0]
491  tupleName = colonWords [1]
492  tofillName = colonWords [2]
493  ntupleDict = GenObject._ntupleDict.\
494  setdefault (tupleName, {})
495  ntupleDict[objName] = tofillName
496  for word in words:
497  # label
498  labelMatch = GenObject._labelRE.search (word)
499  if labelMatch:
500  label = tuple( GenObject._commaRE.\
501  split( labelMatch.group (1) ) )
502  ntupleDict.setdefault ('_label', {}).\
503  setdefault (tofillName,
504  label)
505  continue
506  # shortcut
507  shortcutMatch = GenObject._shortcutRE.search (word)
508  if shortcutMatch:
509  shortcutFill = \
510  GenObject.\
511  parseVariableTofill ( shortcutMatch.\
512  group(1) )
513  ntupleDict.setdefault ('_shortcut', {}).\
514  setdefault (tofillName,
515  shortcutFill)
516  continue
517  # type/handle
518  typeMatch = GenObject._typeRE.search (word)
519  if typeMatch:
520  handleString = \
521  GenObject.\
522  _fixLostGreaterThans (typeMatch.group(1))
523  handle = Handle( handleString )
524  ntupleDict.setdefault ('_handle', {}).\
525  setdefault (tofillName,
526  handle)
527  continue
528  # alias
529  aliasMatch = GenObject._aliasRE.search (word)
530  if aliasMatch:
531  ntupleDict.setdefault ('_alias', {}).\
532  setdefault (tofillName,
533  aliasMatch.\
534  group(1))
535  continue
536  # is this a lost '<'
537  if word == '>':
538  continue
539  # If we're still here, then we didn't have a valid
540  # option. Complain vociferously
541  print("I don't understand '%s' in section '%s' : %s" \
542  % (word, section, mode))
543  raise RuntimeError("Config file parser error '%s'(%d)" \
544  % (fullLine, lineNum))
545  ##############
546  ## Variable ##
547  ##############
548  else:
549  # a variable
550  if modeEnum.none == mode:
551  # Poorly formatted 'section' tag
552  print("I don't understand line '%s'." % fullLine)
553  raise RuntimeError("Config file parser error '%s'(%d)" \
554  % (fullLine, lineNum))
555  colonWords = GenObject._colonRE.split (line, 1)
556  if len (colonWords) < 2:
557  # Poorly formatted 'section' tag
558  print("I don't understand line '%s'." % fullLine)
559  raise RuntimeError("Config file parser error '%s'(%d)" \
560  % (fullLine, lineNum))
561  varName = colonWords[0]
562  option = colonWords[1]
563  if option:
564  pieces = GenObject._spacesRE.split (option)
565  else:
566  pieces = []
567  if modeEnum.define == mode:
568  #########################
569  ## Variable Definition ##
570  #########################
571  # is this a variable or an option?
572  if varName.startswith("-"):
573  # this is an option
574  if "-equiv" == varName.lower():
575  for part in pieces:
576  halves = part.split (",")
577  if 2 != len (halves):
578  print("Problem with -equiv '%s' in '%s'" % \
579  (part, section))
580  raise RuntimeError("Config file parser error '%s'(%d)" \
581  % (fullLine, lineNum))
582  if halves[1]:
583  halves[1] = float (halves[1])
584  if not halves[1] >= 0:
585  print("Problem with -equiv ",\
586  "'%s' in '%s'" % \
587  (part, section))
588  raise RuntimeError("Config file parser error '%s'(%d)" \
589  % (fullLine, lineNum))
590  GenObject.setEquivExpression (section,
591  halves[0],
592  halves[1])
593  continue
594  # If we're here, then this is a variable
595  optionsDict = {}
596  for word in pieces:
597  typeMatch = GenObject._typeRE.search (word)
598  if typeMatch and \
599  GenObject.types.isValidKey (typeMatch.group(1)):
600  varType = typeMatch.group(1).lower()
601  optionsDict['varType'] = GenObject.types (varType)
602  continue
603  defaultMatch = GenObject._defaultRE.search (word)
604  if defaultMatch:
605  optionsDict['default'] = defaultMatch.group(1)
606  continue
607  precMatch = GenObject._precRE.search (word)
608  if precMatch:
609  optionsDict['prec'] = float (precMatch.group (1))
610  continue
611  formMatch = GenObject._formRE.search (word)
612  if formMatch:
613  form = GenObject._doublePercentRE.\
614  sub ('%', formMatch.group (1))
615  optionsDict['form'] = form
616  continue
617  # If we're still here, then we didn't have a valid
618  # option. Complain vociferously
619  print("I don't understand '%s' in section '%s'." \
620  % (word, option))
621  raise RuntimeError("Config file parser error '%s'(%d)" \
622  % (fullLine, lineNum))
623  GenObject.addObjectVariable (objName, varName, \
624  **optionsDict)
625  else: # if modeEnum.define != mode
626  ############################
627  ## Variable 'tofill' Info ##
628  ############################
629  if len (pieces) < 1:
630  continue
631  fillname, pieces = pieces[0], pieces[1:]
632  # I don't yet have any options available here, but
633  # I'm keeping the code here for when I add them.
634  optionsDict = {}
635  for word in pieces:
636  # If we're still here, then we didn't have a valid
637  # option. Complain vociferously
638  print("I don't understand '%s' in section '%s'." \
639  % (word, option))
640  raise RuntimeError("Config file parser error '%s'(%d)" \
641  % (fullLine, lineNum))
642  tofillDict = GenObject._tofillDict.\
643  setdefault (tupleName, {}).\
644  setdefault (objName, {})
645  partsList = GenObject.parseVariableTofill (fillname)
646  tofillDict[varName] = [partsList, optionsDict]
647  # for line
648  for objName in GenObject._objsDict:
649  # if this isn't a singleton, add 'index' as a variable
650  if not GenObject.isSingleton (objName):
651  GenObject.addObjectVariable (objName, 'index',
652  varType = GenObject.types.int,
653  form = '%3d')
654 
655 
656  @staticmethod
657  def changeVariable (tupleName, objName, varName, fillname):
658  """Updates the definition used to go from a Root object to a
659  GenObject. 'tupleName' and 'objName' must already be defined."""
660  parts = GenObject._dotRE.split (fillname)
661  partsList = []
662  for part in parts:
663  parenMatch = GenObject._parenRE.search (part)
664  mode = GenObject._objFunc.obj
665  parens = []
666  if parenMatch:
667  part = parenMatch.group (1)
668  mode = GenObject._objFunc.func
669  parens = \
670  GenObject._convertStringToParameters \
671  (parenMatch.group (2))
672  partsList.append( (part, mode, parens) )
673  GenObject._tofillDict[tupleName][objName][varName] = [partsList, {}]
674 
675 
676 
677  @staticmethod
678  def evaluateFunction (obj, partsList, debug=False):
679  """Evaluates function described in partsList on obj"""
680  for part in partsList:
681  if debug: warn (part, spaces=15)
682  obj = getattr (obj, part[0])
683  if debug: warn (obj, spaces=15)
684  # if this is a function instead of a data member, make
685  # sure you call it with its arguments:
686  if GenObject._objFunc.func == part[1]:
687  # Arguments are stored as a list in part[2]
688  obj = obj (*part[2])
689  if debug: warn (obj, spaces=18)
690  return obj
691 
692 
693  @staticmethod
694  def _genObjectClone (objName, tupleName, obj, index = -1):
695  """Creates a GenObject copy of Root object"""
696  debug = GenObject._kitchenSinkDict.get ('debug', False)
697  if objName == 'runevent':
698  debug = False
699  tofillObjDict = GenObject._tofillDict.get(tupleName, {})\
700  .get(objName, {})
701  genObj = GenObject (objName)
702  origObj = obj
703  if debug: warn (objName, spaces = 9)
704  for genVar, ntDict in six.iteritems(tofillObjDict):
705  if debug: warn (genVar, spaces = 12)
706  # lets work our way down the list
707  partsList = ntDict[0]
708  # start off with the original object
709  obj = GenObject.evaluateFunction (origObj, partsList, debug)
710  if debug: warn (obj, spaces=12)
711  setattr (genObj, genVar, obj)
712  # Do I need to store the index of this object?
713  if index >= 0:
714  setattr (genObj, 'index', index)
715  return genObj
716 
717 
718  @staticmethod
719  def _rootObjectCopy (goSource, rootTarget):
720  """Copies information from goSourse into Root Object"""
721  objName = goSource._objName
722  for varName in GenObject._objsDict [objName].keys():
723  # if the key starts with an '_', then it is not a
724  # variable, so don't treat it as one.
725  if varName.startswith ("_"):
726  continue
727  setattr( rootTarget, varName, goSource (varName) )
728 
729 
730  @staticmethod
731  def _rootObjectClone (obj):
732  """Creates the approprite type of Root object and copies the
733  information into it from the GO object."""
734  objName = obj._objName
735  classObj = GenObject._rootClassDict.get (objName)
736  if not classObj:
737  goName = GenObject.rootClassName (objName)
738  classObj = GenObject._rootClassDict[ goName ]
739  rootObj = classObj()
740  for varName in GenObject._objsDict [objName].keys():
741  setattr( rootObj, varName, obj (varName) )
742  return rootObj
743 
744 
745  @staticmethod
746  def _rootDiffObject (obj1, obj2, rootObj = 0):
747  """Given to GOs, it will create and fill the corresponding
748  root diff object"""
749  objName = obj1._objName
750  # if we don't already have a root object, create one
751  if not rootObj:
752  diffName = GenObject.rootDiffClassName( objName )
753  rootObj = GenObject._rootClassDict[diffName]()
754  for varName in GenObject._objsDict [objName].keys():
755  if varName.startswith ("_"): continue
756  goType = GenObject._objsDict[objName][varName]['varType']
757  if not goType in GenObject._basicSet:
758  # not yet
759  continue
760  setattr( rootObj, varName, obj1 (varName) )
761  if goType == GenObject.types.string:
762  # string
763  otherName = 'other_' + varName
764  if obj1 (varName) != obj2 (varName):
765  # don't agree
766  setattr( rootObj, otherName, obj2 (varName) )
767  else:
768  # agree
769  setattr( rootObj, otherName, '' )
770  else:
771  # float, long, or int
772  deltaName = 'delta_' + varName
773  setattr( rootObj, deltaName,
774  obj2 (varName) - obj1 (varName) )
775  return rootObj
776 
777 
778  @staticmethod
779  def setupOutputTree (outputFile, treeName, treeDescription = "",
780  otherNtupleName = ""):
781  """Opens the output file, loads all of the necessary shared
782  object libraries, and returns the output file and tree. If
783  'otherNtupleName' is given, it will check and make sure that
784  only objects that are defined in it are written out."""
785  rootfile = ROOT.TFile.Open (outputFile, "recreate")
786  tree = ROOT.TTree (treeName, treeDescription)
787  GenObject._loadGoRootLibrary()
788  for objName in sorted (GenObject._objsDict.keys()):
789  classname = GenObject.rootClassName (objName)
790  rootObj = \
791  GenObject._rootClassDict[objName] = \
792  getattr (ROOT, classname)
793  if GenObject.isSingleton (objName):
794  # singleton object
795  obj = GenObject._rootObjectDict[objName] = rootObj()
796  tree.Branch (objName, classname, obj)
797  else:
798  # vector of objects - PLEASE don't forget the '()' on
799  # the end of the declaration. Without this, you are
800  # defining a type, not instantiating an object.
801  vec = \
802  GenObject._rootObjectDict[objName] = \
803  ROOT.std.vector( rootObj )()
804  branchName = objName + "s"
805  vecName = "vector<%s>" % classname
806  tree.Branch( branchName, vecName, vec)
807  # end else if isSingleton
808  # end for objName
809  return rootfile, tree
810 
811 
812  @staticmethod
813  def setupDiffOutputTree (outputFile, diffName, missingName,
814  diffDescription = '', missingDescription = ''):
815  """Opens the diff output file, loads all of the necessary
816  shared object libraries, and returns the output file and tree.b"""
817  rootfile = ROOT.TFile.Open (outputFile, "recreate")
818  GenObject._loadGoRootLibrary()
819  # diff tree
820  diffTree = ROOT.TTree (diffName, diffDescription)
821  runEventObject = getattr (ROOT, 'go_runevent')()
822  diffTree.Branch ('runevent', 'go_runevent', runEventObject)
823  GenObject._rootClassDict['runevent'] = runEventObject
824  for objName in sorted (GenObject._objsDict.keys()):
825  if objName == 'runevent': continue
826  classname = GenObject.rootClassName (objName)
827  GenObject._rootClassDict[classname] = getattr (ROOT, classname)
828  contName = GenObject.rootDiffContClassName (objName)
829  diffName = GenObject.rootDiffClassName (objName)
830  rootObj = GenObject._rootClassDict[contName] = \
831  getattr (ROOT, contName)
832  GenObject._rootClassDict[diffName] = getattr (ROOT, diffName)
833  obj = GenObject._rootObjectDict[objName] = rootObj()
834  diffTree.Branch (objName, contName, obj)
835  # missing tree
836  missingTree = ROOT.TTree (missingName, missingDescription)
837  rootRunEventClass = getattr (ROOT, 'go_runevent')
838  firstOnly = GenObject._rootClassDict['firstOnly'] = \
839  ROOT.std.vector( rootRunEventClass ) ()
840  secondOnly = GenObject._rootClassDict['secondOnly'] = \
841  ROOT.std.vector( rootRunEventClass ) ()
842  missingTree.Branch ('firstOnly', 'vector<go_runevent>', firstOnly)
843  missingTree.Branch ('secondOnly', 'vector<go_runevent>', secondOnly)
844  return rootfile, diffTree, missingTree
845 
846 
847  @staticmethod
848  def _fillRootObjects (event):
849  """Fills root objects from GenObject 'event'"""
850  for objName, obj in sorted (six.iteritems(event)):
851  if GenObject.isSingleton (objName):
852  # Just one
853  GenObject._rootObjectCopy (obj,
854  GenObject._rootObjectDict[objName])
855  else:
856  # a vector
857  vec = GenObject._rootObjectDict[objName]
858  vec.clear()
859  for goObj in obj:
860  vec.push_back( GenObject._rootObjectClone (goObj) )
861 
862 
863  @staticmethod
864  def _fillRootDiffs (event1, event2):
865  """Fills root diff containers from two GenObject 'event's"""
866 
867 
868 
869  @staticmethod
870  def isSingleton (objName):
871  """Returns true if object is a singleton"""
872  return GenObject._objsDict[objName].get('_singleton')
873 
874 
875  @staticmethod
876  def loadEventFromTree (eventTree, eventIndex,
877  onlyRunEvent = False):
878  """Loads event information from Root file (as interfaced by
879  'cmstools.EventTree' or 'ROOT.TChain'). Returns a dictionary
880  'event' containing lists of objects or singleton object. If
881  'onlyRunEvent' is et to True, then only run and event number
882  is read in from the tree."""
883  debug = GenObject._kitchenSinkDict.get ('debug', False)
884  tupleName = GenObject._kitchenSinkDict[eventTree]['tupleName']
885  event = {}
886  # is this a cint tree
887  isChain = eventTree.__class__.__name__ == 'TChain'
888  if isChain:
889  # This means that 'eventTree' is a ROOT.TChain
890  eventTree.GetEntry (eventIndex)
891  else:
892  # This means that 'eventTree' is a FWLite Events
893  eventTree.to(eventIndex)
894  tofillDict = GenObject._tofillDict.get (tupleName)
895  ntupleDict = GenObject._ntupleDict.get (tupleName)
896  if not tofillDict:
897  print("Don't know how to fill from '%s' ntuple." % tupleName)
898  return
899  eventBranchName = ntupleDict['runevent']
900  for objName in tofillDict:
901  branchName = ntupleDict[objName]
902  if onlyRunEvent and branchName != eventBranchName:
903  # not now
904  continue
905  # Have we been given 'tofill' info for this object?
906  if not branchName:
907  # guess not
908  continue
909  if isChain:
910  # Root TChain
911  objects = getattr (eventTree, branchName)
912  else:
913  # FWLite
914  shortcut = ntupleDict.get('_shortcut', {}).get(branchName)
915  if shortcut:
916  objects = GenObject.evaluateFunction (eventTree, shortcut)
917  else:
918  eventTree.toBegin()
919  handle = ntupleDict.get('_handle', {}).get(branchName)
920  label = ntupleDict.get('_label' , {}).get(branchName)
921  if not handle or not label:
922  raise RuntimeError("Missing handle or label for '%s'"\
923  % branchName)
924  if not eventTree.getByLabel (label, handle):
925  raise RuntimeError("not able to get %s for %s" \
926  % (label, branchName))
927  objects = handle.product()
928  # is this a singleton?
929  if GenObject.isSingleton (objName):
930  event[objName] = GenObject.\
931  _genObjectClone (objName,
932  tupleName,
933  objects)
934  continue
935  # if we're here then we have a vector of items
936  if debug: warn (objName, spaces = 3)
937  event[objName] = []
938  for index, obj in enumerate (objects):
939  event[objName].append( GenObject.\
940  _genObjectClone (objName,
941  tupleName,
942  obj,
943  index) )
944  del objects
945  # end for obj
946  ## if not isChain:
947  ## del rootEvent
948  # end for objName
949  return event
950 
951 
952  @staticmethod
953  def printEvent (event):
954  """Prints out event dictionary. Mostly for debugging"""
955  # Print out all singletons first
956  for objName, obj in sorted (six.iteritems(event)):
957  #obj = event[objName]
958  # is this a singleton?
959  if GenObject.isSingleton (objName):
960  print("%s: %s" % (objName, obj))
961  # Now print out all vectors
962  for objName, obj in sorted (six.iteritems(event)):
963  #obj = event[objName]
964  # is this a singleton?
965  if not GenObject.isSingleton (objName):
966  # o.k. obj is a vector
967  print("%s:" % objName)
968  for single in obj:
969  print(" ", single)
970  print()
971 
972 
973  @staticmethod
974  def setAliases (eventTree, tupleName):
975  """runs SetAlias on all saved aliases"""
976  aliases = GenObject._ntupleDict[tupleName].get('_alias', {})
977  for name, alias in six.iteritems(aliases):
978  eventTree.SetAlias (name, alias)
979 
980 
981  @staticmethod
982  def changeAlias (tupleName, name, alias):
983  """Updates an alias for an object for a given tuple"""
984  aliasDict = GenObject._ntupleDict[tupleName]['_alias']
985  if name not in aliasDict:
986  raise RuntimeError("unknown name '%s' in tuple '%s'" % \
987  (name, tupleName))
988  aliasDict[name] = alias
989 
990 
991  @staticmethod
992  def changeLabel (tupleName, objectName, label):
993  """Updates an label for an object for a given tuple"""
994  labelDict = GenObject._ntupleDict[tupleName]['_label']
995  if objectName not in labelDict:
996  raise RuntimeError("unknown name '%s' in tuple '%s'" % \
997  (objectName, tupleName))
998  label = tuple( GenObject._commaRE.split( label ) )
999  labelDict[objectName] = label
1000 
1001 
1002  @staticmethod
1003  def prepareTuple (tupleName, files, numEventsWanted = 0):
1004  """Given the tuple name and list of files, returns either a
1005  TChain or EventTree, and number of entries"""
1006  if "GenObject" == tupleName:
1007  GenObject.prepareToLoadGenObject()
1008  if not isinstance (files, list):
1009  # If this isn't a list, make it one
1010  files = [files]
1011  ntupleDict = GenObject._ntupleDict[tupleName]
1012  treeName = ntupleDict["_tree"]
1013  if ntupleDict.get('_useChain'):
1014  chain = ROOT.TChain (treeName)
1015  for filename in files:
1016  chain.AddFile (filename)
1017  numEntries = chain.GetEntries()
1018  # Are we using a chain or EventTree here?
1019  else:
1020  chain = Events (files, forceEvent=True)
1021  numEntries = chain.size()
1022  chainDict = GenObject._kitchenSinkDict.setdefault (chain, {})
1023  if numEventsWanted and numEventsWanted < numEntries:
1024  numEntries = numEventsWanted
1025  chainDict['numEntries'] = numEntries
1026  chainDict['tupleName' ] = tupleName
1027  return chain
1028 
1029 
1030  @staticmethod
1031  def getRunEventEntryDict (chain, tupleName, numEntries):
1032  """Returns a dictionary of run, event tuples to entryIndicies"""
1033  reeDict = {}
1034  for entryIndex in range (numEntries):
1035  event = GenObject.loadEventFromTree (chain,
1036  entryIndex,
1037  onlyRunEvent = True)
1038  runevent = event['runevent']
1039  reeDict[ GenObject._re2key (runevent) ] = entryIndex
1040  #reeDict[ "one two three" ] = entryIndex
1041  del event
1042  return reeDict
1043 
1044 
1045  @staticmethod
1046  def _re2key (runevent):
1047  """Given a GO 'runevent' object, returns a sortable key"""
1048  # if we don't know how to make this object yet, let's figure
1049  # it out
1050  if not GenObject._runEventListDone:
1051  GenObject._runEventListDone = True
1052  ignoreSet = set( ['run', 'event'] )
1053  for varName in sorted (runevent.__dict__.keys()):
1054  if varName.startswith ('_') or varName in ignoreSet:
1055  continue
1056  form = runevent.getVariableProperty (varName, "form")
1057  if not form:
1058  form = '%s'
1059  GenObject._runEventList.append ((varName, form))
1060  key = 'run:%d event:%d' % (runevent.run, runevent.event)
1061  for items in GenObject._runEventList:
1062  varName = items[0]
1063  form = ' %s:%s' % (varName, items[1])
1064  key += form % runevent.getVariableProperty (varName)
1065  return key
1066 
1067 
1068  @staticmethod
1069  def _key2re (key, runevent=None):
1070  """Given a key, returns a GO 'runevent' object"""
1071  if not runevent:
1072  runevent = GenObject ('runevent')
1073  words = GenObject._spacesRE.split (key)
1074  for word in words:
1075  match = GenObject._singleColonRE.search (word)
1076  if match:
1077  # for now, I'm assuming everything in the runevent
1078  # tuple is an integer. If this isn't the case, I'll
1079  # have to come back and be more clever here.
1080  runevent.__setattr__ (match.group(1), int( match.group(2) ))
1081  return runevent
1082 
1083 
1084  @staticmethod
1085  def compareRunEventDicts (firstDict, secondDict):
1086  """Compares the keys of the two dicts and returns three sets:
1087  the overlap, first but not second, and second but not first."""
1088  overlap = set()
1089  firstOnly = set()
1090  secondOnly = set()
1091  # loop over the keys of the first dict and compare to second dict
1092  for key in firstDict.keys():
1093  if key in secondDict:
1094  overlap.add (key)
1095  else:
1096  firstOnly.add (key)
1097  # now loop over keys of second dict and only check for missing
1098  # entries in first dict
1099  for key in secondDict.keys():
1100  if key not in firstDict:
1101  secondOnly.add (key)
1102  # All done
1103  return overlap, firstOnly, secondOnly
1104 
1105 
1106  @staticmethod
1107  def pairEquivalentObjects (vec1, vec2):
1108  """Finds the equivalent objects in the two vectors"""
1109  len1, len2 = len (vec1), len (vec2)
1110  debug = GenObject._kitchenSinkDict.get ('debug', False)
1111  if not len1 or not len2:
1112  # Nothing to see here folks. Keep moving.
1113  if len1:
1114  noMatch1Set = set( range(len1) )
1115  else:
1116  noMatch1Set = set ()
1117  if len2:
1118  noMatch2Set = set( range(len2) )
1119  else:
1120  noMatch2Set = set ()
1121  if debug: warn ("Nothing found", sapces=6)
1122  return set(), noMatch1Set, noMatch2Set
1123  objName = vec1[0]._objName
1124  equivList = GenObject._equivDict[objName]
1125  firstDict = {}
1126  secondDict = {}
1127  # let's see if we're only using 'index' and nothing else
1128  if GenObject._kitchenSinkDict.get ('strictPairing') or \
1129  equivList == [('index', 0)]:
1130  # we're only matching on index, nothing else matters
1131  matchedSet = set (zip ( list(range( min (len1, len2))),
1132  list(range( min (len1, len2))) ) )
1133  if len1 > len2:
1134  # since main pairing goes from 0..len2-1, we now want
1135  # to go from len2..len1 inclusive
1136  noMatch1Set = set (range(len2, len1 + 1))
1137  else:
1138  noMatch1Set = set()
1139  if len2 > len1:
1140  # same logic as above
1141  noMatch2Set = set (range(len1, len2 + 1))
1142  else:
1143  noMatch2Set = set()
1144  return matchedSet, noMatch1Set, noMatch2Set
1145  ## # If we're still here, that means that we aren't matching on
1146  ## # just index. Instead of jumping to O(N^2), let's assume that
1147  ## # both branches have everything in order and try to pair like
1148  ## # that. Anything not paired will be checked in a third pass.
1149  ## unpairedFirst = []
1150  ## unpairedSecond = []
1151  ## for index in xrange( min (len1, len2) ):
1152  ## obj1 = vec1[index1]
1153  ## total = 0.
1154  ## obj2 = vec2[index2]
1155  ## ok = True
1156 
1157  # First, look for vec2 objects that are equivalent to a
1158  # given vec1 object.
1159  for index1 in range (len1):
1160  objList = []
1161  obj1 = vec1[index1]
1162  for index2 in range (len2):
1163  total = 0.
1164  obj2 = vec2[index2]
1165  ok = True
1166  for equiv in equivList:
1167  var, precision = equiv[0], equiv[1]
1168  val1 = obj1 (var)
1169  val2 = obj2 (var)
1170  # Do we check equality or a precision
1171  if precision:
1172  value = abs (val1 - val2) / precision
1173  if value >= 1.:
1174  ok = False
1175  break
1176  total += value ** 2
1177  elif val1 != val2:
1178  ok = False
1179  break
1180  if ok:
1181  objList.append( (total, index2) )
1182  objList.sort()
1183  firstDict[index1] = objList
1184  # Now do the same thing, but this time look for vec1 objects
1185  # that are equivalent to a given vec2 object
1186  for index2 in range (len2):
1187  objList = []
1188  obj2 = vec2[index2]
1189  for index1 in range (len1):
1190  total = 0.
1191  obj1 = vec1[index1]
1192  ok = True
1193  for equiv in equivList:
1194  var, precision = equiv[0], equiv[1]
1195  val2 = obj2 (var)
1196  val1 = obj1 (var)
1197  # Do we check equality or a precision
1198  if precision:
1199  value = abs (val2 - val1) / precision
1200  if value > 1.:
1201  ok = False
1202  break
1203  total += value ** 2
1204  elif val2 != val1:
1205  ok = False
1206  break
1207  if ok:
1208  objList.append( (total, index1) )
1209  objList.sort()
1210  secondDict[index2] = objList
1211  # O.k. Now that we have the candidate matches, lets see who is
1212  # really matched.
1213  matchedSet = set()
1214  noMatch1Set = set()
1215  firstDictKeys = sorted (firstDict.keys())
1216  for index1 in firstDictKeys:
1217  list1 = firstDict[index1]
1218  # do I have a match?
1219  if not len (list1):
1220  # no match
1221  noMatch1Set.add (index1)
1222  continue
1223  # we've got at least one match
1224  best1 = list1[0]
1225  index2 = best1[1]
1226  # Does this one match me?
1227  list2 = secondDict.get (index2, [])
1228  if len(list2) and list2[0][1] == index1:
1229  matchedSet.add( (index1, index2) )
1230  # get rid of the 2nd key hash
1231  del firstDict[index1]
1232  del secondDict[index2]
1233  else:
1234  # no match
1235  noMatch1Set.add (index1)
1236  noMatch2Set = set( secondDict.keys() )
1237  return matchedSet, noMatch1Set, noMatch2Set
1238 
1239 
1240  @staticmethod
1241  def compareTwoItems (item1, item2):
1242  """Compares all of the variables making sure they are the same
1243  on the two objects."""
1244  objName = item1._objName
1245  problems = {}
1246  relative = GenObject._kitchenSinkDict.get ('relative', False)
1247  for varName in GenObject._objsDict[objName].keys():
1248  prec = item1.getVariableProperty (varName, 'prec')
1249  if prec:
1250  # we want to check within a precision
1251  if relative:
1252  val1 = item1(varName)
1253  val2 = item2(varName)
1254  numerator = 2 * abs (val1 - val2)
1255  denominator = abs(val1) + abs(val2)
1256  if not denominator:
1257  # both are exactly zero, so there's no
1258  # disagreement here.
1259  continue
1260  value = numerator / denominator
1261  if value > prec:
1262  # we've got a problem
1263  problems[varName] = value
1264  else:
1265  value = abs( item1(varName) - item2(varName) )
1266  if value > prec:
1267  # we've got a problem
1268  problems[varName] = value
1269  else:
1270  # we want to check equality
1271  if item1(varName) != item2(varName):
1272  # we have a problem. sort the values
1273  val1, val2 = item1(varName), item2(varName)
1274  if val1 > val2:
1275  val1, val2 = val2, val1
1276  problems[varName] = "%s != %s" % (val1, val2)
1277  # end for
1278  return problems
1279 
1280 
1281  @staticmethod
1282  def blurEvent (event, value, where = ""):
1283  """For debugging purposes only. Will deliberately change
1284  values of first tree to verify that script is correctly
1285  finding problems."""
1286  for objName in sorted (event.keys()):
1287  if "runevent" == objName:
1288  # runevent is a special case. We don't compare these
1289  continue
1290  if GenObject.isSingleton (objName):
1291  # I'll add this in later. For now, just skip it
1292  continue
1293  count = 0
1294  for obj in event[objName]:
1295  count += 1
1296  for varName in GenObject._objsDict[objName].keys():
1297  if isinstance (obj.__dict__[varName], str):
1298  # don't bother
1299  continue
1300  randNumber = random.random()
1301  #print "rN", randNumber
1302  if randNumber < GenObject._kitchenSinkDict['blurRate']:
1303  print(" %s: changing '%s' of '%s:%d'" \
1304  % (where, varName, obj._objName, count))
1305  ## print "objdict", obj.__dict__.get(varName), ':',\
1306  ## value
1307  obj.__dict__[varName] += value
1308 
1309 
1310  @staticmethod
1311  def compareTwoTrees (chain1, chain2, **kwargs):
1312  """Given all of the necessary information, this routine will
1313  go through and compare two trees making sure they are
1314  'identical' within requested precision. If 'diffOutputName'
1315  is passed in, a root file with a diffTree and missingTree will
1316  be produced."""
1317  print("Comparing Two Trees")
1318  diffOutputName = kwargs.get ('diffOutputName')
1319  tupleName1 = GenObject._kitchenSinkDict[chain1]['tupleName']
1320  numEntries1 = GenObject._kitchenSinkDict[chain1]['numEntries']
1321  tupleName2 = GenObject._kitchenSinkDict[chain2]['tupleName']
1322  numEntries2 = GenObject._kitchenSinkDict[chain2]['numEntries']
1323  debug = GenObject._kitchenSinkDict.get ('debug', False)
1324  ree1 = GenObject.getRunEventEntryDict (chain1, tupleName1, numEntries1)
1325  ree2 = GenObject.getRunEventEntryDict (chain2, tupleName2, numEntries2)
1326  overlap, firstOnly, secondOnly = \
1327  GenObject.compareRunEventDicts (ree1, ree2)
1328  if diffOutputName:
1329  rootfile, diffTree, missingTree = \
1330  GenObject.setupDiffOutputTree (diffOutputName,
1331  'diffTree',
1332  'missingTree')
1333  if firstOnly:
1334  vec = GenObject._rootClassDict['firstOnly']
1335  for key in firstOnly:
1336  runevent = GenObject._key2re (key)
1337  vec.push_back( GenObject._rootObjectClone( runevent ) )
1338  if secondOnly:
1339  vec = GenObject._rootClassDict['secondOnly']
1340  for key in secondOnly:
1341  runevent = GenObject._key2re (key)
1342  vec.push_back( GenObject._rootObjectClone( runevent ) )
1343  missingTree.Fill()
1344  resultsDict = {}
1345  if firstOnly:
1346  resultsDict.setdefault ('_runevent', {})['firstOnly'] = \
1347  len (firstOnly)
1348  if secondOnly:
1349  resultsDict.setdefault ('_runevent', {})['secondOnly'] = \
1350  len (secondOnly)
1351  resultsDict['eventsCompared'] = len (overlap)
1352  for reTuple in sorted(overlap):
1353  # if we are filling the diff tree, then save the run and
1354  # event information.
1355  if diffOutputName:
1356  GenObject._key2re (reTuple,
1357  GenObject._rootClassDict['runevent'])
1358  if debug: warn ('event1', blankLines = 3)
1359  event1 = GenObject.loadEventFromTree (chain1, ree1 [reTuple])
1360  if debug: warn ('event2', blankLines = 3)
1361  event2 = GenObject.loadEventFromTree (chain2, ree2 [reTuple])
1362  if GenObject._kitchenSinkDict.get('printEvent'):
1363  print("event1:")
1364  GenObject.printEvent (event1)
1365  print("event2:")
1366  GenObject.printEvent (event2)
1367  if GenObject._kitchenSinkDict.get('blur'):
1368  where = reTuple
1369  GenObject.blurEvent (event1,
1370  GenObject._kitchenSinkDict['blur'],
1371  where)
1372  for objName in sorted (event1.keys()):
1373  if "runevent" == objName:
1374  # runevent is a special case. We don't compare these
1375  continue
1376  if not GenObject._equivDict.get (objName):
1377  # we don't know how to compare these objects, so
1378  # skip them.
1379  continue
1380  if GenObject.isSingleton (objName):
1381  # I'll add this in later. For now, just skip it
1382  print("singleton")
1383  continue
1384  # Get ready to calculate root diff object if necessary
1385  rootObj = 0
1386  if diffOutputName:
1387  rootObj = GenObject._rootObjectDict[objName]
1388  rootObj.clear()
1389  vec1 = event1[objName]
1390  vec2 = event2[objName]
1391  matchedSet, noMatch1Set, noMatch2Set = \
1392  GenObject.pairEquivalentObjects (vec1, vec2)
1393  if noMatch1Set or noMatch2Set:
1394  ## print "No match 1", noMatch1Set
1395  ## print "No match 2", noMatch2Set
1396  count1 = len (noMatch1Set)
1397  count2 = len (noMatch2Set)
1398  key = (count1, count2)
1399  countDict = resultsDict.\
1400  setdefault (objName, {}).\
1401  setdefault ('_missing', {})
1402  if key in countDict:
1403  countDict[key] += 1
1404  else:
1405  countDict[key] = 1
1406  # should be calculating root diff objects
1407  if diffOutputName:
1408  # first set
1409  for index in sorted(list(noMatch1Set)):
1410  goObj = vec1 [index]
1411  rootObj.firstOnly.push_back ( GenObject.\
1412  _rootObjectClone \
1413  (goObj) )
1414  # second set
1415  for index in sorted(list(noMatch2Set)):
1416  goObj = vec2 [index]
1417  rootObj.secondOnly.push_back ( GenObject.\
1418  _rootObjectClone \
1419  (goObj) )
1420  # o.k. Now that we have them matched, let's compare
1421  # the proper items:
1422  for pair in sorted(list(matchedSet)):
1423  if diffOutputName:
1424  rootDiffObj = GenObject._rootDiffObject \
1425  ( vec1[ pair[1 - 1] ],
1426  vec2[ pair[2 - 1] ] )
1427  rootObj.diff.push_back ( rootDiffObj )
1428  problems = GenObject.\
1429  compareTwoItems (vec1[ pair[1 - 1] ],
1430  vec2[ pair[2 - 1] ])
1431  if problems.keys():
1432  # pprint.pprint (problems)
1433  for varName in problems.keys():
1434  countDict = resultsDict.\
1435  setdefault (objName, {}).\
1436  setdefault ('_var', {})
1437  if varName in countDict:
1438  countDict[varName] += 1
1439  else:
1440  countDict[varName] = 1
1441  key = 'count_%s' % objName
1442  if key not in resultsDict:
1443  resultsDict[key] = 0
1444  resultsDict[key] += len (matchedSet)
1445  # try cleaning up
1446  del vec1
1447  del vec2
1448  # end for objName
1449  if diffOutputName:
1450  diffTree.Fill()
1451  del event1
1452  del event2
1453  # end for overlap
1454  if diffOutputName:
1455  diffTree.Write()
1456  missingTree.Write()
1457  rootfile.Close()
1458  return resultsDict
1459 
1460 
1461  @staticmethod
1462  def saveTupleAs (chain, rootFile):
1463  """Saves a chain as a GO tree"""
1464  print("saveTupleAs")
1465  rootfile, tree = GenObject.setupOutputTree (rootFile, "goTree")
1466  numEntries = GenObject._kitchenSinkDict[chain]['numEntries']
1467  for entryIndex in range (numEntries):
1468  event = GenObject.loadEventFromTree (chain, entryIndex)
1469  if GenObject._kitchenSinkDict.get('blur'):
1470  where = "run %d event %d" % (event['runevent'].run,
1471  event['runevent'].event)
1472  if random.random() < GenObject._kitchenSinkDict.get('blur'):
1473  # dropping event
1474  print("Dropping", where)
1475  continue
1476  GenObject.blurEvent (event,
1477  GenObject._kitchenSinkDict['blur'],
1478  where)
1479  # check to see if we should drop the event
1480  if GenObject._kitchenSinkDict.get('printEvent'):
1481  GenObject.printEvent (event)
1482  GenObject._fillRootObjects (event)
1483  tree.Fill()
1484  tree.Write()
1485  rootfile.Close()
1486 
1487 
1488  @staticmethod
1489  def setGlobalFlag (key, value):
1490  """Sets a global flag in _kitchenSinkDict"""
1491  GenObject._kitchenSinkDict [key] = value
1492 
1493 
1494  @staticmethod
1495  def printTuple (chain):
1496  """Prints out all events to stdout"""
1497  numEntries = GenObject._kitchenSinkDict[chain]['numEntries']
1498  debug = GenObject._kitchenSinkDict.get ('debug', False)
1499  if debug: warn (numEntries)
1500  for entryIndex in range (numEntries):
1501  if debug: warn (entryIndex, spaces=3)
1502  event = GenObject.loadEventFromTree (chain, entryIndex)
1503  GenObject.printEvent (event)
1504  if debug: warn(spaces=3)
1505 
1506  @staticmethod
1508  """Convert comma-separated string into a python list of
1509  parameters. Currently only understands strings, floats, and
1510  integers."""
1511  retval = []
1512  words = GenObject._commaRE.split (string)
1513  for word in words:
1514  if not len (word):
1515  continue
1516  match = GenObject._singleQuoteRE.search (word)
1517  if match:
1518  retval.append (match.group (1))
1519  continue
1520  match = GenObject._doubleQuoteRE.search (word)
1521  if match:
1522  retval.append (match.group (1))
1523  continue
1524  try:
1525  val = int (word)
1526  retval.append (val)
1527  continue
1528  except:
1529  pass
1530  try:
1531  val = float (word)
1532  retval.append (val)
1533  continue
1534  except:
1535  pass
1536  # if we're still here, we've got a problem
1537  raise RuntimeError("Unknown parameter '%s'." % word)
1538  return retval
1539 
1540 
1541  ######################
1542  ## Member Functions ##
1543  ######################
1544 
1545 
1546  def __init__ (self, objName):
1547  """Class initializer"""
1548  if objName not in GenObject._objsDict:# or \
1549  #not GenObject._equivDict.has_key (objName) :
1550  # not good
1551  print("Error: GenObject does not know about object '%s'." % objName)
1552  raise RuntimeError("Failed to create GenObject object.")
1553  self._localObjsDict = GenObject._objsDict [objName]
1554  self._objName = objName;
1555  for key, varDict in six.iteritems(self._localObjsDict):
1556  # if the key starts with an '_', then it is not a
1557  # variable, so don't treat it as one.
1558  if key.startswith ("_"):
1559  continue
1560  self.setValue (key, varDict['default'])
1561 
1562 
1563  def setValue (self, name, value):
1564  """Wrapper for __setattr___"""
1565  self.__setattr__ (name, value)
1566 
1567 
1568  def getVariableProperty (self, var, key):
1569  """ Returns property assoicated with 'key' for variable 'var'
1570  of object of the same type as 'self'. Returns 'None' if 'var'
1571  or 'key' is not defined."""
1572  return GenObject._objsDict.get (self._objName,
1573  {}).get (var, {}). get (key, None)
1574 
1575 
1576  def __setattr__ (self, name, value):
1577  """Controls setting of values."""
1578  if name.startswith ("_"):
1579  # The internal version. Set anything you want.
1580  object.__setattr__ (self, name, value)
1581  else:
1582  # user version - Make sure this variable has already been
1583 
1584  # defined for this type:
1585  if name not in self._localObjsDict:
1586  # this variable has not been defined
1587  print("Warning: '%s' for class '%s' not setup. Skipping." % \
1588  (name, self._objName))
1589  return
1590  varType = self.getVariableProperty (name, 'varType')
1591  # if this is an int, make sure it stays an int
1592  if GenObject.types.int == varType:
1593  try:
1594  # This will work with integers, floats, and string
1595  # representations of integers.
1596  value = int (value)
1597  except:
1598  # This works with string representations of floats
1599  value = int( float( value ) )
1600  elif GenObject.types.long == varType:
1601  try:
1602  # This will work with integers, floats, and string
1603  # representations of integers.
1604  value = long (value)
1605  except:
1606  # This works with string representations of floats
1607  value = long( float( value ) )
1608  elif GenObject.types.float == varType:
1609  # Make sure it's a float
1610  value = float (value)
1611  elif GenObject.types.string == varType:
1612  # make sure it's a string
1613  value = str (value)
1614  # if we're still here, set it
1615  object.__setattr__ (self, name, value)
1616 
1617 
1618  def __call__ (self, key):
1619  """Makes object callable"""
1620  return object.__getattribute__ (self, key)
1621 
1622 
1623  def __str__ (self):
1624  """String representation"""
1625  retval = ""
1626  for varName, value in sorted (six.iteritems(self.__dict__)):
1627  if varName.startswith ('_'): continue
1628  form = self.getVariableProperty (varName, "form")
1629  if form:
1630  format = "%s:%s " % (varName, form)
1631  retval = retval + format % value
1632  else:
1633  retval = retval + "%s:%s " % (varName, value)
1634  return retval
def prepareTuple(tupleName, files, numEventsWanted=0)
Definition: GenObject.py:1003
def changeVariable(tupleName, objName, varName, fillname)
Definition: GenObject.py:657
def encodeNonAlphanumerics(line)
Definition: GenObject.py:129
def loadConfigFile(configFile)
Definition: GenObject.py:421
def blurEvent(event, value, where="")
Definition: GenObject.py:1282
def char2ascii(match)
Static Member Functions ##.
Definition: GenObject.py:121
def _finishClassHeader(className, datadec)
Definition: GenObject.py:236
def setEquivExpression(obj, variable, precision)
Definition: GenObject.py:167
def _loadGoRootLibrary()
Definition: GenObject.py:316
def evaluateFunction(obj, partsList, debug=False)
Definition: GenObject.py:678
def _rootObjectCopy(goSource, rootTarget)
Definition: GenObject.py:719
def _rootObjectClone(obj)
Definition: GenObject.py:731
def getVariableProperty(obj, var, key)
Definition: GenObject.py:159
def addObjectVariable(obj, var, optionsDict)
Definition: GenObject.py:140
S & print(S &os, JobReport::InputFile const &f)
Definition: JobReport.cc:66
def printEvent(event)
Definition: GenObject.py:953
def _fillRootObjects(event)
Definition: GenObject.py:848
def printTuple(chain)
Definition: GenObject.py:1495
def setGlobalFlag(key, value)
Definition: GenObject.py:1489
def _convertStringToParameters(string)
Definition: GenObject.py:1507
def setAliases(eventTree, tupleName)
Definition: GenObject.py:974
def warn(args, kwargs)
Definition: GenObject.py:32
def compareTwoItems(item1, item2)
Definition: GenObject.py:1241
def ascii2char(match)
Definition: GenObject.py:125
def setupDiffOutputTree(outputFile, diffName, missingName, diffDescription='', missingDescription='')
Definition: GenObject.py:814
def setQuietWarn(quiet=True)
Definition: GenObject.py:27
def setValue(self, name, value)
Definition: GenObject.py:1563
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
def _genObjectClone(objName, tupleName, obj, index=-1)
Definition: GenObject.py:694
def __setattr__(self, name, value)
Definition: GenObject.py:1576
def changeLabel(tupleName, objectName, label)
Definition: GenObject.py:992
def changeAlias(tupleName, name, alias)
Definition: GenObject.py:982
def saveTupleAs(chain, rootFile)
Definition: GenObject.py:1462
def prepareToLoadGenObject()
Definition: GenObject.py:384
def __call__(self, key)
Definition: GenObject.py:1618
def rootDiffClassName(objName)
Definition: GenObject.py:209
def setupOutputTree(outputFile, treeName, treeDescription="", otherNtupleName="")
Definition: GenObject.py:780
def compareRunEventDicts(firstDict, secondDict)
Definition: GenObject.py:1085
def _createCppClass(objName)
Definition: GenObject.py:245
def getRunEventEntryDict(chain, tupleName, numEntries)
Definition: GenObject.py:1031
def compareTwoTrees(chain1, chain2, kwargs)
Definition: GenObject.py:1311
def pairEquivalentObjects(vec1, vec2)
Definition: GenObject.py:1107
def loadEventFromTree(eventTree, eventIndex, onlyRunEvent=False)
Definition: GenObject.py:877
def rootDiffContClassName(objName)
Definition: GenObject.py:215
def _rootDiffObject(obj1, obj2, rootObj=0)
Definition: GenObject.py:746
def _key2re(key, runevent=None)
Definition: GenObject.py:1069
def rootClassName(objName)
Definition: GenObject.py:203
def __init__(self, objName)
Member Functions ##.
Definition: GenObject.py:1546
def isSingleton(objName)
Definition: GenObject.py:870
def _setupClassHeader(className, noColon=False)
Definition: GenObject.py:222
def _fixLostGreaterThans(handle)
Definition: GenObject.py:410
def parseVariableTofill(fillname)
Definition: GenObject.py:392
double split
Definition: MVATrainer.cc:139
def _re2key(runevent)
Definition: GenObject.py:1046
def _fillRootDiffs(event1, event2)
Definition: GenObject.py:864
T get(const Candidate &c)
Definition: component.h:55
def decodeNonAlphanumerics(line)
Definition: GenObject.py:134
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