Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/tools/route/checkStopOrder.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 checkStopOrder.py
15
# @author Jakob Erdmann
16
# @date 2020-03-19
17
18
"""
19
Check order of arriving and leaving vehicles at stopping places.
20
Report if vehicles change their order at a stop (a vehicle arrives later but leaves earlier)
21
Also Reports if vehicle stop times are inconsistent with itself (times jump backwards)
22
"""
23
24
from __future__ import absolute_import
25
from __future__ import print_function
26
27
import os
28
import sys
29
from collections import defaultdict
30
import fnmatch
31
32
if 'SUMO_HOME' in os.environ:
33
sys.path.append(os.path.join(os.environ['SUMO_HOME'], 'tools'))
34
import sumolib # noqa
35
from sumolib.miscutils import parseTime, humanReadableTime
36
else:
37
sys.exit("please declare environment variable 'SUMO_HOME'")
38
39
40
def get_options(args=None):
41
parser = sumolib.options.ArgumentParser(description="Sample routes to match counts")
42
parser.add_argument("-r", "--route-files", category='input', dest="routeFiles",
43
help="Input route file")
44
parser.add_argument("-H", "--human-readable-time", dest="hrTime", action="store_true", default=False,
45
help="Write time values as hour:minute:second or day:hour:minute:second rathern than seconds")
46
parser.add_argument("-p", "--ignore-parking", dest="ignoreParking", action="store_true", default=False,
47
help="Do not report conflicts with parking vehicles")
48
parser.add_argument("--until-from-duration", action="store_true", default=False, dest="untilFromDuration",
49
help="Use stop arrival+duration instead of 'until' to compute overtaking")
50
parser.add_argument("--filter-ids", category="processing", dest="filterIDs",
51
help="only consider stops for vehicles in the given list of ids")
52
parser.add_argument("--stop-table", dest="stopTable",
53
help="Print timetable information for the given list of busStops")
54
55
options = parser.parse_args(args=args)
56
if options.routeFiles:
57
options.routeFiles = options.routeFiles.split(',')
58
else:
59
print("Argument --route-files is mandatory", file=sys.stderr)
60
sys.exit()
61
62
if options.filterIDs:
63
options.filterIDs = set(options.filterIDs.split(','))
64
65
return options
66
67
68
def main(options):
69
70
tf = humanReadableTime if options.hrTime else lambda x: x
71
72
stopTimes = defaultdict(list)
73
for routefile in options.routeFiles:
74
for vehicle in sumolib.xml.parse(routefile, ['vehicle', 'trip'], heterogeneous=True):
75
if vehicle.stop is None:
76
continue
77
if options.filterIDs and vehicle.id not in options.filterIDs:
78
continue
79
lastUntil = None
80
stops = list(vehicle.stop)
81
for i, stop in enumerate(stops):
82
isParking = stop.parking in ["true", "True", "1"]
83
if isParking and options.ignoreParking:
84
continue
85
if options.untilFromDuration:
86
if stop.arrival:
87
until = parseTime(stop.arrival) + parseTime(stop.duration)
88
else:
89
print("Cannot compute 'until' for Vehicle %s because 'arrival' is not defined" %
90
vehicle.id, file=sys.stderr)
91
else:
92
until = parseTime(stop.until)
93
arrival = parseTime(stop.arrival) if stop.arrival else until - parseTime(stop.duration)
94
if until < arrival:
95
print("Vehicle %s has 'until' before 'arrival' (%s, %s) at stop %s" % (
96
vehicle.id, tf(arrival), tf(until), stop.busStop), file=sys.stderr)
97
# comparing lastUntil with arrival makes sense logically but
98
# produces unnecessary warnings when using until times to encode small delays
99
#
100
# if lastUntil is not None and arrival < lastUntil:
101
# print("Vehicle %s has 'arrival' (%s) before previous 'until' (%s) at stop %s" % (
102
# vehicle.id, tf(arrival), tf(lastUntil), stop.busStop), file=sys.stderr)
103
if lastUntil is not None and until < lastUntil:
104
print("Vehicle %s has 'until' (%s) before previous 'until' (%s) at stop %s" % (
105
vehicle.id, tf(until), tf(lastUntil), stop.busStop), file=sys.stderr)
106
lastUntil = until
107
flags = ''
108
if isParking:
109
flags += "p"
110
if i == 0:
111
flags += "F"
112
if i == len(stops) - 1:
113
flags += "L"
114
if float(stop.getAttributeSecure("speed", "0")) > 0:
115
flags += "w"
116
stopTimes[stop.busStop].append([arrival, until, vehicle.id,
117
stop.getAttributeSecure("tripId", ""),
118
stop.getAttributeSecure("started", ""),
119
stop.getAttributeSecure("ended", ""),
120
flags
121
])
122
123
for stop, times in stopTimes.items():
124
times.sort()
125
for i, (a, u, v, t, s, e, f) in enumerate(times):
126
for i2, (a2, u2, v2, t2, s2, e2, f2) in enumerate(times[i + 1:]):
127
if u2 <= u:
128
times[i][-1] += "o"
129
times[i + 1 + i2][-1] += "O"
130
print("Vehicle %s (%s, %s) overtakes %s (%s, %s) at stop %s" % (
131
v2, tf(a2), tf(u2), v, tf(a), tf(u), stop), file=sys.stderr)
132
133
if options.stopTable:
134
times = []
135
stopIDs = []
136
for stopID in options.stopTable.split(','):
137
if stopID in stopTimes:
138
stopIDs.append(stopID)
139
elif "*" in stopID:
140
for candID in sorted(stopTimes.keys()):
141
if fnmatch.fnmatch(candID, stopID):
142
stopIDs.append(candID)
143
else:
144
print("No vehicle stops at busStop '%s' found" % stopID, file=sys.stderr)
145
146
for stopID in stopIDs:
147
times += [t + [stopID] for t in stopTimes[stopID]]
148
149
if stopIDs:
150
print("# busStop: %s" % ','.join(stopIDs))
151
if len(stopIDs) == 1:
152
print("arrival\tuntil\tveh\ttripId\tstarted\tended\tflags")
153
for a, u, v, t, s, e, f, i in sorted(times):
154
print("%s\t%s\t%s\t%s\t%s\t%s\t%s" % (tf(a), tf(u), v, t, s, e, f))
155
else:
156
print("arrival\tuntil\tveh\ttripId\tstarted\tended\tflags\tbusStop")
157
for a, u, v, t, s, e, f, i in sorted(times):
158
print("%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s" % (tf(a), tf(u), v, t, s, e, f, i))
159
160
161
if __name__ == "__main__":
162
main(get_options())
163
164