Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/tools/import/visum/visum_convertRoutes.py
169679 views
1
#!/usr/bin/env python
2
# Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
# Copyright (C) 2009-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 visum_convertRoutes.py
15
# @author Daniel Krajzewicz
16
# @author Michael Behrisch
17
# @date 2007-02-21
18
19
20
from __future__ import print_function
21
from __future__ import absolute_import
22
import os
23
import sys
24
import random
25
if "SUMO_HOME" in os.environ:
26
sys.path.append(os.path.join(os.environ['SUMO_HOME'], 'tools'))
27
import sumolib # noqa
28
29
30
class Statistics:
31
found = 0
32
foundN = 0
33
missing = 0
34
missingN = 0
35
36
37
stats = Statistics()
38
routes = []
39
40
41
def addRouteChecking(route, id, count, ok):
42
route = route.strip()
43
if route != "":
44
if ok:
45
if options.distribution and routes:
46
distID = routes[0][0][:routes[0][0].rfind("_")]
47
if distID != id[:id.rfind("_")]:
48
sum = 0
49
r_max = (None, 0, None)
50
for r in routes:
51
sum += r[1]
52
if r_max[1] < r[1]:
53
r_max = r
54
if sum < options.cutoff:
55
del routes[:]
56
routes.append((r_max[0], sum, r_max[2]))
57
if len(routes) > 1:
58
fdo.write(' <routeDistribution id="%s">\n' % distID)
59
else:
60
routes[0] = (distID, routes[0][1], routes[0][2])
61
for r in routes:
62
if net2:
63
trace = []
64
for e in route.split():
65
edge = net.getEdge(e)
66
numSteps = int(edge.getLength() / options.step)
67
for p in range(numSteps):
68
trace.append(
69
sumolib.geomhelper.positionAtShapeOffset(edge.getShape(), p * options.step))
70
path = sumolib.route.mapTrace(
71
trace, net2, options.delta)
72
r = (r[0], r[1], " ".join(path))
73
fdo.write(
74
' <route id="%s" probability="%s" edges="%s"/>\n' % r)
75
if len(routes) > 1:
76
fdo.write(' </routeDistribution>\n')
77
del routes[:]
78
routes.append((id, count, route))
79
stats.found += 1
80
stats.foundN += count
81
else:
82
stats.missing += 1
83
stats.missingN += count
84
85
86
def sorter(idx):
87
def t(i, j):
88
if i[idx] < j[idx]:
89
return -1
90
elif i[idx] > j[idx]:
91
return 1
92
else:
93
return 0
94
95
96
# initialise
97
op = sumolib.options.ArgumentParser()
98
op.add_option("-n", "--net-file", dest="netfile", category="input", required=True, type=op.net_file,
99
help="SUMO net file to work with")
100
op.add_option("-r", "--visum-routes", dest="routes", category="input", required=True, type=op.file,
101
help="The VISUM-routes files to parse")
102
op.add_option("-o", "--output", category="output", type=op.file, required=True,
103
help="Name of the file to write")
104
op.add_option("-b", "--begin", category="time", type=op.time,
105
help="The begin time of the routes to generate", default=0)
106
op.add_option("-e", "--end", category="time", type=op.time,
107
help="The end time (+1) of the routes to generate", default=3600)
108
op.add_option("-p", "--prefix", category="input",
109
help="ID prefix to use")
110
op.add_option("-t", "--type", category="input",
111
help="The type to use for vehicles")
112
op.add_option("-u", "--uniform",
113
help="Whether departures shall be distributed uniform in each interval", action="store_true",
114
default=False)
115
op.add_option("-l", "--timeline", category="input",
116
help="Percentages over a day")
117
op.add_option("-a", "--tabs", action="store_true",
118
default=False, help="tab separated route file")
119
op.add_option("-v", "--verbose", action="store_true",
120
default=False, help="tell me what you are doing")
121
op.add_option("-2", "--net2", category="input", type=op.net_file,
122
help="immediately match routes to a second network", metavar="FILE")
123
op.add_option("-s", "--step", default=10, category="input",
124
type=float, help="distance between successive trace points")
125
op.add_option("-d", "--delta", default=1, category="input",
126
type=float, help="maximum distance between edge and trace points when matching " +
127
" to the second net")
128
op.add_option("-i", "--distribution", action="store_true",
129
default=False, help="write route distributions only")
130
op.add_option("--cutoff", category="input",
131
help="Keep only one route when less than CUTOFF vehicles drive the OD", type=int,
132
default=0)
133
134
# parse options
135
options = op.parse_args()
136
137
if options.verbose:
138
print("Reading net...")
139
net = sumolib.net.readNet(options.netfile)
140
net2 = None
141
if options.net2:
142
net.move(-net.getLocationOffset()[0], -net.getLocationOffset()[1])
143
net2 = sumolib.net.readNet(options.net2)
144
net2.move(-net2.getLocationOffset()[0], -net2.getLocationOffset()[1])
145
146
# initialise nodes/edge map
147
emap = {}
148
for e in net._edges:
149
if e._from._id not in emap:
150
emap[e._from._id] = {}
151
if e._to._id not in emap[e._from._id]:
152
emap[e._from._id][e._to._id] = e._id
153
154
# fill with read values
155
if options.verbose:
156
print("Reading routes...")
157
separator = "\t" if options.tabs else ";"
158
parse = False
159
ok = True
160
route = ""
161
id = ""
162
attributes = []
163
count = 0
164
no = 0
165
fd = open(options.routes)
166
fdo = open(options.output, "w")
167
fdo.write("<routes>\n")
168
for idx, line in enumerate(fd):
169
if options.verbose and idx % 10000 == 0:
170
sys.stdout.write("%s lines read\r" % "{:,}".format(idx))
171
if line.find("$") == 0 or line.find("*") == 0 or line.find(separator) < 0:
172
parse = False
173
addRouteChecking(route, id, count, ok)
174
if parse:
175
values = line.strip('\n\r').split(separator)
176
amap = {}
177
for i in range(0, len(attributes)):
178
amap[attributes[i]] = values[i]
179
if amap["origzoneno"] != "":
180
# route begin (not the route)
181
addRouteChecking(route, id, count, ok)
182
id = amap["origzoneno"] + "_" + \
183
amap["destzoneno"] + "_" + amap["pathindex"]
184
count = float(amap["prtpath\\vol(ap)"])
185
route = " "
186
ok = True
187
else:
188
if not ok:
189
continue
190
fromnode = amap["fromnodeno"]
191
tonode = amap["tonodeno"]
192
link = amap["linkno"]
193
if fromnode not in emap:
194
if no != 0:
195
print("Missing from-node '" + fromnode + "'; skipping")
196
ok = False
197
continue
198
if tonode not in emap[fromnode]:
199
if no != 0:
200
print("No connection between from-node '" +
201
fromnode + "' and to-node '" + tonode + "'; skipping")
202
ok = False
203
continue
204
edge = emap[fromnode][tonode]
205
if link != edge and link != edge[1:]:
206
if no != 0:
207
print("Mismatching edge '" + link + "' (from '" +
208
fromnode + "', to '" + tonode + "'); skipping")
209
ok = False
210
continue
211
route = route + edge + " "
212
213
if line.find("$PRTPATHLINK:") == 0 or line.find("$IVTEILWEG:") == 0:
214
attributes = line[line.find(":") + 1:].strip().lower().split(separator)
215
for i in range(0, len(attributes)):
216
if attributes[i] == "qbeznr":
217
attributes[i] = "origzoneno"
218
if attributes[i] == "zbeznr":
219
attributes[i] = "destzoneno"
220
if attributes[i] == "iv-weg\\bel(ap)":
221
attributes[i] = "prtpath\\vol(ap)"
222
if attributes[i] == "wegind":
223
attributes[i] = "pathindex"
224
if attributes[i] == "vonknotnr":
225
attributes[i] = "fromnodeno"
226
if attributes[i] == "nachknotnr":
227
attributes[i] = "tonodeno"
228
if attributes[i] == "strnr":
229
attributes[i] = "linkno"
230
parse = True
231
232
addRouteChecking(route, id, count, ok)
233
fd.close()
234
235
if options.verbose:
236
print(" %s routes found (%s vehs)" % (stats.found, stats.foundN))
237
print(" %s routes missing (%s vehs)" % (stats.missing, stats.missingN))
238
239
if options.distribution:
240
if routes:
241
distID = routes[0][0][:routes[0][0].rfind("_")]
242
fdo.write(' <routeDistribution id="%s">\n' % distID)
243
for r in routes:
244
fdo.write(
245
' <route id="%s" probability="%s" edges="%s"/>\n' % r)
246
fdo.write(' </routeDistribution>\n')
247
fdo.write("</routes>\n")
248
fdo.close()
249
exit()
250
251
timeline = None
252
# apply timeline
253
if options.timeline:
254
timeline = []
255
nNo = 0
256
vals = options.timeline.split(",")
257
sum = 0
258
for v in vals:
259
timeline.append(float(v))
260
sum += float(v)
261
if len(timeline) != 24:
262
print("The timeline must have 24 entries")
263
sys.exit()
264
nRoutes = []
265
266
# convert to vehicles
267
if options.verbose:
268
print("Generating vehicles...")
269
emissions = []
270
begin = int(options.begin)
271
end = int(options.end)
272
273
if not timeline:
274
for r in routes:
275
for i in range(0, int(r[1])):
276
if options.uniform:
277
t = float(begin) + float(end - begin) / float(r[1]) * float(i)
278
else:
279
t = float(begin) + float(end - begin) * random.random()
280
emissions.append((int(t), r[0] + "__" + str(i), r[2]))
281
else:
282
for r in routes:
283
left = 0.
284
tbeg = 0
285
j = 0
286
for t in timeline:
287
fno = (float(r[1]) + left) * t / 100.
288
no = int(fno)
289
left += fno - no
290
if left >= 1.:
291
left -= 1
292
no += 1
293
for i in range(0, no):
294
if options.uniform:
295
t = tbeg + float(3600) / float(r[1]) * float(i)
296
else:
297
t = tbeg + float(3600) * random.random()
298
emissions.append((int(t), r[0] + "__" + str(j), r[2]))
299
j = j + 1
300
nNo += no
301
tbeg += 3600
302
if options.verbose:
303
print(" %s vehicles after applying timeline" % nNo)
304
305
306
# sort emissions
307
if options.verbose:
308
print("Sorting routes...")
309
emissions.sort(sorter(0))
310
311
# save emissions
312
if options.verbose:
313
print("Writing routes...")
314
for emission in emissions:
315
fdo.write(' <vehicle id="')
316
if options.prefix:
317
fdo.write(options.prefix + "_")
318
fdo.write(emission[1] + '" depart="' + str(emission[0]) + '"')
319
if options.type:
320
fdo.write(' type="' + options.type + '"')
321
fdo.write('><route edges="' + emission[2] + '"/></vehicle>\n')
322
fdo.write("</routes>\n")
323
fdo.close()
324
if options.verbose:
325
print(" %s vehicles written" % len(emissions))
326
327