CMS 3D CMS Logo

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