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