Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/tools/runSeeds.py
169660 views
1
#!/usr/bin/env python
2
# Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
# Copyright (C) 2008-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 runSeeds.py
15
# @author Jakob Erdmann
16
# @date 2022-04-30
17
18
"""
19
This script executes a config repeatedly with different seeds
20
"""
21
from __future__ import absolute_import
22
from __future__ import print_function
23
import os
24
import sys
25
import subprocess
26
import shutil
27
from threading import Thread
28
if sys.version_info.major < 3:
29
from Queue import Queue
30
else:
31
from queue import Queue
32
33
if 'SUMO_HOME' in os.environ:
34
sys.path.append(os.path.join(os.environ['SUMO_HOME'], 'tools'))
35
import sumolib # noqa
36
37
38
def get_options(args=None):
39
ap = sumolib.options.ArgumentParser()
40
ap.add_option("-v", "--verbose", action="store_true", default=False,
41
help="tell me what you are doing")
42
ap.add_option("-k", "--configuration", category="input", metavar="FILE", required=True,
43
type=ap.sumoconfig_file_list,
44
help="configuration to run or comma-separated list of configurations")
45
ap.add_option("-a", "--application", metavar="FILE",
46
help="application to run or comma-separated list of applications")
47
ap.add_option("-p", "--output-prefix", default="SEED.", dest="prefix",
48
help="output prefix",)
49
ap.add_option("--no-folders", action="store_true", category="output", default=False, dest="noFolders",
50
help=("do not create folders to distinguish multiple configurations or applications" +
51
"but use prefixes instead"))
52
ap.add_option("--seeds", default="0:10",
53
help="which seeds to run")
54
ap.add_option("--threads", type=int, default=1,
55
help="number of parallel processes")
56
# parse options
57
options, unknown_args = ap.parse_known_args(args=args)
58
options.unknown_args = unknown_args
59
60
if ":" in options.seeds:
61
options.seeds = range(*map(int, options.seeds.split(":")))
62
else:
63
options.seeds = list(map(int, options.seeds.split(",")))
64
65
if options.application is None:
66
options.application = [sumolib.checkBinary("sumo")]
67
else:
68
options.application = options.application.split(',')
69
for app in options.application:
70
if hasattr(shutil, "which") and not shutil.which(app):
71
sys.stderr.write("Error: application '%s' not found\n" % app)
72
sys.exit()
73
74
options.configuration = options.configuration.split(',')
75
for cfg in options.configuration:
76
if not os.path.exists(cfg):
77
sys.stderr.write("Error: configuration '%s' not found\n" % cfg)
78
sys.exit()
79
80
if "SEED" not in options.prefix:
81
sys.stderr.write("Warning: --output-prefix should contain 'SEED' to prevent overwriting\n")
82
83
return options
84
85
86
def getUniqueFolder(options, app, cfg, folders):
87
key = []
88
if len(options.application) > 1:
89
key.append(os.path.basename(app))
90
if len(options.configuration) > 1:
91
key.append(os.path.basename(cfg))
92
if not key:
93
return ""
94
95
folder = '_'.join(key)
96
if folder in folders:
97
i = 0
98
folder = '_'.join(key + [str(i)])
99
while folder in folders:
100
i += 1
101
folder = '_'.join(key + [str(i)])
102
103
folders.add(folder)
104
if not options.noFolders and not os.path.exists(folder):
105
os.makedirs(folder)
106
return folder
107
108
109
def getCommExtensionLength(names):
110
if not names or len(names) == 1:
111
return 0
112
common = reversed(names[0])
113
for n in names[1:]:
114
common2 = []
115
for c1, c2 in zip(common, reversed(n)):
116
if c1 == c2:
117
common2.append(c1)
118
else:
119
break
120
common = ''.join(common2)
121
return len(common)
122
123
124
def main(options):
125
q = Queue()
126
127
def runSim():
128
while True:
129
app, cfg, seed, folder = q.get()
130
prefix = options.prefix.replace("SEED", str(seed))
131
if folder:
132
if options.noFolders:
133
prefix = "%s_%s" % (folder, prefix)
134
else:
135
prefix = os.path.join(folder, prefix)
136
if options.verbose:
137
print("running seed %s" % seed)
138
args = [app,
139
'-c', cfg,
140
'--seed', str(seed),
141
'--output-prefix', prefix]
142
subprocess.call(args + options.unknown_args)
143
q.task_done()
144
145
for i in range(options.threads):
146
t = Thread(target=runSim)
147
t.daemon = True
148
t.start()
149
150
folders = set()
151
152
cEL = getCommExtensionLength(options.configuration)
153
for app in options.application:
154
for cfg in options.configuration:
155
folder = getUniqueFolder(options, app, cfg[:-cEL], folders)
156
for seed in options.seeds:
157
q.put((app, cfg, seed, folder))
158
q.join()
159
160
161
if __name__ == "__main__":
162
if not main(get_options()):
163
sys.exit(1)
164
165