Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/tools/detector/flowFromEdgeData.py
169673 views
1
#!/usr/bin/env python
2
# Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
# Copyright (C) 2007-2025 German Aerospace Center (DLR) and others.
4
# This program and the accompanying materials are made available under the
5
# terms of the Eclipse Public License 2.0 which is available at
6
# https://www.eclipse.org/legal/epl-2.0/
7
# This Source Code may also be made available under the following Secondary
8
# Licenses when the conditions for such availability set forth in the Eclipse
9
# Public License 2.0 are satisfied: GNU General Public License, version 2
10
# or later which is available at
11
# https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12
# SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13
14
# @file flowFromEdgeData.py
15
# @author Jakob Erdmann
16
# @author Mirko Barthauer
17
# @date 2017-11-27
18
19
from __future__ import absolute_import
20
from __future__ import print_function
21
import math
22
import sys
23
import os
24
25
from collections import defaultdict
26
27
import detector
28
from detector import relError
29
30
SUMO_HOME = os.environ.get('SUMO_HOME',
31
os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', '..'))
32
sys.path.append(os.path.join(SUMO_HOME, 'tools'))
33
import sumolib # noqa
34
from sumolib.xml import parse # noqa
35
from sumolib.miscutils import parseTime # noqa
36
DEBUG = False
37
38
39
def get_options(args=None):
40
parser = sumolib.options.ArgumentParser()
41
parser.add_argument("-d", "--detector-file", dest="detfile", category="input", type=parser.additional_file,
42
help="read detectors from FILE (mandatory)", metavar="FILE")
43
parser.add_argument("-e", "--edgedata-file", dest="edgeDataFile", category="input", type=parser.edgedata_file,
44
help="read edgeData from FILE (mandatory)", metavar="FILE")
45
parser.add_argument("-f", "--detector-flow-file", dest="flowfile", category="input", type=parser.file,
46
help="read detector flows to compare to from FILE (mandatory)", metavar="FILE")
47
parser.add_argument("--flow-column", dest="flowcol", default="qPKW", type=str,
48
help="which column contains flows", metavar="STRING")
49
parser.add_argument("-z", "--respect-zero", action="store_true", dest="respectzero",
50
default=False, help="respect detectors without data (or with permanent zero) with zero flow")
51
parser.add_argument("-i", "--interval", type=parser.time,
52
default="1440", help="aggregation interval in minutes")
53
parser.add_argument("--long-names", action="store_true", dest="longnames",
54
default=False, help="do not use abbreviated names for detector groups")
55
parser.add_argument("--edge-names", action="store_true", dest="edgenames",
56
default=False, help="include detector group edge name in output")
57
parser.add_argument("-b", "--begin", type=parser.time, default=0, help="begin time in minutes")
58
parser.add_argument("--end", type=parser.time, default=None, help="end time in minutes")
59
parser.add_argument("-o", "--output-file", dest="output", category="output", type=parser.file,
60
help="write output to file instead of printing it to console", metavar="FILE")
61
parser.add_argument("--flow-output", dest="flowout", category="output", type=parser.file,
62
help="write output in flowfile format to FILE", metavar="FILE")
63
parser.add_argument("-v", "--verbose", action="store_true", dest="verbose",
64
default=False, help="tell me what you are doing")
65
options = parser.parse_args()
66
if not options.detfile or not options.edgeDataFile or (not options.flowfile and
67
not options.flowout):
68
parser.print_help()
69
sys.exit()
70
71
return options
72
73
74
def readEdgeData(edgeDataFile, begin, end, detReader, flowout):
75
edgeFlow = defaultdict(lambda: 0)
76
for interval in parse(edgeDataFile, "interval", attr_conversions={"begin": parseTime, "end": parseTime}):
77
if DEBUG:
78
print("reading intervals for begin=%s end=%s (current interval begin=%s end=%s)" %
79
(begin, end, interval.begin, interval.end))
80
if interval.begin < end and interval.end > begin:
81
# if read interval is partly outside comparison interval we must scale demand
82
validInterval = interval.end - interval.begin
83
if interval.begin < begin:
84
validInterval -= begin - interval.begin
85
if interval.end > end:
86
validInterval -= interval.end - end
87
scale = validInterval / (interval.end - interval.begin)
88
# store data
89
if flowout:
90
f = open(flowout, 'a')
91
if interval.edge is None:
92
continue
93
for edge in interval.edge:
94
flow = (int(edge.departed) + int(edge.entered)) * scale
95
edgeFlow[edge.id] += flow
96
# print(interval.begin, interval.end, edge.id, edge.departed, edge.entered, scale, edgeFlow[edge.id])
97
if flowout:
98
for group in detReader.getEdgeDetGroups(edge.id):
99
f.write(";".join(map(str, [group.ids[0], interval.begin / 60,
100
flow, edge.speed])) + "\n")
101
if flowout:
102
f.close()
103
if DEBUG:
104
print(" validInterval=%s scale=%s" % (validInterval, scale))
105
return edgeFlow
106
107
108
def printFlows(options, edgeFlow, detReader):
109
edgeIDCol = "edge " if options.edgenames else ""
110
print('# detNames %sRouteFlow DetFlow ratio' % edgeIDCol, file=options.outfile)
111
output = []
112
for edge, detData in detReader._edge2DetData.items():
113
detString = []
114
dFlow = []
115
for group in detData:
116
if group.isValid:
117
groupName = os.path.commonprefix(group.ids)
118
if groupName == "" or options.longnames:
119
groupName = ';'.join(sorted(group.ids))
120
detString.append(groupName)
121
dFlow.append(group.totalFlow)
122
rFlow = len(detString) * [edgeFlow.get(edge, 0)]
123
edges = len(detString) * [edge]
124
output.extend(zip(detString, edges, rFlow, dFlow))
125
for group, edge, rflow, dflow in sorted(output):
126
if dflow > 0 or options.respectzero:
127
if options.edgenames:
128
print(group, edge, repr(rflow), repr(dflow), repr(relError(rflow, dflow)), file=options.outfile)
129
else:
130
print(group, repr(rflow), repr(dflow), repr(relError(rflow, dflow)), file=options.outfile)
131
132
133
def calcStatistics(options, begin, edgeFlow, detReader):
134
rSum = 0.
135
dSum = 0.
136
sumAbsDev = 0.
137
sumSquaredDev = 0.
138
sumSquaredPercent = 0.
139
n = 0
140
for edge, detData in detReader._edge2DetData.items():
141
rFlow = edgeFlow.get(edge, 0)
142
for group in detData:
143
if group.isValid:
144
dFlow = group.totalFlow
145
if dFlow > 0 or options.respectzero:
146
rSum += rFlow
147
dSum += dFlow
148
dev = float(abs(rFlow - dFlow))
149
sumAbsDev += dev
150
sumSquaredDev += dev * dev
151
if dFlow > 0:
152
sumSquaredPercent += dev * dev / dFlow / dFlow
153
n += 1
154
print('# interval', begin, file=options.outfile)
155
print('# avgRouteFlow avgDetFlow avgDev RMSE RMSPE', file=options.outfile)
156
if n == 0:
157
# avoid division by zero
158
n = -1
159
print('#', " ".join(map(repr, [rSum / n, dSum / n, sumAbsDev / n,
160
math.sqrt(sumSquaredDev / n), math.sqrt(sumSquaredPercent / n)])),
161
file=options.outfile)
162
163
164
class LaneMap:
165
def get(self, key, default):
166
return key[0:-2]
167
168
169
def main(options):
170
if options.output is None:
171
options.outfile = sys.stdout
172
else:
173
options.outfile = open(options.output, 'w')
174
if options.flowout:
175
with open(options.flowout, 'w') as f:
176
f.write("Detector;Time;qPKW;vPKW\n")
177
options.begin = None
178
for interval in parse(options.edgeDataFile, "interval", attr_conversions={"begin": float, "end": float}):
179
if options.begin is None:
180
options.begin = interval.begin / 60
181
options.end = interval.end / 60
182
183
detReader = detector.DetectorReader(options.detfile, LaneMap())
184
intervalBeginM = options.begin
185
haveDetFlows = True
186
while ((options.end is None and haveDetFlows) or
187
(options.end is not None and intervalBeginM < options.end)):
188
intervalEndM = intervalBeginM + options.interval
189
if options.end is not None:
190
intervalEndM = min(intervalEndM, options.end)
191
if options.flowfile:
192
if options.verbose:
193
print("Reading flows")
194
haveDetFlows = detReader.readFlows(options.flowfile, flow=options.flowcol,
195
time="Time", timeVal=intervalBeginM, timeMax=intervalEndM)
196
if options.verbose:
197
print("Reading edgeData")
198
edgeFlow = readEdgeData(
199
options.edgeDataFile, intervalBeginM * 60, intervalEndM * 60,
200
detReader, options.flowout)
201
if haveDetFlows and options.flowfile:
202
printFlows(options, edgeFlow, detReader)
203
calcStatistics(options, intervalBeginM, edgeFlow, detReader)
204
detReader.clearFlows()
205
intervalBeginM += options.interval
206
options.outfile.close()
207
208
209
if __name__ == "__main__":
210
main(get_options())
211
212