Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/tools/route/splitRouteFiles.py
169673 views
1
#!/usr/bin/env python
2
# Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
# Copyright (C) 2010-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 splitRouteFiles.py
15
# @author Michael Behrisch
16
# @date 2007-09-10
17
18
"""
19
Splits a list of route files (e.g. coming from the duarouter)
20
by start time and by edges which contain detectors from an optional
21
detector file.
22
"""
23
from __future__ import print_function
24
import os
25
import sys
26
import re
27
import random
28
import pickle
29
import bisect
30
import ctypes
31
32
from xml.sax import make_parser, handler
33
from collections import defaultdict
34
35
sys.path += [os.path.join(os.environ['SUMO_HOME'], 'tools'),
36
os.path.join(os.environ['SUMO_HOME'], 'tools', 'detector')]
37
import sumolib # noqa
38
from detector import DetectorReader, LaneMap # noqa
39
40
41
def getFreeSpace(folder):
42
""" Return folder/drive free space (in bytes)
43
"""
44
if os.name == "posix":
45
s = os.statvfs(folder)
46
return s.f_bfree * s.f_bsize
47
else:
48
free_bytes = ctypes.c_ulonglong(0)
49
ctypes.windll.kernel32.GetDiskFreeSpaceExW(ctypes.c_wchar_p(folder), None, None, ctypes.pointer(free_bytes))
50
return free_bytes.value
51
52
53
def checkDirOpen(path, mode='w'):
54
dirName = os.path.dirname(path)
55
if dirName != '' and not os.path.exists(dirName):
56
os.makedirs(dirName)
57
return open(path, mode)
58
59
60
class RouteReader(handler.ContentHandler):
61
62
def __init__(self, collectFile, edgeCountFile, pythonEdgeFile, collectAll=False):
63
"""when parsing, collects all routes with their multiplicities in _routeOccurrences.
64
when closeAll() is called the edge distributions are created"""
65
handler.ContentHandler.__init__(self)
66
self._routeOccurrences = defaultdict(lambda: 0) # listOfEdges -> count
67
self._vehID = None
68
self._routeString = ''
69
self._routeDistributions = {}
70
self._routeIDs = []
71
self._calibRoutes = checkDirOpen(collectFile)
72
print("<routes>", file=self._calibRoutes)
73
self._edgeCountFile = edgeCountFile
74
self._pythonEdgeFile = pythonEdgeFile
75
self._collectAll = collectAll
76
77
def addEdge(self, edge):
78
dirName = ""
79
if len(edge) > 2:
80
dirName = edge[:2]
81
if edge[0] == "-":
82
dirName = edge[1:3]
83
fileName = os.path.join(os.path.dirname(self._calibRoutes.name), dirName, edge)
84
f = checkDirOpen(fileName)
85
f.write(' <routeDistribution id="routedist_%s" ' % edge)
86
f.close()
87
self._routeDistributions[edge] = fileName
88
89
def startElement(self, name, attrs):
90
if name == 'route':
91
self._routeString = ''
92
if 'edges' in attrs:
93
self._routeString = attrs['edges']
94
95
def characters(self, content):
96
self._routeString += content
97
98
def endElement(self, name):
99
if name == 'route':
100
self._routeOccurrences[self._routeString] += 1
101
102
def closeAll(self):
103
"""build edge distributions from self._routeOccurrences"""
104
# build distributions
105
# edge -> (route -> prob)
106
edgeCount = defaultdict(lambda: 0)
107
routeProbs = defaultdict(dict)
108
numRoutesTotal = 0
109
for index, (edgeString, count) in enumerate(self._routeOccurrences.items()):
110
edges = edgeString.split()
111
routeID = 'r%s' % index
112
numRoutesTotal += count
113
print(' <route id="%s" edges="%s"/>' % (routeID, ' '.join(edges)), file=self._calibRoutes)
114
for edge in edges:
115
edgeCount[edge] += count
116
if self._collectAll and edge not in self._routeDistributions:
117
self.addEdge(edge)
118
if edge in self._routeDistributions:
119
routeProbs[edge][routeID] = count
120
print(("writing distributions for %s routes (%s unique)" % (
121
numRoutesTotal, len(self._routeOccurrences))))
122
# write distributions
123
for edge, filename in self._routeDistributions.items():
124
if edge in routeProbs:
125
with open(filename, 'a') as f:
126
print(('routes="%s" probabilities="%s"/>' % (
127
' '.join(routeProbs[edge].keys()),
128
' '.join(map(str, routeProbs[edge].values())))), file=f)
129
else:
130
print("Warning! No routes for %s." % edge, file=sys.stderr)
131
os.remove(filename)
132
print("</routes>", file=self._calibRoutes)
133
self._calibRoutes.close()
134
135
if self._edgeCountFile:
136
edgeCountOut = checkDirOpen(self._edgeCountFile)
137
print("<netstats>", file=edgeCountOut)
138
print(' <interval begin="0" end="%s">' % (24*3600), file=edgeCountOut)
139
for edge, weight in edgeCount.items():
140
print(' <edge id="%s" traveltime="%s"/>' % (edge, weight), file=edgeCountOut)
141
print(' </interval>', file=edgeCountOut)
142
print("</netstats>", file=edgeCountOut)
143
edgeCountOut.close()
144
if self._pythonEdgeFile:
145
pythonOut = checkDirOpen(self._pythonEdgeFile, 'wb')
146
pickle.dump(set(edgeCount.keys()), pythonOut)
147
pythonOut.close()
148
149
150
def splitFiles(routeFiles, typesFile, routesPrefix, step, verbose, modifyID, safactor, sufactor):
151
if verbose:
152
print("Writing types to file", os.path.basename(typesFile))
153
print("... in dir", os.path.dirname(typesFile), "TEXTTEST_IGNORE")
154
vtypes = checkDirOpen(typesFile)
155
print("""<vtypes>
156
<vType id="PKW" accel="2.6" decel="4.5" sigma="0.5" length="7" maxspeed="41.6" color="0,1,0"/>
157
<vType id="LKW" accel="2.6" decel="4.5" sigma="0.5" length="15" maxspeed="25" color="1,0,0"/>""", file=vtypes)
158
currentTime = 0
159
out = {"mofr": None, "sa": None, "so": None}
160
prefix = {"mofr": routesPrefix, "sa": None, "so": None}
161
factor = {"mofr": 1.0, "sa": safactor, "so": sufactor}
162
if safactor > 0.0:
163
prefix["sa"] = routesPrefix.replace("mofr", "sa")
164
if sufactor > 0.0:
165
prefix["so"] = routesPrefix.replace("mofr", "so")
166
files = []
167
sortedDeparts = []
168
pattern = re.compile(u'depart="([^"]+)"')
169
# pattern = re.compile('<vehicle.*depart="([0-9]+(\.[0-9]*)?)"')
170
for routesIn in routeFiles:
171
if verbose:
172
print("Reading routes from", routesIn)
173
f = sumolib.openz(routesIn)
174
while True:
175
pos = f.tell()
176
line = f.readline()
177
if not line:
178
break
179
match = pattern.search(line)
180
if match:
181
entry = (float(match.group(1)), len(files), pos)
182
sortedDeparts.insert(bisect.bisect(sortedDeparts, entry), entry)
183
elif '<vtype' in line:
184
print("Warning. Route files use outdated tag 'vtype'")
185
print(line, file=vtypes)
186
elif '<vType' in line:
187
print(line, file=vtypes)
188
files.append(f)
189
for depart, idx, pos in sortedDeparts:
190
f = files[idx]
191
f.seek(pos)
192
line = f.readline().rstrip()
193
while depart >= currentTime or not out["mofr"]:
194
for day in out.keys():
195
if out[day]:
196
print("</routes>", file=out[day])
197
out[day].close()
198
if prefix[day]:
199
routeFilename = prefix[day] + "%s.rou.xml" % currentTime
200
if verbose:
201
print("Writing file", os.path.basename(routeFilename))
202
print("... in dir", os.path.dirname(routeFilename), "TEXTTEST_IGNORE")
203
out[day] = checkDirOpen(routeFilename)
204
print("<routes>", file=out[day])
205
currentTime += step
206
if modifyID:
207
line = re.sub('id="([^"]*)"', 'id="\\1_%s"' % idx, line)
208
nextLine = ""
209
while "</vehicle>" not in nextLine:
210
nextLine = f.readline().rstrip()
211
if nextLine.strip():
212
line += "\n" + nextLine
213
for day in out.keys():
214
if out[day] and random.random() < factor[day]:
215
print(line, file=out[day])
216
for day in out.keys():
217
if out[day]:
218
print("</routes>", file=out[day])
219
out[day].close()
220
print("</vtypes>", file=vtypes)
221
vtypes.close()
222
for f in files:
223
f.close()
224
225
226
class DepartChanger(handler.ContentHandler):
227
def __init__(self, prefix, beg):
228
self._offset = 86400
229
self._indent = ""
230
self._ofile = open("%s%s.rou.xml" % (prefix, beg+self._offset), "w")
231
parser = make_parser()
232
parser.setContentHandler(self)
233
parser.parse("%s%s.rou.xml" % (prefix, beg))
234
self._ofile.close()
235
236
def startElement(self, name, attrs):
237
print("%s<%s" % (self._indent, name), end=' ', file=self._ofile)
238
for attr in attrs.keys():
239
if attr == "depart":
240
print('%s="%s"' % (attr, float(attrs[attr])+self._offset), end=' ', file=self._ofile)
241
else:
242
print('%s="%s"' % (attr, attrs[attr]), end=' ', file=self._ofile)
243
print(">", file=self._ofile)
244
self._indent += " "
245
246
def endElement(self, name):
247
self._indent = self._indent[:-4]
248
print("%s</%s>" % (self._indent, name), file=self._ofile)
249
250
def characters(self, chars):
251
self._ofile.write(chars)
252
253
254
def main(args=None):
255
ap = sumolib.options.ArgumentParser(usage="usage: %prog [options] <routefiles>")
256
ap.add_argument("-f", "--detector-file", dest="detfile", category="input", type=ap.file,
257
help="read detectors from FILE", metavar="FILE")
258
ap.add_argument("-v", "--verbose", action="store_true", dest="verbose",
259
default=False, help="tell me what you are doing")
260
ap.add_argument("-s", "--step", dest="step", type=int, default=900,
261
help="time split step in seconds")
262
ap.add_argument("-n", "--next-day", dest="nextday", type=int, default=2700,
263
help="how far to go into the next day in seconds")
264
ap.add_argument("-t", "--types-file", dest="typesfile", default="vehtypes.xml",
265
help="write vehicle types to FILE", metavar="FILE")
266
ap.add_argument("--route-collection", dest="collectfile", category="output", type=ap.route_file,
267
help="write route collection for the distributions to FILE", metavar="FILE")
268
ap.add_argument("-o", "--routes-prefix", dest="routesprefix", default="validate/validate_mofr_",
269
help="let time splitted route files start with PREFIX", metavar="PREFIX")
270
ap.add_argument("-e", "--edge-count", dest="edgecount",
271
help="dump number of routes for each edge to FILE", metavar="FILE")
272
ap.add_argument("-p", "--pickle-edges", dest="pickleedge",
273
help="dump used edges as pickled set to FILE", metavar="FILE")
274
ap.add_argument("-a", "--saturday-factor", dest="safact", type=float, default=0.,
275
help="generate saturday files scaled down by FACTOR", metavar="FACTOR")
276
ap.add_argument("-u", "--sunday-factor", dest="sufact", type=float, default=0.,
277
help="generate sunday files scaled down by FACTOR", metavar="FACTOR")
278
ap.add_argument("-m", "--modify-id", action="store_true", dest="modifyid",
279
default=False, help="try to make vehicle and route ids unique")
280
ap.add_argument("routefiles", category="input", type=ap.file_list,
281
nargs="+", help="list of route files")
282
options = ap.parse_args(args=args)
283
tempPrefix = options.routesprefix
284
reader = None
285
if options.detfile:
286
if not options.collectfile:
287
options.collectfile = "calibrator_routes.rou.xml"
288
if options.verbose:
289
print("Reading detectors")
290
reader = RouteReader(options.collectfile, options.edgecount, options.pickleedge)
291
detReader = DetectorReader(options.detfile, laneMap=LaneMap())
292
for edge, _ in detReader.getGroups():
293
reader.addEdge(edge)
294
elif options.collectfile:
295
reader = RouteReader(options.collectfile, options.edgecount, options.pickleedge, True)
296
splitFiles(options.routefiles, options.typesfile, tempPrefix, options.step,
297
options.verbose, options.modifyid, options.safact, options.sufact)
298
if reader:
299
parser = make_parser()
300
parser.setContentHandler(reader)
301
if options.detfile:
302
parser.parse(options.detfile)
303
for time in range(0, 24*3600, options.step):
304
routeFilename = tempPrefix+"%s.rou.xml" % time
305
if os.path.exists(routeFilename):
306
if options.verbose:
307
print("Parsing file", os.path.basename(routeFilename))
308
print("... in dir", os.path.dirname(routeFilename), "TEXTTEST_IGNORE")
309
parser.parse(routeFilename)
310
reader.closeAll()
311
for i in range(0, options.nextday, options.step):
312
DepartChanger(options.routesprefix, i)
313
if options.safact > 0.0:
314
DepartChanger(options.routesprefix.replace("mofr", "sa"), i)
315
if options.sufact > 0.0:
316
DepartChanger(options.routesprefix.replace("mofr", "so"), i)
317
318
319
if __name__ == '__main__':
320
sys.path.append(os.path.join(os.path.dirname(sys.argv[0]), "..", "loop"))
321
# from detector import DetectorReader
322
main()
323
324