CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
deltar.py
Go to the documentation of this file.
1 # Copyright (C) 2014 Colin Bernet
2 # https://github.com/cbernet/heppy/blob/master/LICENSE
3 
4 import math
5 import copy
6 
7 def deltaR2( e1, p1, e2=None, p2=None):
8  """Take either 4 arguments (eta,phi, eta,phi) or two objects that have 'eta', 'phi' methods)"""
9  if (e2 == None and p2 == None):
10  return deltaR2(e1.eta(),e1.phi(), p1.eta(), p1.phi())
11  de = e1 - e2
12  dp = deltaPhi(p1, p2)
13  return de*de + dp*dp
14 
15 
16 def deltaR( *args ):
17  return math.sqrt( deltaR2(*args) )
18 
19 
20 def deltaPhi( p1, p2):
21  '''Computes delta phi, handling periodic limit conditions.'''
22  res = p1 - p2
23  while res > math.pi:
24  res -= 2*math.pi
25  while res < -math.pi:
26  res += 2*math.pi
27  return res
28 
29 
30 def inConeCollection(pivot, particles, deltaRMax, deltaRMin=1e-5):
31  '''Returns the list of particles that are less than deltaRMax away from pivot.'''
32  dR2Max = deltaRMax ** 2
33  dR2Min = deltaRMin ** 2
34  results = []
35  for ptc in particles:
36  dR2 = deltaR2(pivot.eta(), pivot.phi(), ptc.eta(), ptc.phi())
37  if dR2Min < dR2 < dR2Max:
38  results.append(ptc)
39  return results
40 
41 def matchObjectCollection3 ( objects, matchCollection, deltaRMax = 0.3, filter = lambda x,y : True ):
42  '''Univoque association of an element from matchCollection to an element of objects.
43  Reco and Gen objects get the "matched" attribute, true is they are re part of a matched tulpe.
44  By default, the matching is true only if delta R is smaller than 0.3.
45  '''
46  #
47 
48  pairs = {}
49  if len(objects)==0:
50  return pairs
51  if len(matchCollection)==0:
52  return dict( zip(objects, [None]*len(objects)) )
53  # build all possible combinations
54 
55  objectCoords = [ (o.eta(),o.phi(),o) for o in objects ]
56  matchdCoords = [ (o.eta(),o.phi(),o) for o in matchCollection ]
57  allPairs = [(deltaR2 (oeta, ophi, meta, mphi), (object, match)) for (oeta,ophi,object) in objectCoords for (meta,mphi,match) in matchdCoords if abs(oeta-meta)<=deltaRMax and filter(object,match) ]
58  #allPairs = [(deltaR2 (object.eta(), object.phi(), match.eta(), match.phi()), (object, match)) for object in objects for match in matchCollection if filter(object,match) ]
59  allPairs.sort ()
60  #
61  # to flag already matched objects
62  # FIXME this variable remains appended to the object, I do not like it
63 
64  for object in objects:
65  object.matched = False
66  for match in matchCollection:
67  match.matched = False
68  #
69 
70  deltaR2Max = deltaRMax * deltaRMax
71  for dR2, (object, match) in allPairs:
72  if dR2 > deltaR2Max:
73  break
74  if dR2 < deltaR2Max and object.matched == False and match.matched == False:
75  object.matched = True
76  match.matched = True
77  pairs[object] = match
78  #
79 
80  for object in objects:
81  if object.matched == False:
82  pairs[object] = None
83  #
84 
85  return pairs
86  # by now, the matched attribute remains in the objects, for future usage
87  # one could remove it with delattr (object, attrname)
88 
89 
90 
91 
92 def cleanObjectCollection2( objects, masks, deltaRMin ):
93  '''Masks objects using a deltaR cut, another algorithm (same results).'''
94  if len(objects)==0:
95  return objects
96  deltaR2Min = deltaRMin*deltaRMin
97  cleanObjects = copy.copy( objects )
98  for mask in masks:
99  tooClose = []
100  for idx, object in enumerate(cleanObjects):
101  dR2 = deltaR2( object.eta(), object.phi(),
102  mask.eta(), mask.phi() )
103  if dR2 < deltaR2Min:
104  tooClose.append( idx )
105  nRemoved = 0
106  for idx in tooClose:
107  # yes, everytime an object is removed, the list of objects is updated
108  # so need to update the index accordingly.
109  # example: to remove : ele 1 and 2
110  # first, ele 1 is removed
111  # -> ele 2 is now at index 1
112  # one should again remove the element at index 1
113  idx -= nRemoved
114  del cleanObjects[idx]
115  nRemoved += 1
116  return cleanObjects
117 
118 
119 def cleanObjectCollection( objects, masks, deltaRMin ):
120  '''Masks objects using a deltaR cut.'''
121  if len(objects)==0 or len(masks)==0:
122  return objects, []
123  deltaR2Min = deltaRMin*deltaRMin
124  cleanObjects = []
125  dirtyObjects = []
126  for object in objects:
127  ok = True
128  for mask in masks:
129  dR2 = deltaR2( object.eta(), object.phi(),
130  mask.eta(), mask.phi() )
131  if dR2 < deltaR2Min:
132  ok = False
133  if ok:
134  cleanObjects.append( object )
135  else:
136  dirtyObjects.append( object )
137  return cleanObjects, dirtyObjects
138 
139 def bestMatch( object, matchCollection):
140  '''Return the best match to object in matchCollection, which is the closest object in delta R'''
141  deltaR2Min = float('+inf')
142  bm = None
143  for match in matchCollection:
144  dR2 = deltaR2( object.eta(), object.phi(),
145  match.eta(), match.phi() )
146  if dR2 < deltaR2Min:
147  deltaR2Min = dR2
148  bm = match
149  return bm, deltaR2Min
150 
151 
152 def matchObjectCollection( objects, matchCollection, deltaR2Max):
153  pairs = {}
154  if len(objects)==0:
155  return pairs
156  if len(matchCollection)==0:
157  return dict( zip(objects, [None]*len(objects)) )
158  for object in objects:
159  bm, dr2 = bestMatch( object, matchCollection )
160  if dr2<deltaR2Max:
161  pairs[object] = bm
162  else:
163  pairs[object] = None
164  return pairs
165 
166 
167 def matchObjectCollection2 ( objects, matchCollection, deltaRMax = 0.3 ):
168  '''Univoque association of an element from matchCollection to an element of objects.
169  Reco and Gen objects get the "matched" attribute, true is they are re part of a matched tulpe.
170  By default, the matching is true only if delta R is smaller than 0.3.
171  '''
172 
173  pairs = {}
174  if len(objects)==0:
175  return pairs
176  if len(matchCollection)==0:
177  return dict( zip(objects, [None]*len(objects)) )
178  # build all possible combinations
179  allPairs = [(deltaR2 (object.eta(), object.phi(), match.eta(), match.phi()), (object, match)) for object in objects for match in matchCollection]
180  allPairs.sort ()
181 
182  # to flag already matched objects
183  # FIXME this variable remains appended to the object, I do not like it
184  for object in objects:
185  object.matched = False
186  for match in matchCollection:
187  match.matched = False
188 
189  deltaR2Max = deltaRMax * deltaRMax
190  for dR2, (object, match) in allPairs:
191  if dR2 > deltaR2Max:
192  break
193  if dR2 < deltaR2Max and object.matched == False and match.matched == False:
194  object.matched = True
195  match.matched = True
196  pairs[object] = match
197 
198  for object in objects:
199  if object.matched == False:
200  pairs[object] = None
201 
202  return pairs
203  # by now, the matched attribute remains in the objects, for future usage
204  # one could remove it with delattr (object, attrname)
205 
206 
207 
208 if __name__ == '__main__':
209 
210  import sys
211  args = sys.argv[1:]
212  fargs = map( float, args )
213 
214  print 'dR2 = ', deltaR2( *fargs )
215  print 'dR = ', deltaR( *fargs )
216 
217 
218 
def bestMatch
Definition: deltar.py:139
def cleanObjectCollection
Definition: deltar.py:119
def deltaPhi
Definition: deltar.py:20
tuple zip
Definition: archive.py:476
def matchObjectCollection
Definition: deltar.py:152
def cleanObjectCollection2
Definition: deltar.py:92
def matchObjectCollection2
Definition: deltar.py:167
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
def inConeCollection
Definition: deltar.py:30
def deltaR2
Definition: deltar.py:7
def deltaR
Definition: deltar.py:16
def matchObjectCollection3
Definition: deltar.py:41