CMS 3D CMS Logo

datamodel.py
Go to the documentation of this file.
1 from PhysicsTools.NanoAODTools.postprocessing.framework.treeReaderArrayTools import InputTree
2 import ROOT
3 import math
4 ROOT.PyConfig.IgnoreCommandLineOptions = True
5 
6 statusflags = { # GenPart_statusFlags, stored bitwise (powers of 2):
7  # https://github.com/cms-sw/cmssw/edit/master/PhysicsTools/NanoAOD/python/genparticles_cff.py
8  # https://cms-nanoaod-integration.web.cern.ch/integration/master-106X/mc106Xul18_doc.html#GenPart
9  'isPrompt': (1 << 0), 'fromHardProcess': (1 << 8),
10  'isDecayedLeptonHadron': (1 << 1), 'isHardProcessTauDecayProduct': (1 << 9),
11  'isTauDecayProduct': (1 << 2), 'isDirectHardProcessTauDecayProduct': (1 << 10),
12  'isPromptTauDecayProduct': (1 << 3), 'fromHardProcessBeforeFSR': (1 << 11),
13  'isDirectTauDecayProduct': (1 << 4), 'isFirstCopy': (1 << 12),
14  'isDirectPromptTauDecayProduct': (1 << 5), 'isLastCopy': (1 << 13),
15  'isDirectHadronDecayProduct': (1 << 6), 'isLastCopyBeforeFSR': (1 << 14),
16  'isHardProcess': (1 << 7),
17 }
18 
19 
20 class Event:
21  """Class that allows seeing an entry of a PyROOT TTree as an Event"""
22 
23  def __init__(self, tree, entry):
24  self._tree = tree
25  self._entry = entry
26  self._tree.gotoEntry(entry)
27 
28  def __getattr__(self, name):
29  if name in self.__dict__:
30  return self.__dict__[name]
31  return self._tree.readBranch(name)
32 
33  def __getitem__(self, attr):
34  return self.__getattr__(attr)
35 
36  def eval(self, expr):
37  """Evaluate an expression, as TTree::Draw would do.
38 
39  This is added for convenience, but it may perform poorly and the implementation is not bulletproof,
40  so it's better to rely on reading values, collections or objects directly
41  """
42  if not hasattr(self._tree, '_exprs'):
43  self._tree._exprs = {}
44  # remove useless warning about EvalInstance()
45  import warnings
46  warnings.filterwarnings(action='ignore', category=RuntimeWarning,
47  message='creating converter for unknown type "const char\\*\\*"$')
48  warnings.filterwarnings(action='ignore', category=RuntimeWarning,
49  message='creating converter for unknown type "const char\\*\\[\\]"$')
50  if expr not in self._tree._exprs:
51  formula = ROOT.TTreeFormula(expr, expr, self._tree)
52  if formula.IsInteger():
53  formula.go = formula.EvalInstance64
54  else:
55  formula.go = formula.EvalInstance
56  self._tree._exprs[expr] = formula
57  # force sync, to be safe
58  self._tree.GetEntry(self._entry)
59  self._tree.entry = self._entry
60  # self._tree._exprs[expr].SetQuickLoad(False)
61  else:
62  self._tree.gotoEntry(self._entry)
63  formula = self._tree._exprs[expr]
64  if "[" in expr: # unclear why this is needed, but otherwise for some arrays x[i] == 0 for all i > 0
65  formula.GetNdata()
66  return formula.go()
67 
68 
69 class Object:
70  """Class that allows seeing a set branches plus possibly an index as an Object"""
71 
72  def __init__(self, event, prefix, index=None):
73  self._event = event
74  self._prefix = prefix + "_"
75  self._index = index
76 
77  def __getattr__(self, name):
78  if name in self.__dict__:
79  return self.__dict__[name]
80  if name[:2] == "__" and name[-2:] == "__":
81  raise AttributeError
82  val = getattr(self._event, self._prefix + name)
83  if self._index != None:
84  val = val[self._index]
85  # convert char to integer number
86  val = ord(val) if type(val) == str else val
87  self.__dict__[name] = val # cache
88  return val
89 
90  def __getitem__(self, attr):
91  return self.__getattr__(attr)
92 
93  def p4(self, corr_pt=None):
94  """Create TLorentzVector for this particle."""
95  ret = ROOT.TLorentzVector()
96  if corr_pt == None:
97  ret.SetPtEtaPhiM(self.pt, self.eta, self.phi, self.mass)
98  else:
99  ret.SetPtEtaPhiM(corr_pt, self.eta, self.phi, self.mass)
100  return ret
101 
102  def DeltaR(self, other):
103  if isinstance(other, ROOT.TLorentzVector):
104  deta = abs(other.Eta() - self.eta)
105  dphi = abs(other.Phi() - self.phi)
106  else:
107  deta = abs(other.eta - self.eta)
108  dphi = abs(other.phi - self.phi)
109  while dphi > math.pi:
110  dphi = abs(dphi - 2 * math.pi)
111  return math.sqrt(dphi**2 + deta**2)
112 
113  def statusflag(self, flag):
114  """Find if bit for statusflag is set (for GenPart only)."""
115  return (self.statusFlags & statusflags[flag])==statusflags[flag]
116 
117  def subObj(self, prefix):
118  return Object(self._event, self._prefix + prefix)
119 
120  def __repr__(self):
121  return ("<%s[%s]>" % (self._prefix[:-1], self._index)) if self._index != None else ("<%s>" % self._prefix[:-1])
122 
123  def __str__(self):
124  return self.__repr__()
125 
126 
128  def __init__(self, event, prefix, lenVar=None):
129  self._event = event
130  self._prefix = prefix
131  if lenVar != None:
132  self._len = getattr(event, lenVar)
133  else:
134  self._len = getattr(event, "n" + prefix)
135  self._cache = {}
136 
137  def __getitem__(self, index):
138  if type(index) == int and index in self._cache:
139  return self._cache[index]
140  if index >= self._len:
141  raise IndexError("Invalid index %r (len is %r) at %s" % (index, self._len, self._prefix))
142  elif index < 0:
143  raise IndexError("Invalid index %r (negative) at %s" % (index, self._prefix))
144  ret = Object(self._event, self._prefix, index=index)
145  if type(index) == int:
146  self._cache[index] = ret
147  return ret
148 
149  def __len__(self):
150  return self._len
def __str__(self)
Definition: datamodel.py:123
def readBranch(tree, branchName)
def __getattr__(self, name)
Definition: datamodel.py:28
def __getitem__(self, index)
Definition: datamodel.py:137
def __getitem__(self, attr)
Definition: datamodel.py:90
def __getattr__(self, name)
Definition: datamodel.py:77
def p4(self, corr_pt=None)
Definition: datamodel.py:93
def subObj(self, prefix)
Definition: datamodel.py:117
def __getitem__(self, attr)
Definition: datamodel.py:33
def __init__(self, event, prefix, index=None)
Definition: datamodel.py:72
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
def __init__(self, tree, entry)
Definition: datamodel.py:23
def __init__(self, event, prefix, lenVar=None)
Definition: datamodel.py:128
def __repr__(self)
Definition: datamodel.py:120
def eval(self, expr)
Definition: datamodel.py:36
def statusflag(self, flag)
Definition: datamodel.py:113
def DeltaR(self, other)
Definition: datamodel.py:102