Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/tools/output/instantOutDiff.py
169674 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 instantOutDiff.py
16
# @author Jakob Erdmann
17
# @date 2025-04-13
18
19
"""
20
Compare differences between instantInductionLoop output files
21
"""
22
23
from __future__ import absolute_import
24
from __future__ import print_function
25
import os
26
import sys
27
import bisect
28
from collections import defaultdict
29
sys.path.append(os.path.join(os.environ["SUMO_HOME"], 'tools'))
30
import sumolib # noqa
31
from sumolib.miscutils import Statistics, parseTime # noqa
32
from sumolib.options import ArgumentParser # noqa
33
from sumolib.net import lane2edge # noqa
34
35
36
def get_options(args=None):
37
argParser = ArgumentParser()
38
argParser.add_argument("orig", help="the first tripinfo file")
39
argParser.add_argument("new", help="the second tripinfo file")
40
argParser.add_argument("output", help="the output file")
41
argParser.add_argument("--event-type", dest="eType", default="leave",
42
help="Which type of detection event to compare (enter, stay, leave)")
43
argParser.add_argument("--combine-lanes", action="store_true", dest="combineLanes",
44
default=False, help="do not distinguish detectors by lane id")
45
argParser.add_argument("--filter-ids", dest="filterIDs",
46
help="only use detector ids with the given substring")
47
options = argParser.parse_args(args=args)
48
return options
49
50
51
def parseTimes(fname, options):
52
detTimes = defaultdict(list) # detID -> [time1, time2, ...]
53
for event in sumolib.xml.parse_fast(fname, 'instantOut', ['id', 'time', 'state']):
54
if event.state == options.eType:
55
detID = event.id
56
if options.combineLanes:
57
detID = lane2edge(detID)
58
detTimes[detID].append(parseTime(event.time))
59
return detTimes
60
61
62
def write_diff(options):
63
origTimes = parseTimes(options.orig, options)
64
newTimes = parseTimes(options.new, options)
65
66
countMismatch = Statistics('Count mismatch')
67
absCountMismatch = Statistics('Count mismatch (absolute)')
68
totalTimeMismatch = Statistics('Avg Time mismatch')
69
70
with sumolib.openz(options.output, 'w') as outf:
71
sumolib.writeXMLHeader(outf, "$Id$", "instantOutDiff", options=options, rootAttrs=None)
72
73
for det, times in origTimes.items():
74
if det in newTimes:
75
timeMismatch = Statistics(det)
76
times2 = newTimes[det]
77
iMax = len(times2)
78
for t in times:
79
i = bisect.bisect_left(times2, t)
80
delta = 1e100
81
if i > 0:
82
delta = min(delta, abs(t - times2[i - 1]))
83
if i < iMax:
84
delta = min(delta, abs(t - times2[i]))
85
timeMismatch.add(delta, t)
86
totalTimeMismatch.add(delta, "%s,%s" % (det, t))
87
countMismatch.add(len(times) - len(times2), det)
88
absCountMismatch.add(abs(len(times) - len(times2)), det)
89
outf.write(timeMismatch.toXML())
90
else:
91
countMismatch.add(len(times), det)
92
absCountMismatch.add(len(times), det)
93
94
outf.write('</instantOutDiff>\n')
95
96
print(countMismatch)
97
print(absCountMismatch)
98
print(totalTimeMismatch)
99
100
101
if __name__ == "__main__":
102
options = get_options()
103
write_diff(options)
104
105