comparison python/storage.py @ 746:e7ff0f60fef8

merged new developments (indicator and trajectory clustering)
author Nicolas Saunier <nicolas.saunier@polymtl.ca>
date Thu, 10 Sep 2015 15:52:45 -0400
parents ed6ff2ec0aeb
children 6049e9b6902c
comparison
equal deleted inserted replaced
727:c6d4ea05a2d0 746:e7ff0f60fef8
31 cursor = connection.cursor() 31 cursor = connection.cursor()
32 for tableName in tableNames: 32 for tableName in tableNames:
33 cursor.execute('DROP TABLE IF EXISTS '+tableName) 33 cursor.execute('DROP TABLE IF EXISTS '+tableName)
34 except sqlite3.OperationalError as error: 34 except sqlite3.OperationalError as error:
35 printDBError(error) 35 printDBError(error)
36
37 def tableExists(filename, tableName):
38 'indicates if the table exists in the database'
39 try:
40 connection = sqlite3.connect(filename)
41 cursor = connection.cursor()
42 cursor.execute('SELECT COUNT(*) FROM SQLITE_MASTER WHERE type = \'table\' AND name = \''+tableName+'\'')
43 return cursor.fetchone()[0] == 1
44 except sqlite3.OperationalError as error:
45 printDBError(error)
36 46
37 def createIndex(connection, tableName, columnName, unique = False): 47 def createIndex(connection, tableName, columnName, unique = False):
38 '''Creates an index for the column in the table 48 '''Creates an index for the column in the table
39 I will make querying with a condition on this column faster''' 49 I will make querying with a condition on this column faster'''
40 try: 50 try:
107 cursor.execute(query,(trajectory_id,frame_number,position.x,position.y)) 117 cursor.execute(query,(trajectory_id,frame_number,position.x,position.y))
108 118
109 connection.commit() 119 connection.commit()
110 connection.close() 120 connection.close()
111 121
112 def writeFeaturesToSqlite(objects, outputFilename, trajectoryType, objectNumbers = -1):
113 '''write features trajectories maintain trajectory ID,velocities dataset '''
114 connection = sqlite3.connect(outputFilename)
115 cursor = connection.cursor()
116
117 cursor.execute("CREATE TABLE IF NOT EXISTS \"positions\"(trajectory_id INTEGER,frame_number INTEGER, x_coordinate REAL, y_coordinate REAL, PRIMARY KEY(trajectory_id, frame_number))")
118 cursor.execute("CREATE TABLE IF NOT EXISTS \"velocities\"(trajectory_id INTEGER,frame_number INTEGER, x_coordinate REAL, y_coordinate REAL, PRIMARY KEY(trajectory_id, frame_number))")
119
120 if trajectoryType == 'feature':
121 if type(objectNumbers) == int and objectNumbers == -1:
122 for trajectory in objects:
123 trajectory_id = trajectory.num
124 frame_number = trajectory.timeInterval.first
125 for position,velocity in zip(trajectory.getPositions(),trajectory.getVelocities()):
126 cursor.execute("insert into positions (trajectory_id, frame_number, x_coordinate, y_coordinate) values (?,?,?,?)",(trajectory_id,frame_number,position.x,position.y))
127 cursor.execute("insert into velocities (trajectory_id, frame_number, x_coordinate, y_coordinate) values (?,?,?,?)",(trajectory_id,frame_number,velocity.x,velocity.y))
128 frame_number += 1
129
130 connection.commit()
131 connection.close()
132
133 def writePrototypesToSqlite(prototypes,nMatching, outputFilename):
134 """ prototype dataset is a dictionary with keys== routes, values== prototypes Ids """
135 connection = sqlite3.connect(outputFilename)
136 cursor = connection.cursor()
137
138 cursor.execute("CREATE TABLE IF NOT EXISTS \"prototypes\"(prototype_id INTEGER,routeIDstart INTEGER,routeIDend INTEGER, nMatching INTEGER, PRIMARY KEY(prototype_id))")
139
140 for route in prototypes.keys():
141 if prototypes[route]!=[]:
142 for i in prototypes[route]:
143 cursor.execute("insert into prototypes (prototype_id, routeIDstart,routeIDend, nMatching) values (?,?,?,?)",(i,route[0],route[1],nMatching[route][i]))
144
145 connection.commit()
146 connection.close()
147
148 def loadPrototypesFromSqlite(filename):
149 """
150 This function loads the prototype file in the database
151 It returns a dictionary for prototypes for each route and nMatching
152 """
153 prototypes = {}
154 nMatching={}
155
156 connection = sqlite3.connect(filename)
157 cursor = connection.cursor()
158
159 try:
160 cursor.execute('SELECT * from prototypes order by prototype_id, routeIDstart,routeIDend, nMatching')
161 except sqlite3.OperationalError as error:
162 utils.printDBError(error)
163 return []
164
165 for row in cursor:
166 route=(row[1],row[2])
167 if route not in prototypes.keys():
168 prototypes[route]=[]
169 prototypes[route].append(row[0])
170 nMatching[row[0]]=row[3]
171
172 connection.close()
173 return prototypes,nMatching
174
175 def writeLabelsToSqlite(labels, outputFilename):
176 """ labels is a dictionary with keys: routes, values: prototypes Ids
177 """
178 connection = sqlite3.connect(outputFilename)
179 cursor = connection.cursor()
180
181 cursor.execute("CREATE TABLE IF NOT EXISTS \"labels\"(object_id INTEGER,routeIDstart INTEGER,routeIDend INTEGER, prototype_id INTEGER, PRIMARY KEY(object_id))")
182
183 for route in labels.keys():
184 if labels[route]!=[]:
185 for i in labels[route]:
186 for j in labels[route][i]:
187 cursor.execute("insert into labels (object_id, routeIDstart,routeIDend, prototype_id) values (?,?,?,?)",(j,route[0],route[1],i))
188
189 connection.commit()
190 connection.close()
191
192 def loadLabelsFromSqlite(filename):
193 labels = {}
194
195 connection = sqlite3.connect(filename)
196 cursor = connection.cursor()
197
198 try:
199 cursor.execute('SELECT * from labels order by object_id, routeIDstart,routeIDend, prototype_id')
200 except sqlite3.OperationalError as error:
201 utils.printDBError(error)
202 return []
203
204 for row in cursor:
205 route=(row[1],row[2])
206 p=row[3]
207 if route not in labels.keys():
208 labels[route]={}
209 if p not in labels[route].keys():
210 labels[route][p]=[]
211 labels[route][p].append(row[0])
212
213 connection.close()
214 return labels
215 def writeSpeedPrototypeToSqlite(prototypes,nmatching, outFilename):
216 """ to match the format of second layer prototypes"""
217 connection = sqlite3.connect(outFilename)
218 cursor = connection.cursor()
219
220 cursor.execute("CREATE TABLE IF NOT EXISTS \"speedprototypes\"(spdprototype_id INTEGER,prototype_id INTEGER,routeID_start INTEGER, routeID_end INTEGER, nMatching INTEGER, PRIMARY KEY(spdprototype_id))")
221
222 for route in prototypes.keys():
223 if prototypes[route]!={}:
224 for i in prototypes[route]:
225 if prototypes[route][i]!= []:
226 for j in prototypes[route][i]:
227 cursor.execute("insert into speedprototypes (spdprototype_id,prototype_id, routeID_start, routeID_end, nMatching) values (?,?,?,?,?)",(j,i,route[0],route[1],nmatching[j]))
228
229 connection.commit()
230 connection.close()
231
232 def loadSpeedPrototypeFromSqlite(filename):
233 """
234 This function loads the prototypes table in the database of name <filename>.
235 """
236 prototypes = {}
237 nMatching={}
238 connection = sqlite3.connect(filename)
239 cursor = connection.cursor()
240
241 try:
242 cursor.execute('SELECT * from speedprototypes order by spdprototype_id,prototype_id, routeID_start, routeID_end, nMatching')
243 except sqlite3.OperationalError as error:
244 utils.printDBError(error)
245 return []
246
247 for row in cursor:
248 route=(row[2],row[3])
249 if route not in prototypes.keys():
250 prototypes[route]={}
251 if row[1] not in prototypes[route].keys():
252 prototypes[route][row[1]]=[]
253 prototypes[route][row[1]].append(row[0])
254 nMatching[row[0]]=row[4]
255
256 connection.close()
257 return prototypes,nMatching
258
259
260 def writeRoutesToSqlite(Routes, outputFilename):
261 """ This function writes the activity path define by start and end IDs"""
262 connection = sqlite3.connect(outputFilename)
263 cursor = connection.cursor()
264
265 cursor.execute("CREATE TABLE IF NOT EXISTS \"routes\"(object_id INTEGER,routeIDstart INTEGER,routeIDend INTEGER, PRIMARY KEY(object_id))")
266
267 for route in Routes.keys():
268 if Routes[route]!=[]:
269 for i in Routes[route]:
270 cursor.execute("insert into routes (object_id, routeIDstart,routeIDend) values (?,?,?)",(i,route[0],route[1]))
271
272 connection.commit()
273 connection.close()
274
275 def loadRoutesFromSqlite(filename):
276 Routes = {}
277
278 connection = sqlite3.connect(filename)
279 cursor = connection.cursor()
280
281 try:
282 cursor.execute('SELECT * from routes order by object_id, routeIDstart,routeIDend')
283 except sqlite3.OperationalError as error:
284 utils.printDBError(error)
285 return []
286
287 for row in cursor:
288 route=(row[1],row[2])
289 if route not in Routes.keys():
290 Routes[route]=[]
291 Routes[route].append(row[0])
292
293 connection.close()
294 return Routes
295
296 def setRoutes(filename, objects):
297 connection = sqlite3.connect(filename)
298 cursor = connection.cursor()
299 for obj in objects:
300 cursor.execute('update objects set startRouteID = {} where object_id = {}'.format(obj.startRouteID, obj.getNum()))
301 cursor.execute('update objects set endRouteID = {} where object_id = {}'.format(obj.endRouteID, obj.getNum()))
302 connection.commit()
303 connection.close()
304
305 def setRoadUserTypes(filename, objects):
306 '''Saves the user types of the objects in the sqlite database stored in filename
307 The objects should exist in the objects table'''
308 connection = sqlite3.connect(filename)
309 cursor = connection.cursor()
310 for obj in objects:
311 cursor.execute('update objects set road_user_type = {} where object_id = {}'.format(obj.getUserType(), obj.getNum()))
312 connection.commit()
313 connection.close()
314 122
315 def loadPrototypeMatchIndexesFromSqlite(filename): 123 def loadPrototypeMatchIndexesFromSqlite(filename):
316 """ 124 """
317 This function loads the prototypes table in the database of name <filename>. 125 This function loads the prototypes table in the database of name <filename>.
318 It returns a list of tuples representing matching ids : [(prototype_id, matched_trajectory_id),...] 126 It returns a list of tuples representing matching ids : [(prototype_id, matched_trajectory_id),...]
475 objects = [] 283 objects = []
476 284
477 connection.close() 285 connection.close()
478 return objects 286 return objects
479 287
288 def savePrototypesToSqlite(filename, prototypes, trajectoryType = 'feature'):
289 'Work in progress, do not use'
290 connection = sqlite3.connect(filename)
291 cursor = connection.cursor()
292 try:
293 cursor.execute('CREATE TABLE IF NOT EXISTS prototypes (id INTEGER PRIMARY KEY, object_id INTEGER, trajectory_id INTEGER, nMatchings INTEGER, FOREIGN KEY(object_id) REFERENCES objects(id), FOREIGN KEY(trajectory_id) REFERENCES positions(trajectory_id))')
294 #for inter in interactions:
295 # saveInteraction(cursor, inter)
296 except sqlite3.OperationalError as error:
297 printDBError(error)
298 connection.commit()
299 connection.close()
300
301 def loadPrototypesFromSqlite(filename):
302 pass
303
480 def loadGroundTruthFromSqlite(filename, gtType = 'bb', gtNumbers = None): 304 def loadGroundTruthFromSqlite(filename, gtType = 'bb', gtNumbers = None):
481 'Loads bounding box annotations (ground truth) from an SQLite ' 305 'Loads bounding box annotations (ground truth) from an SQLite '
482 connection = sqlite3.connect(filename) 306 connection = sqlite3.connect(filename)
483 gt = [] 307 gt = []
484 308
627 except sqlite3.OperationalError as error: 451 except sqlite3.OperationalError as error:
628 printDBError(error) 452 printDBError(error)
629 return boundingBoxes 453 return boundingBoxes
630 connection.close() 454 connection.close()
631 return boundingBoxes 455 return boundingBoxes
456
457 #########################
458 # saving and loading for scene interpretation (Mohamed Gomaa Mohamed's PhD)
459 #########################
460
461 def writeFeaturesToSqlite(objects, outputFilename, trajectoryType, objectNumbers = -1):
462 '''write features trajectories maintain trajectory ID,velocities dataset '''
463 connection = sqlite3.connect(outputFilename)
464 cursor = connection.cursor()
465
466 cursor.execute("CREATE TABLE IF NOT EXISTS \"positions\"(trajectory_id INTEGER,frame_number INTEGER, x_coordinate REAL, y_coordinate REAL, PRIMARY KEY(trajectory_id, frame_number))")
467 cursor.execute("CREATE TABLE IF NOT EXISTS \"velocities\"(trajectory_id INTEGER,frame_number INTEGER, x_coordinate REAL, y_coordinate REAL, PRIMARY KEY(trajectory_id, frame_number))")
468
469 if trajectoryType == 'feature':
470 if type(objectNumbers) == int and objectNumbers == -1:
471 for trajectory in objects:
472 trajectory_id = trajectory.num
473 frame_number = trajectory.timeInterval.first
474 for position,velocity in zip(trajectory.getPositions(),trajectory.getVelocities()):
475 cursor.execute("insert into positions (trajectory_id, frame_number, x_coordinate, y_coordinate) values (?,?,?,?)",(trajectory_id,frame_number,position.x,position.y))
476 cursor.execute("insert into velocities (trajectory_id, frame_number, x_coordinate, y_coordinate) values (?,?,?,?)",(trajectory_id,frame_number,velocity.x,velocity.y))
477 frame_number += 1
478
479 connection.commit()
480 connection.close()
481
482 def writePrototypesToSqlite(prototypes,nMatching, outputFilename):
483 """ prototype dataset is a dictionary with keys== routes, values== prototypes Ids """
484 connection = sqlite3.connect(outputFilename)
485 cursor = connection.cursor()
486
487 cursor.execute("CREATE TABLE IF NOT EXISTS \"prototypes\"(prototype_id INTEGER,routeIDstart INTEGER,routeIDend INTEGER, nMatching INTEGER, PRIMARY KEY(prototype_id))")
488
489 for route in prototypes.keys():
490 if prototypes[route]!=[]:
491 for i in prototypes[route]:
492 cursor.execute("insert into prototypes (prototype_id, routeIDstart,routeIDend, nMatching) values (?,?,?,?)",(i,route[0],route[1],nMatching[route][i]))
493
494 connection.commit()
495 connection.close()
496
497 def readPrototypesFromSqlite(filename):
498 """
499 This function loads the prototype file in the database
500 It returns a dictionary for prototypes for each route and nMatching
501 """
502 prototypes = {}
503 nMatching={}
504
505 connection = sqlite3.connect(filename)
506 cursor = connection.cursor()
507
508 try:
509 cursor.execute('SELECT * from prototypes order by prototype_id, routeIDstart,routeIDend, nMatching')
510 except sqlite3.OperationalError as error:
511 utils.printDBError(error)
512 return []
513
514 for row in cursor:
515 route=(row[1],row[2])
516 if route not in prototypes.keys():
517 prototypes[route]=[]
518 prototypes[route].append(row[0])
519 nMatching[row[0]]=row[3]
520
521 connection.close()
522 return prototypes,nMatching
523
524 def writeLabelsToSqlite(labels, outputFilename):
525 """ labels is a dictionary with keys: routes, values: prototypes Ids
526 """
527 connection = sqlite3.connect(outputFilename)
528 cursor = connection.cursor()
529
530 cursor.execute("CREATE TABLE IF NOT EXISTS \"labels\"(object_id INTEGER,routeIDstart INTEGER,routeIDend INTEGER, prototype_id INTEGER, PRIMARY KEY(object_id))")
531
532 for route in labels.keys():
533 if labels[route]!=[]:
534 for i in labels[route]:
535 for j in labels[route][i]:
536 cursor.execute("insert into labels (object_id, routeIDstart,routeIDend, prototype_id) values (?,?,?,?)",(j,route[0],route[1],i))
537
538 connection.commit()
539 connection.close()
540
541 def loadLabelsFromSqlite(filename):
542 labels = {}
543
544 connection = sqlite3.connect(filename)
545 cursor = connection.cursor()
546
547 try:
548 cursor.execute('SELECT * from labels order by object_id, routeIDstart,routeIDend, prototype_id')
549 except sqlite3.OperationalError as error:
550 utils.printDBError(error)
551 return []
552
553 for row in cursor:
554 route=(row[1],row[2])
555 p=row[3]
556 if route not in labels.keys():
557 labels[route]={}
558 if p not in labels[route].keys():
559 labels[route][p]=[]
560 labels[route][p].append(row[0])
561
562 connection.close()
563 return labels
564
565 def writeSpeedPrototypeToSqlite(prototypes,nmatching, outFilename):
566 """ to match the format of second layer prototypes"""
567 connection = sqlite3.connect(outFilename)
568 cursor = connection.cursor()
569
570 cursor.execute("CREATE TABLE IF NOT EXISTS \"speedprototypes\"(spdprototype_id INTEGER,prototype_id INTEGER,routeID_start INTEGER, routeID_end INTEGER, nMatching INTEGER, PRIMARY KEY(spdprototype_id))")
571
572 for route in prototypes.keys():
573 if prototypes[route]!={}:
574 for i in prototypes[route]:
575 if prototypes[route][i]!= []:
576 for j in prototypes[route][i]:
577 cursor.execute("insert into speedprototypes (spdprototype_id,prototype_id, routeID_start, routeID_end, nMatching) values (?,?,?,?,?)",(j,i,route[0],route[1],nmatching[j]))
578
579 connection.commit()
580 connection.close()
581
582 def loadSpeedPrototypeFromSqlite(filename):
583 """
584 This function loads the prototypes table in the database of name <filename>.
585 """
586 prototypes = {}
587 nMatching={}
588 connection = sqlite3.connect(filename)
589 cursor = connection.cursor()
590
591 try:
592 cursor.execute('SELECT * from speedprototypes order by spdprototype_id,prototype_id, routeID_start, routeID_end, nMatching')
593 except sqlite3.OperationalError as error:
594 utils.printDBError(error)
595 return []
596
597 for row in cursor:
598 route=(row[2],row[3])
599 if route not in prototypes.keys():
600 prototypes[route]={}
601 if row[1] not in prototypes[route].keys():
602 prototypes[route][row[1]]=[]
603 prototypes[route][row[1]].append(row[0])
604 nMatching[row[0]]=row[4]
605
606 connection.close()
607 return prototypes,nMatching
608
609
610 def writeRoutesToSqlite(Routes, outputFilename):
611 """ This function writes the activity path define by start and end IDs"""
612 connection = sqlite3.connect(outputFilename)
613 cursor = connection.cursor()
614
615 cursor.execute("CREATE TABLE IF NOT EXISTS \"routes\"(object_id INTEGER,routeIDstart INTEGER,routeIDend INTEGER, PRIMARY KEY(object_id))")
616
617 for route in Routes.keys():
618 if Routes[route]!=[]:
619 for i in Routes[route]:
620 cursor.execute("insert into routes (object_id, routeIDstart,routeIDend) values (?,?,?)",(i,route[0],route[1]))
621
622 connection.commit()
623 connection.close()
624
625 def loadRoutesFromSqlite(filename):
626 Routes = {}
627
628 connection = sqlite3.connect(filename)
629 cursor = connection.cursor()
630
631 try:
632 cursor.execute('SELECT * from routes order by object_id, routeIDstart,routeIDend')
633 except sqlite3.OperationalError as error:
634 utils.printDBError(error)
635 return []
636
637 for row in cursor:
638 route=(row[1],row[2])
639 if route not in Routes.keys():
640 Routes[route]=[]
641 Routes[route].append(row[0])
642
643 connection.close()
644 return Routes
645
646 def setRoutes(filename, objects):
647 connection = sqlite3.connect(filename)
648 cursor = connection.cursor()
649 for obj in objects:
650 cursor.execute('update objects set startRouteID = {} where object_id = {}'.format(obj.startRouteID, obj.getNum()))
651 cursor.execute('update objects set endRouteID = {} where object_id = {}'.format(obj.endRouteID, obj.getNum()))
652 connection.commit()
653 connection.close()
654
655 def setRoadUserTypes(filename, objects):
656 '''Saves the user types of the objects in the sqlite database stored in filename
657 The objects should exist in the objects table'''
658 connection = sqlite3.connect(filename)
659 cursor = connection.cursor()
660 for obj in objects:
661 cursor.execute('update objects set road_user_type = {} where object_id = {}'.format(obj.getUserType(), obj.getNum()))
662 connection.commit()
663 connection.close()
632 664
633 ######################### 665 #########################
634 # txt files 666 # txt files
635 ######################### 667 #########################
636 668
795 if npsum(diff == 0.) >= proportionStationaryTime*len(positions): 827 if npsum(diff == 0.) >= proportionStationaryTime*len(positions):
796 nStationary += 1 828 nStationary += 1
797 829
798 return nStationary, nVehicles 830 return nStationary, nVehicles
799 831
800 def countCollisionsVissim(filename, lanes = None, collisionTimeDifference = 0.2): 832 def countCollisionsVissim(filename, lanes = None, collisionTimeDifference = 0.2, lowMemory = True):
801 '''Counts the number of collisions per lane in a VISSIM trajectory file 833 '''Counts the number of collisions per lane in a VISSIM trajectory file
802 834
803 To distinguish between cars passing and collision, 835 To distinguish between cars passing and collision,
804 one checks when the sign of the position difference inverts 836 one checks when the sign of the position difference inverts
805 (if the time are closer than collisionTimeDifference) 837 (if the time are closer than collisionTimeDifference)
806 If lanes is not None, only the data for the selected lanes will be provided 838 If lanes is not None, only the data for the selected lanes will be provided
807 (format as string x_y where x is link index and y is lane index)''' 839 (format as string x_y where x is link index and y is lane index)'''
808 from pandas import read_csv, merge 840 from pandas import read_csv, merge
809 data = read_csv(filename, delimiter=';', comment='*', header=0, skiprows = 1, usecols = ['LANE\LINK\NO', 'LANE\INDEX', '$VEHICLE:SIMSEC', 'NO', 'POS'], low_memory = lowMemory) 841 data = read_csv(filename, delimiter=';', comment='*', header=0, skiprows = 1, usecols = ['LANE\LINK\NO', 'LANE\INDEX', '$VEHICLE:SIMSEC', 'NO', 'POS'], low_memory = lowMemory)
810 data = selectPDLanes(data, lanes) 842 data = selectPDLanes(data, lanes)
843 data = data.convert_objects(convert_numeric=True)
844
811 merged = merge(data, data, how='inner', left_on=['LANE\LINK\NO', 'LANE\INDEX', '$VEHICLE:SIMSEC'], right_on=['LANE\LINK\NO', 'LANE\INDEX', '$VEHICLE:SIMSEC'], sort = False) 845 merged = merge(data, data, how='inner', left_on=['LANE\LINK\NO', 'LANE\INDEX', '$VEHICLE:SIMSEC'], right_on=['LANE\LINK\NO', 'LANE\INDEX', '$VEHICLE:SIMSEC'], sort = False)
812 merged = merged[merged['NO_x']>merged['NO_y']] 846 merged = merged[merged['NO_x']>merged['NO_y']]
813 847
814 nCollisions = 0 848 nCollisions = 0
815 for name, group in merged.groupby(['LANE\LINK\NO', 'LANE\INDEX', 'NO_x', 'NO_y']): 849 for name, group in merged.groupby(['LANE\LINK\NO', 'LANE\INDEX', 'NO_x', 'NO_y']):
816 diff = group['POS_x'].convert_objects(convert_numeric=True)-group['POS_y'].convert_objects(convert_numeric=True) 850 diff = group['POS_x']-group['POS_y']
817 # diff = group['POS_x']-group['POS_y'] # to check the impact of convert_objects and the possibility of using type conversion in read_csv or function to convert strings if any 851 # diff = group['POS_x']-group['POS_y'] # to check the impact of convert_objects and the possibility of using type conversion in read_csv or function to convert strings if any
818 if len(diff) >= 2 and npmin(diff) < 0 and npmax(diff) > 0: 852 if len(diff) >= 2 and npmin(diff) < 0 and npmax(diff) > 0:
819 xidx = diff[diff < 0].argmax() 853 xidx = diff[diff < 0].argmax()
820 yidx = diff[diff > 0].argmin() 854 yidx = diff[diff > 0].argmin()
821 if abs(group.loc[xidx, '$VEHICLE:SIMSEC'] - group.loc[yidx, '$VEHICLE:SIMSEC']) <= collisionTimeDifference: 855 if abs(group.loc[xidx, '$VEHICLE:SIMSEC'] - group.loc[yidx, '$VEHICLE:SIMSEC']) <= collisionTimeDifference: