Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/tools/route/checkReversals.py
169673 views
1
#!/usr/bin/env python
2
# Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
# Copyright (C) 2014-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 checkReversals.py
15
# @author Jakob Erdmann
16
# @date 2025-04-16
17
18
"""
19
Check for reversals in loaded routes
20
"""
21
22
from __future__ import absolute_import
23
from __future__ import print_function
24
25
import os
26
import sys
27
from collections import defaultdict
28
29
if 'SUMO_HOME' in os.environ:
30
sys.path.append(os.path.join(os.environ['SUMO_HOME'], 'tools'))
31
from sumolib.statistics import Statistics
32
import sumolib # noqa
33
else:
34
sys.exit("please declare environment variable 'SUMO_HOME'")
35
36
37
def get_options(args=None):
38
ap = sumolib.options.ArgumentParser(description="Sample routes to match counts")
39
ap.add_argument("-n", "--network", category="input", required=True, type=ap.net_file,
40
help="sumo network to use")
41
ap.add_argument("-r", "--route-files", category='input', dest="routeFiles", required=True,
42
help="Input route files")
43
ap.add_argument("-o", "--output-file", category='output', dest="output",
44
help="Output file for info on each reversing vehicle")
45
options = ap.parse_args(args=args)
46
options.routeFiles = options.routeFiles.split(',')
47
return options
48
49
50
def main(options):
51
revByVeh = Statistics("Reversals by vehicle")
52
revByEdge = Statistics("Reversals by edge")
53
nRevByEdge = defaultdict(lambda: 0)
54
routes = {} # id -> edges
55
nVehs = 0
56
57
outf = None
58
if options.output:
59
outf = sumolib.openz(options.output, 'w')
60
sumolib.xml.writeHeader(outf, "$Id$", "reversals", options=options, rootAttrs=None)
61
62
net = sumolib.net.readNet(options.network)
63
for routefile in options.routeFiles:
64
lastEdges = None
65
for elem in sumolib.xml.parse(routefile, ['vehicle', 'flow', 'route'], heterogeneous=True):
66
if elem.name == 'route':
67
lastEdges = [net.getEdge(e) for e in elem.edges.split()]
68
if elem.id:
69
routes[elem.id] = lastEdges
70
else:
71
# embedded route
72
continue
73
else:
74
nVehs += 1
75
if type(elem.route) is str:
76
edges = routes[elem.route]
77
else:
78
edges = lastEdges
79
reversals = []
80
for e, e2 in zip(edges[:-1], edges[1:]):
81
if e.getBidi() == e2:
82
reversals.append(e.getID())
83
nRevByEdge[e.getID()] += 1
84
if reversals:
85
revByVeh.add(len(reversals), elem.id)
86
if outf:
87
outf.write(' <%s id="%s" reversalEdges="%s"/>\n' % (
88
elem.name, elem.id, " ".join(reversals)))
89
for e, n in nRevByEdge.items():
90
revByEdge.add(n, e)
91
92
if routes:
93
print("Loaded %s named routes" % len(routes))
94
print("Loaded %s vehicles" % nVehs)
95
print(revByVeh)
96
print(revByEdge)
97
98
if outf:
99
outf.write('</reversals>\n')
100
outf.close()
101
102
103
if __name__ == "__main__":
104
main(get_options())
105
106