Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/tools/output/generateDetectors.py
169674 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 generateDetectors.py
15
# @author Jakob Erdmann
16
# @date 2025-04-13
17
18
from __future__ import absolute_import
19
from __future__ import print_function
20
21
import os
22
import sys
23
import random
24
25
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
26
import sumolib # noqa
27
from sumolib.options import ArgumentParser # noqa
28
from sumolib.miscutils import openz # noqa
29
30
SHORT_NAMES = {
31
'E1': 'inductionLoop',
32
'E1I': 'instantInductionLoop',
33
'E2': 'laneAreaDetector',
34
# 'E3': 'multiEntryExitDetector'
35
}
36
37
NEED_EXTENT = ['laneAreaDetector',
38
# 'multiEntryExitDetector'
39
]
40
41
42
def get_options(args=None):
43
ap = ArgumentParser(description="Generate detectors on selected network edges")
44
ap.add_option("-n", "--net-file", dest="net_file", type=ap.net_file, required=True,
45
help="Network file to work with. Mandatory.")
46
ap.add_option("-o", "--output", required=True, type=ap.additional_file,
47
help="The name of the file to write the detectors to")
48
ap.add_option("--period", type=int, default=60,
49
help="Aggregation period in s")
50
ap.add_option("--prefix", default="",
51
help="prefix for the detectors ids")
52
ap.add_option("-r", "--results-file", dest="results", type=ap.file, default="det.out.xml",
53
help="The name of the file the detectors write their output into. Defaults to det.out.xml.")
54
ap.add_option("--relpos", default=0.5,
55
help="relative detector position along the edge [0,1] or 'random'")
56
ap.add_option("--probability", type=float, default=1,
57
help="build detector with the given probability ]0, 1] (lanewise)")
58
ap.add_option("--edge-probability", type=float, default=1, dest="edgeProbability",
59
help="build detector with the given probability ]0, 1] (edgewise)")
60
ap.add_option("-t", "--detector-type", dest="dType", default="inductionLoop",
61
help="one of %s or the corresponding shortcut %s" % (
62
list(SHORT_NAMES.values()),
63
list(SHORT_NAMES.keys())))
64
ap.add_option("--vclass", default="passenger",
65
help="only place detectors on lanes that permit the given vehicle class")
66
ap.add_option("--length", type=float,
67
help="Set length for detector types that support it")
68
ap.add_option("-s", "--seed", type=int, default=42, help="random seed")
69
ap.add_option("-v", "--verbose", action="store_true", default=False,
70
help="tell me what you are doing")
71
options = ap.parse_args(args=args)
72
73
options.dType = SHORT_NAMES.get(options.dType, options.dType)
74
75
if options.dType not in SHORT_NAMES.values():
76
sys.exit("Unsupported value '%s' for option --detector-type ")
77
78
if options.relpos is not None:
79
try:
80
options.relpos = max(0, min(1, float(options.relpos)))
81
options.getRelpos = lambda lane: lane.getLength() * options.relpos
82
except ValueError:
83
if options.relpos == 'random':
84
options.getRelpos = lambda lane: lane.getLength() * random.random()
85
else:
86
sys.exit("option --relpos must be set to 'random' or to a float value from [0,1]")
87
88
if options.length and options.dType == "instantInductionLoop":
89
sys.exit("Unsupported option --length for detector-type %s" % options.dType)
90
91
return options
92
93
94
def main(options):
95
random.seed(options.seed)
96
97
if options.verbose:
98
print("Reading net '%s'..." % options.net_file)
99
net = sumolib.net.readNet(options.net_file)
100
101
if options.verbose:
102
print("Generating detectors...")
103
104
numWritten = 0
105
with openz(options.output, 'w') as fout:
106
sumolib.writeXMLHeader(fout, "$Id$", "additional", options=options)
107
period = '' if options.dType == "instantInductionLoop" else 'period="%s" ' % options.period
108
length = '' if options.length is None else 'length="%s" ' % options.length
109
endPos = ''
110
friendlyPos = ''
111
if length != '':
112
friendlyPos = 'friendlyPos="true" '
113
elif options.dType in NEED_EXTENT:
114
endPos = 'endPos="-1" '
115
116
for edge in net.getEdges():
117
if options.edgeProbability < 1 and random.random() > options.edgeProbability:
118
continue
119
for lane in edge.getLanes():
120
if not lane.allows(options.vclass):
121
continue
122
if options.probability < 1 and random.random() > options.probability:
123
continue
124
numWritten += 1
125
fout.write(' <%s id="%s%s" lane="%s" pos="%s" %s%s%s%sfile="%s"/>\n' % (
126
options.dType,
127
options.prefix, lane.getID(),
128
lane.getID(),
129
"%.2f" % options.getRelpos(lane),
130
period, length, endPos, friendlyPos,
131
options.results))
132
133
fout.write('</additional>\n')
134
135
if options.verbose:
136
print("Wrote %s detectors." % numWritten)
137
138
139
if __name__ == "__main__":
140
main(get_options())
141
142