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