-
Notifications
You must be signed in to change notification settings - Fork 0
/
SatFlows.py
215 lines (169 loc) · 8.58 KB
/
SatFlows.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
# -*- coding: utf-8 -*-
"""
Created on Tue Jun 14 18:04:06 2016
@author: BallisT
"""
import numpy as np
from itertools import groupby
from operator import itemgetter
def Main():
#-------------------------PARAMETERS---------------------------------------------------------------------------#
vehsIgnored = 2 #Numbrer of vehicles to ignore at start of green
satFlowHead = 3 #End of sat flow headway (Maximum Gap between crossing vehicles in seconds)
minVehsPerMeas = 6 #Minimum number of vehicles per measurement
minValidCycles = 2 #Minimum number of (valid) signal head Cycles in order to calculate an average
#DON'T Forget to use double backslashes (\\) for separating Folders
csv_output_fp = r'Output\Output_SatFlows.csv'
dis_input_fp = 'Input_DIS_files'
#csv_input_filepath = 'Input_CSV\\SatFlows.csv'
#--------------------------------------------------------------------------------------------------------------#
satFlow_data = GetDisData(dis_input_fp)
#Old Approach using power query to create the csv input
#satFlow_data = GetCSVData(csv_input_filepath)
#Keep the original Data in memory
wt = satFlow_data
#Remove the rows of the data where crossVehIdx <= VehsIgnored
wt = RemoveIgnoredVehs(wt,vehsIgnored)
#Return a dictionary with the total valid crossing time of vehicles for each Signal Head and Simulation
satFlows = CalculateSatFlows(wt,satFlowHead,minValidCycles,minVehsPerMeas)
#For the valid Signal Heads we can calculate the average of Saturation Flows
#For the rest we print the list
avgSatFlows = CalculateAvgSatFlows(satFlows)
Output(csv_output_fp,avgSatFlows)
print 'End of execution - Results in ' + str(csv_output_fp)
def GetDisData(dis_input_fp):
#Function to read the dis files generated by Vissim
#The output is a table with columns['sigHead','SimRun','cycleStart','timeGap']
import glob
sigHeads = []
Simulation_Runs = []
cycleStarts = []
crossVehIdxs = []
timeGaps = []
path = dis_input_fp + '\\*.dis'
for dis_file in glob.glob(path):
with open(dis_file) as f:
simRun = int(dis_file.rsplit('_',1)[1].replace('.dis',''))
lines = f.readlines()
for line in lines:
line = line.strip()
if line.startswith('Discharge at'):
sigHead = int(line.rsplit(' ', 1)[1])
else:
first_val = line.split(' ',1)[0]
#Try to convert value in float
try:
cycleStart = float(first_val)
#remove the consecutive spaces from the string
line_tmp = " ".join(line.split())
#First remove everything after the parenthesis
timeGaps_inLine = line_tmp.split('(')[0].strip()
timeGaps_inLine = timeGaps_inLine.split(' ')
del timeGaps_inLine[0]
crossVehIdx = 1
for timeGap in timeGaps_inLine:
sigHeads.append(sigHead)
Simulation_Runs.append(simRun)
cycleStarts.append(cycleStart)
crossVehIdxs.append(crossVehIdx)
timeGaps.append(timeGap)
crossVehIdx += 1
except:
continue
#Create the numpy array
#np_array = np.array(sigHeads,Simulation_Runs,cycleStarts,crossVehIdxs,timeGaps)
wtype=np.dtype([('sigHead','i4'),('SimRun','i4'),
('cycleStart','f4'),('crossVehIdx','f4'),
('timeGap','f4')])
wt=np.empty(len(sigHeads),dtype=wtype)
wt['sigHead'] = sigHeads
wt['SimRun'] = Simulation_Runs
wt['cycleStart'] = cycleStarts
wt['crossVehIdx'] = crossVehIdxs
wt['timeGap']= timeGaps
wt.sort(order='sigHead')
return wt
def GetCSVData(filepath):
data = np.genfromtxt (filepath, delimiter=",",dtype=None,names=True)
return data
def RemoveIgnoredVehs(inp_tbl,vehsIgnored):
inds_to_del = np.where(inp_tbl['crossVehIdx'] <= vehsIgnored)[0]
out_tbl = np.delete(inp_tbl,inds_to_del,axis=0)
return out_tbl
def CalculateSatFlows(wt,satFlowHead,minValidCycles,minVehsPerMeas):
""" Return a dictionary with keys [Signal_Head_Simulation_Run]
and values the total time of vehicles crossing (number of subsequent vehicles with
acceptable timeGap, greater than minVehsPerMeas) and their count
"""
satFlows = {}
for signalHead in np.unique(wt['sigHead']):
#dictionary to store the sat flows of the signal head for each iteration
d = {}
for simRun in np.unique(wt['SimRun']):
#Find the unique values of cycleStarts for this signalHead and simRun
sliced_tbl = wt[(wt['sigHead'] == signalHead) & (wt['SimRun'] == simRun)]
unique_cycleStarts = np.unique(sliced_tbl['cycleStart'])
if len(unique_cycleStarts) >= minValidCycles:
for cycleStart in unique_cycleStarts:
#Indices of the vehicles with low (acceptable) relative gap
idx_validGaps = np.where((wt['sigHead'] == signalHead) &
(wt['SimRun'] == simRun) &
(wt['cycleStart'] == cycleStart) &
(wt['timeGap'] <= satFlowHead))[0]
#Check if there is a sequence of acceptable indices with more element than the limit (minVehsPerMeas)
#Group the array in groups of consecutive integers
for k, g in groupby(enumerate(idx_validGaps), lambda ix: ix[0]-ix[1]):
idxs = map(itemgetter(1), g)
if len(idxs) >= minVehsPerMeas:
#We have found a sequence of vehicles with more elements than minVehsPerMeas so we can move on
crossTime = 0
for idx in idxs:
#Add the sum to a dictionary with the number of vehicles that were counted
crossTime += wt['timeGap'][idx]
sf = round((3600 * len(idxs)/crossTime),2)
d.setdefault(simRun,[]).append(sf)
break
satFlows[signalHead] = d
return satFlows
def CalculateAvgSatFlows(satFlows):
#Create a dictionary with the average sat flows for each Signal Head and each iteration
avgSatFlows = {}
for signalHead, simRun_SatFlows in satFlows.iteritems():
#dictionary with the avg sat flows for each iteration
d = {}
for simRun, satFlows in simRun_SatFlows.iteritems():
if len(satFlows) > 0:
avg = sum(satFlows)/len(satFlows)
else:
avg=-1
d[simRun] = round(avg,2)
avgSatFlows[signalHead] = d
#Calculate also the avg of all simRuns
tot = 0
for k, v in d.iteritems():
tot += v
if len(d) > 0:
d['AllSimRuns'] = round(tot/len(d),2)
else:
d['AllSimRuns'] = -1
return avgSatFlows
def Output(filepath_out,results):
import csv
import os
import collections as cl
directory = os.path.dirname(filepath_out)
if not os.path.exists(directory):
os.makedirs(directory)
with open(filepath_out,'wb') as f:
w = csv.writer(f)
w.writerow(['Signal_Head','Avg_Saturation_Flow'])
results_ordered = cl.OrderedDict(sorted(results.items()))
for k, v in results_ordered.iteritems():
dout = v
avgAllSimRuns = dout.pop('AllSimRuns',-1)
l = [[k],[avgAllSimRuns],dout.values()]
#flatten the list
row = [i for slst in l for i in slst]
w.writerow(row)
if __name__ == '__main__':
Main()