Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/tools/assign/duaIterate_analysis.py
169673 views
1
#!/usr/bin/env python
2
# -*- coding: utf-8 -*-
3
# Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
4
# Copyright (C) 2012-2025 German Aerospace Center (DLR) and others.
5
# This program and the accompanying materials are made available under the
6
# terms of the Eclipse Public License 2.0 which is available at
7
# https://www.eclipse.org/legal/epl-2.0/
8
# This Source Code may also be made available under the following Secondary
9
# Licenses when the conditions for such availability set forth in the Eclipse
10
# Public License 2.0 are satisfied: GNU General Public License, version 2
11
# or later which is available at
12
# https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
13
# SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
14
15
# @file duaIterate_analysis.py
16
# @author Jakob Erdmann
17
# @author Michael Behrisch
18
# @author Mirko Barthauer
19
# @date 2012-09-06
20
21
"""
22
Parses the log outputs from duaIterate.py.
23
By default, the concatenaded log of sumo outputs (named dua.log by default) is
24
parsed to obtain statistics on the following quantities:
25
inserted, teleports, waiting, loaded and running.
26
Optionally, the stdout.log is parsed as well to obtain statistics on
27
routingMinutes, simMinutes and absAvgError
28
"""
29
30
from __future__ import absolute_import
31
from __future__ import print_function
32
import os
33
import sys
34
import re
35
import glob
36
from collections import defaultdict
37
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
38
from sumolib.miscutils import Statistics, uMax # noqa
39
from sumolib.output import parse_fast # noqa
40
from sumolib.options import ArgumentParser # noqa
41
42
43
def parse_args():
44
parser = ArgumentParser()
45
parser.add_argument("--stdout", type=parser.file,
46
help="also parse the given FILE containing stdout of duaIterate")
47
parser.add_argument("-o", "--output", category="output", default="plot",
48
help="output prefix for plotting with gnuplot")
49
parser.add_argument("-l", "--label-size", default=40, dest="label_size", type=int,
50
help="limit length of the plot label to this size")
51
parser.add_argument("--limit", type=int,
52
help="only parse the first INT number of iterations")
53
parser.add_argument("--teleports", category="output", default="teleplot",
54
help="output prefix for plotting teleport-prone edges")
55
parser.add_argument("--mpl", category="output",
56
help="output prefix for matplotlib plots or SHOW for plotting to the display")
57
parser.add_argument("dualog", category="output", nargs=1, type=parser.file, help="file path to dua log file")
58
options = parser.parse_args()
59
options.dualog = options.dualog[0]
60
61
if options.limit is None:
62
options.limit = uMax
63
return options
64
65
66
def parse_dualog(dualog, limit):
67
print("Parsing %s" % dualog)
68
teleStats = Statistics('Teleports')
69
header = ['#Inserted', 'Running', 'Waiting', 'Teleports', 'Loaded']
70
step_values = [] # list of lists
71
step_counts = [] # list of edge teleport counters
72
reInserted = re.compile(r"Inserted: (\d*)")
73
reLoaded = re.compile(r"Loaded: (\d*)")
74
reRunning = re.compile(r"Running: (\d*)")
75
reWaiting = re.compile(r"Waiting: (\d*)")
76
reFrom = re.compile("from '([^']*)'") # mesosim
77
teleports = 0
78
inserted = None
79
loaded = None
80
running = None
81
waiting = None
82
haveMicrosim = None
83
counts = defaultdict(lambda: 0)
84
with open(dualog) as dualogIn:
85
for line in dualogIn:
86
try:
87
if "Warning: Teleporting vehicle" in line:
88
if haveMicrosim is None:
89
if "lane='" in line:
90
haveMicrosim = True
91
reFrom = re.compile("lane='([^']*)'")
92
else:
93
haveMicrosim = False
94
teleports += 1
95
edge = reFrom.search(line).group(1)
96
if ':' in edge: # mesosim output
97
edge = edge.split(':')[0]
98
counts[edge] += 1
99
elif "Inserted:" in line:
100
inserted = reInserted.search(line).group(1)
101
if "Loaded:" in line: # optional output
102
loaded = reLoaded.search(line).group(1)
103
else:
104
loaded = inserted
105
elif "Running:" in line:
106
running = reRunning.search(line).group(1)
107
elif "Waiting:" in line:
108
iteration = len(step_values)
109
if iteration > limit:
110
break
111
waiting = reWaiting.search(line).group(1)
112
teleStats.add(teleports, iteration)
113
step_values.append([inserted, running, waiting, teleports, loaded])
114
teleports = 0
115
step_counts.append(counts)
116
counts = defaultdict(lambda: 0)
117
except Exception:
118
sys.exit("error when parsing line '%s'" % line)
119
120
print(" parsed %s steps" % len(step_values))
121
print(teleStats)
122
return [header] + step_values, step_counts
123
124
125
def parse_stdout(step_values, stdout):
126
print("Parsing %s" % stdout)
127
step_values[0] += ['routingMinutes', 'simMinutes', 'absAvgError']
128
reDuration = re.compile("Duration: (.*)$")
129
reError = re.compile(r"Absolute Error avg:(\d*)")
130
131
def get_minutes(line):
132
hours, minutes, seconds = reDuration.search(line).group(1).split(':')
133
return int(hours) * 60 + int(minutes) + float(seconds) / 60
134
step = 1
135
routingMinutes = None
136
simMinutes = None
137
error = None
138
for line in open(stdout):
139
if "Duration" in line:
140
if routingMinutes is None:
141
routingMinutes = get_minutes(line)
142
else:
143
simMinutes = get_minutes(line)
144
elif "Absolute" in line:
145
error = reError.search(line).group(1)
146
step_values[step] += [routingMinutes, simMinutes, error]
147
step += 1
148
if step >= len(step_values):
149
break
150
routingMinutes = None
151
print(" parsed %s steps" % (step - 1))
152
153
154
def gnuplot_teleport_edges(plotfile, step_counts, xlabel):
155
datafile = plotfile + '.data'
156
# an edge is interesting if a large proportion of teleports happen on it
157
interestingness = defaultdict(lambda: 0)
158
for counts in step_counts:
159
teleports = float(sum(counts.values()))
160
if teleports == 0:
161
continue
162
for edge, count in counts.items():
163
interestingness[edge] += count / teleports
164
interesting = sorted([(c, e) for e, c in interestingness.items()])[-7:]
165
print("most interesting edges:", interesting)
166
if len(interesting) > 0:
167
interesting = [e for c, e in interesting]
168
with open(datafile, 'w') as f:
169
print('#' + ' '.join(interesting), file=f)
170
for counts in step_counts:
171
values = [counts[e] for e in interesting]
172
f.write(' '.join(map(str, values)) + '\n')
173
# write plotfile
174
with open(plotfile, 'w') as f:
175
f.write("set xlabel '%s'\nplot \\\n" % xlabel)
176
lines = ["'%s' using 0:%s title '%s' with lines" % (datafile, ii + 1, edge)
177
for ii, edge in enumerate(interesting)]
178
f.write(', \\\n'.join(lines))
179
180
181
def parse_trip_durations():
182
result = []
183
for file in sorted(glob.glob("tripinfo_*.xml")):
184
result.append([float(t.duration)
185
for t in parse_fast(file, 'tripinfo', ['duration'])])
186
return result
187
188
189
def matplot(output):
190
if output is not None:
191
import matplotlib
192
if output != 'SHOW':
193
matplotlib.use('Agg')
194
import matplotlib.pyplot as plt
195
plt.boxplot(parse_trip_durations())
196
if output == 'SHOW':
197
plt.show()
198
else:
199
plt.savefig(output)
200
plt.close()
201
202
203
def gnuplot_vehicle_summary(plotfile, xlabel, step_values):
204
datafile = plotfile + '.data'
205
with open(datafile, 'w') as f:
206
for values in step_values:
207
f.write(' '.join(map(str, values)) + '\n')
208
209
with open(plotfile, 'w') as f:
210
f.write("""
211
set xlabel '%s'
212
plot \\
213
'%s' using 0:1 title 'inserted' with lines, \\
214
'%s' using 0:4 title 'teleports' with lines, \\
215
'%s' using 0:3 title 'waiting' with lines, \\
216
'%s' using 0:5 title 'loaded' with lines, \\
217
'%s' using 0:2 title 'running' with lines
218
""" % ((xlabel,) + (datafile,) * 5))
219
220
221
def main():
222
options = parse_args()
223
step_values, step_counts = parse_dualog(options.dualog, options.limit)
224
if options.stdout is not None:
225
parse_stdout(step_values, options.stdout)
226
duaPath = os.path.dirname(
227
os.path.abspath(options.dualog))[-options.label_size:]
228
xlabel = 'Iterations in ' + duaPath
229
230
gnuplot_vehicle_summary(options.output, xlabel, step_values)
231
gnuplot_teleport_edges(options.teleports, step_counts, xlabel)
232
matplot(options.mpl)
233
234
235
##################
236
if __name__ == "__main__":
237
main()
238
239