mirror of
https://github.com/Ahp06/SUMO_Emissions.git
synced 2024-11-21 19:16:30 +00:00
Merge pull request #10 from Ahp06/sumo-config-generator
An urban traffic generator to generate SUMO scenarios from an OpenStreetMap map with the following options: different vehicle classes (passenger, bus, …) with a given density in veh/km/h a random seed, for reproducibility a given length
This commit is contained in:
commit
1d5c0ec576
116
.gitignore
vendored
Normal file
116
.gitignore
vendored
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
# Byte-compiled / optimized / DLL files
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
|
||||||
|
# C extensions
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Distribution / packaging
|
||||||
|
.Python
|
||||||
|
build/
|
||||||
|
develop-eggs/
|
||||||
|
dist/
|
||||||
|
downloads/
|
||||||
|
eggs/
|
||||||
|
.eggs/
|
||||||
|
lib/
|
||||||
|
lib64/
|
||||||
|
parts/
|
||||||
|
sdist/
|
||||||
|
var/
|
||||||
|
wheels/
|
||||||
|
share/python-wheels/
|
||||||
|
*.egg-info/
|
||||||
|
.installed.cfg
|
||||||
|
*.egg
|
||||||
|
MANIFEST
|
||||||
|
|
||||||
|
# PyInstaller
|
||||||
|
# Usually these files are written by a python script from a template
|
||||||
|
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||||
|
*.manifest
|
||||||
|
*.spec
|
||||||
|
|
||||||
|
# Installer logs
|
||||||
|
pip-log.txt
|
||||||
|
pip-delete-this-directory.txt
|
||||||
|
|
||||||
|
# Unit test / coverage reports
|
||||||
|
htmlcov/
|
||||||
|
.tox/
|
||||||
|
.nox/
|
||||||
|
.coverage
|
||||||
|
.coverage.*
|
||||||
|
.cache
|
||||||
|
nosetests.xml
|
||||||
|
coverage.xml
|
||||||
|
*.cover
|
||||||
|
.hypothesis/
|
||||||
|
.pytest_cache/
|
||||||
|
|
||||||
|
# Translations
|
||||||
|
*.mo
|
||||||
|
*.pot
|
||||||
|
|
||||||
|
# Django stuff:
|
||||||
|
*.log
|
||||||
|
local_settings.py
|
||||||
|
db.sqlite3
|
||||||
|
|
||||||
|
# Flask stuff:
|
||||||
|
instance/
|
||||||
|
.webassets-cache
|
||||||
|
|
||||||
|
# Scrapy stuff:
|
||||||
|
.scrapy
|
||||||
|
|
||||||
|
# Sphinx documentation
|
||||||
|
docs/_build/
|
||||||
|
|
||||||
|
# PyBuilder
|
||||||
|
target/
|
||||||
|
|
||||||
|
# Jupyter Notebook
|
||||||
|
.ipynb_checkpoints
|
||||||
|
|
||||||
|
# IPython
|
||||||
|
profile_default/
|
||||||
|
ipython_config.py
|
||||||
|
|
||||||
|
# pyenv
|
||||||
|
.python-version
|
||||||
|
|
||||||
|
# celery beat schedule file
|
||||||
|
celerybeat-schedule
|
||||||
|
|
||||||
|
# SageMath parsed files
|
||||||
|
*.sage.py
|
||||||
|
|
||||||
|
# Environments
|
||||||
|
.env
|
||||||
|
.venv
|
||||||
|
env/
|
||||||
|
venv/
|
||||||
|
ENV/
|
||||||
|
env.bak/
|
||||||
|
venv.bak/
|
||||||
|
|
||||||
|
# Spyder project settings
|
||||||
|
.spyderproject
|
||||||
|
.spyproject
|
||||||
|
|
||||||
|
# Rope project settings
|
||||||
|
.ropeproject
|
||||||
|
|
||||||
|
# mkdocs documentation
|
||||||
|
/site
|
||||||
|
|
||||||
|
# mypy
|
||||||
|
.mypy_cache/
|
||||||
|
.dmypy.json
|
||||||
|
dmypy.json
|
||||||
|
|
||||||
|
# Pyre type checker
|
||||||
|
.pyre/
|
||||||
|
|
284
sumo_project/configurator.py
Normal file
284
sumo_project/configurator.py
Normal file
@ -0,0 +1,284 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
if 'SUMO_HOME' in os.environ:
|
||||||
|
TOOLSDIR = os.path.join(os.environ['SUMO_HOME'], 'tools')
|
||||||
|
sys.path.append(TOOLSDIR)
|
||||||
|
else:
|
||||||
|
sys.exit("Please declare environment variable 'SUMO_HOME'")
|
||||||
|
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import datetime
|
||||||
|
import json
|
||||||
|
import logging
|
||||||
|
import shutil
|
||||||
|
import subprocess
|
||||||
|
import tempfile
|
||||||
|
import time
|
||||||
|
from sys import argv
|
||||||
|
from types import SimpleNamespace
|
||||||
|
from xml.etree import ElementTree
|
||||||
|
|
||||||
|
import randomTrips
|
||||||
|
import sumolib
|
||||||
|
|
||||||
|
# Absolute path of the directory the script is in
|
||||||
|
SCRIPTDIR = os.path.dirname(__file__)
|
||||||
|
TEMPLATEDIR = os.path.join(SCRIPTDIR, 'templates')
|
||||||
|
SUMOBIN = os.path.join(os.environ['SUMO_HOME'], 'bin')
|
||||||
|
|
||||||
|
# Init logger
|
||||||
|
logfile = os.path.join(SCRIPTDIR, f'files/logs/configurator_{datetime.datetime.utcnow().isoformat()}.log')
|
||||||
|
logging.basicConfig(
|
||||||
|
filename=logfile,
|
||||||
|
level=logging.DEBUG,
|
||||||
|
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
||||||
|
)
|
||||||
|
|
||||||
|
"""
|
||||||
|
Definition of vehicle classes.
|
||||||
|
See http://sumo.dlr.de/wiki/Definition_of_Vehicles,_Vehicle_Types,_and_Routes#Abstract_Vehicle_Class
|
||||||
|
"""
|
||||||
|
vehicle_classes = {
|
||||||
|
'passenger': {
|
||||||
|
'--vehicle-class': 'passenger',
|
||||||
|
'--vclass': 'passenger',
|
||||||
|
'--prefix': 'veh',
|
||||||
|
'--min-distance': 300,
|
||||||
|
'--trip-attributes': 'departLane="best"',
|
||||||
|
},
|
||||||
|
'bus': {
|
||||||
|
'--vehicle-class': 'bus',
|
||||||
|
'--vclass': 'bus',
|
||||||
|
'--prefix': 'bus',
|
||||||
|
},
|
||||||
|
'truck': {
|
||||||
|
'--vehicle-class': 'truck',
|
||||||
|
'--vclass': 'truck',
|
||||||
|
'--prefix': 'truck',
|
||||||
|
'--min-distance': 600,
|
||||||
|
'--trip-attributes': 'departLane="best"',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class RandomTripsGenerator:
|
||||||
|
def __init__(self, netpath, routepath, output, vclass, density, *flags, **opts):
|
||||||
|
self.vclass = vclass
|
||||||
|
self.density = density
|
||||||
|
self.options = {
|
||||||
|
# Default options
|
||||||
|
'--net-file': netpath,
|
||||||
|
'--output-trip-file': output,
|
||||||
|
'--route-file': routepath,
|
||||||
|
**opts
|
||||||
|
}
|
||||||
|
self.flags = [*flags]
|
||||||
|
edges = sumolib.net.readNet(netpath).getEdges()
|
||||||
|
self._init_trips(edges, vclass, density)
|
||||||
|
self.options.update(vehicle_classes[self.vclass])
|
||||||
|
|
||||||
|
def generate(self):
|
||||||
|
logging.info(f'Generating trips for vehicle class {self.vclass} with density of {self.density} veh/km/h')
|
||||||
|
randomTrips.main(randomTrips.get_options(dict_to_list(self.options) + self.flags))
|
||||||
|
|
||||||
|
def _init_trips(self, edges, vclass, density):
|
||||||
|
"""
|
||||||
|
:param edges: foo.rou.xml
|
||||||
|
:param density: vehicle/km/h
|
||||||
|
"""
|
||||||
|
# calculate the total length of the available lanes
|
||||||
|
length = 0.
|
||||||
|
for edge in edges:
|
||||||
|
if edge.allows(vclass):
|
||||||
|
length += edge.getLaneNumber() * edge.getLength()
|
||||||
|
|
||||||
|
logging.debug(f'density = {density}')
|
||||||
|
period = 3600 / (length / 1000) / density
|
||||||
|
logging.debug(f'Period computed for network : {period}, vclass={self.vclass}')
|
||||||
|
self.options.update({'-p': period})
|
||||||
|
|
||||||
|
|
||||||
|
class StoreDictKeyPair(argparse.Action):
|
||||||
|
def __call__(self, parser, namespace, values, option_string=None):
|
||||||
|
pairs = {}
|
||||||
|
for kv in values:
|
||||||
|
k, v = kv.split("=")
|
||||||
|
pairs[k] = v
|
||||||
|
setattr(namespace, self.dest, pairs)
|
||||||
|
|
||||||
|
|
||||||
|
def load_netconvert_template(osm_input, out_name):
|
||||||
|
netconfig = ElementTree.parse(os.path.join(TEMPLATEDIR, 'simul.netcfg'))
|
||||||
|
root = netconfig.getroot()
|
||||||
|
root.find('input/osm-files').set('value', osm_input)
|
||||||
|
root.find('output/output-file').set('value', f'{out_name}.net.xml')
|
||||||
|
root.find('report/log').set('value', f'{out_name}.netconvert.log')
|
||||||
|
return netconfig
|
||||||
|
|
||||||
|
|
||||||
|
def load_polyconvert_template(osm_file, type_file, scenario_name):
|
||||||
|
polyconfig = ElementTree.parse(os.path.join(TEMPLATEDIR, 'simul.polycfg'))
|
||||||
|
root = polyconfig.getroot()
|
||||||
|
root.find('input/osm-files').set('value', osm_file)
|
||||||
|
root.find('input/net-file').set('value', f'{scenario_name}.net.xml')
|
||||||
|
root.find('input/type-file').set('value', type_file)
|
||||||
|
root.find('output/output-file').set('value', f'{scenario_name}.poly.xml')
|
||||||
|
root.find('report/log').set('value', f'{scenario_name}.polyconvert.log')
|
||||||
|
return polyconfig
|
||||||
|
|
||||||
|
|
||||||
|
def load_sumoconfig_template(simulation_name, routefiles=(), generate_polygons=False, seed=None):
|
||||||
|
routefiles = routefiles or (f'{simulation_name}.rou.xml',)
|
||||||
|
sumoconfig = ElementTree.parse(os.path.join(TEMPLATEDIR, 'simul.sumocfg'))
|
||||||
|
root = sumoconfig.getroot()
|
||||||
|
root.find('input/net-file').set('value', f'{simulation_name}.net.xml')
|
||||||
|
root.find('input/route-files').set('value', ','.join(routefiles))
|
||||||
|
additional = root.find('input/additional-files')
|
||||||
|
if generate_polygons:
|
||||||
|
additional.set('value', f'{simulation_name}.poly.xml')
|
||||||
|
else:
|
||||||
|
root.find('input').remove(additional)
|
||||||
|
root.find('report/log').set('value', f'{simulation_name}.log')
|
||||||
|
# Set the seed for the random number generator. By default, use the current time
|
||||||
|
root.find('random_number/seed').set('value', seed or str(int(time.time())))
|
||||||
|
return sumoconfig
|
||||||
|
|
||||||
|
|
||||||
|
def generate_scenario(osm_file, out_path, scenario_name, generate_polygons=False):
|
||||||
|
net_template = load_netconvert_template(osm_file, scenario_name)
|
||||||
|
|
||||||
|
with tempfile.TemporaryDirectory() as tmpdirname:
|
||||||
|
# Generate NETCONVERT configuration
|
||||||
|
netconfig = os.path.join(tmpdirname, f'{scenario_name}.netcfg')
|
||||||
|
net_template.write(netconfig)
|
||||||
|
# Copy typemaps to tempdir
|
||||||
|
shutil.copytree(os.path.join(TEMPLATEDIR, 'typemap'), os.path.join(tmpdirname, 'typemap'))
|
||||||
|
# Call NETCONVERT
|
||||||
|
logging.info("Generating network…")
|
||||||
|
netconvertcmd = [os.path.join(SUMOBIN, 'netconvert'), '-c', netconfig]
|
||||||
|
logging.debug(f'Calling {" ".join(netconvertcmd)}')
|
||||||
|
subprocess.run(netconvertcmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
||||||
|
# Optionaly generate polygons
|
||||||
|
if generate_polygons:
|
||||||
|
generate_polygons_(osm_file, scenario_name, tmpdirname)
|
||||||
|
# Move files to destination
|
||||||
|
ignore_patterns = shutil.ignore_patterns('*.polycfg', '*.netcfg', 'typemap')
|
||||||
|
shutil.copytree(tmpdirname, out_path, ignore=ignore_patterns)
|
||||||
|
|
||||||
|
|
||||||
|
def generate_polygons_(osm_file, scenario_name, dest):
|
||||||
|
polyconfig = os.path.join(dest, f'{scenario_name}.polycfg')
|
||||||
|
poly_template = load_polyconvert_template(osm_file, 'typemap/osmPolyconvert.typ.xml', scenario_name)
|
||||||
|
poly_template.write(polyconfig)
|
||||||
|
# Call POLYCONVERT
|
||||||
|
logging.info('Generating polygons…')
|
||||||
|
polyconvert_cmd = [os.path.join(SUMOBIN, 'polyconvert'), '-c', polyconfig]
|
||||||
|
logging.debug(f'Calling {" ".join(polyconvert_cmd)}')
|
||||||
|
subprocess.run(polyconvert_cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
||||||
|
|
||||||
|
|
||||||
|
def generate_mobility(out_path, name, vclasses, end_time):
|
||||||
|
netfile = f'{name}.net.xml'
|
||||||
|
netpath = os.path.join(out_path, netfile)
|
||||||
|
output = os.path.join(out_path, f'{name}.trips.xml')
|
||||||
|
routefiles = []
|
||||||
|
for vclass, density in vclasses.items():
|
||||||
|
# simname.bus.rou.xml, simname.passenger.rou.xml, ...
|
||||||
|
routefile = f'{name}.{vclass}.rou.xml'
|
||||||
|
routepath = os.path.join(out_path, routefile)
|
||||||
|
routefiles.append(routefile)
|
||||||
|
logging.debug(routefile)
|
||||||
|
generator = RandomTripsGenerator(netpath, routepath, output, vclass, float(density))
|
||||||
|
generator.flags.append('-l')
|
||||||
|
generator.flags.append('--validate')
|
||||||
|
generator.options.update(**{'--end': end_time})
|
||||||
|
generator.generate()
|
||||||
|
return routefiles
|
||||||
|
|
||||||
|
|
||||||
|
def generate_sumo_configuration(routefiles, path, scenario_name, generate_polygons):
|
||||||
|
sumo_template = load_sumoconfig_template(scenario_name, routefiles, generate_polygons)
|
||||||
|
sumo_template.write(os.path.join(path, f'{scenario_name}.sumocfg'))
|
||||||
|
|
||||||
|
|
||||||
|
def generate_all(args):
|
||||||
|
simulation_name = args.name
|
||||||
|
simulation_dir = os.path.join(args.path, simulation_name)
|
||||||
|
try:
|
||||||
|
generate_polygons = args.generate_polygons
|
||||||
|
except AttributeError:
|
||||||
|
generate_polygons = False
|
||||||
|
osm_file = args.osmfile
|
||||||
|
logs_dir = os.path.join(simulation_dir, 'log')
|
||||||
|
|
||||||
|
generate_scenario(osm_file, simulation_dir, simulation_name, generate_polygons)
|
||||||
|
routefiles = generate_mobility(simulation_dir, simulation_name, args.vclasses, args.end)
|
||||||
|
generate_sumo_configuration(routefiles, simulation_dir, simulation_name, generate_polygons)
|
||||||
|
# Move all logs to logdir
|
||||||
|
move_logs(simulation_dir, logs_dir)
|
||||||
|
|
||||||
|
|
||||||
|
def move_logs(simulation_dir, logs_dir):
|
||||||
|
for f in os.listdir(simulation_dir):
|
||||||
|
if os.path.splitext(f)[1] == '.log':
|
||||||
|
shutil.move(os.path.join(simulation_dir, f), logs_dir)
|
||||||
|
|
||||||
|
|
||||||
|
def dict_to_list(d):
|
||||||
|
return [item for k in d for item in (k, d[k])]
|
||||||
|
|
||||||
|
|
||||||
|
def parse_command_line(args=None):
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument('osmfile', help='Path to the .osm file to convert to a SUMO simulation')
|
||||||
|
parser.add_argument('--path', help='Where to generate the files')
|
||||||
|
parser.add_argument('--name', required=True, help='Name of the SUMO scenario to generate')
|
||||||
|
parser.add_argument('--generate-polygons', default=False, action='store_true',
|
||||||
|
help='Whether to generate polygons and POIs (defaults to false).')
|
||||||
|
parser.add_argument('--vclass', dest='vclasses', action=StoreDictKeyPair,
|
||||||
|
nargs="+", metavar="VCLASS=DENSITY",
|
||||||
|
help='Generate this vclass with given density, in pair form vclass=density. The density is '
|
||||||
|
'given in vehicles per hour per kilometer. For now, the following vehicle classes are '
|
||||||
|
'available: passenger, truck, bus.')
|
||||||
|
parser.add_argument('--seed', help='Initializes the random number generator.')
|
||||||
|
parser.add_argument('-e', '--end', type=int, default=200, help='end time (default 200)')
|
||||||
|
return parser.parse_args(args=args)
|
||||||
|
|
||||||
|
|
||||||
|
def handle_args(options):
|
||||||
|
# If no vehicle classes are specified, use 'passenger' as a default with a density of 10 cars/km/h.
|
||||||
|
options.vclasses = options.vclasses or {'passenger': 10}
|
||||||
|
# Delete simul_dir if it already exists
|
||||||
|
simul_dir = os.path.join(options.path, options.name)
|
||||||
|
if os.path.isdir(simul_dir):
|
||||||
|
input(f'{simul_dir} already exists ! Press Enter to delete...')
|
||||||
|
shutil.rmtree(simul_dir)
|
||||||
|
logging.debug(f'Options : {options}')
|
||||||
|
generate_all(options)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_json(json_file):
|
||||||
|
logging.info(f'Loading config from {json_file}')
|
||||||
|
config = SimpleNamespace(**json.load(json_file))
|
||||||
|
logging.debug(f'Config {config}')
|
||||||
|
return config
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
# Try to load the config file
|
||||||
|
if len(argv) > 2 and argv[1] == '-c' or argv[1] == '--config' or argv[1] == '-config':
|
||||||
|
try:
|
||||||
|
with open(argv[2]) as jsonfile:
|
||||||
|
config = parse_json(jsonfile)
|
||||||
|
handle_args(config)
|
||||||
|
except FileNotFoundError:
|
||||||
|
msg = f'The config file {argv[2]} does not exist!'
|
||||||
|
logging.fatal(msg)
|
||||||
|
raise FileNotFoundError(msg)
|
||||||
|
else:
|
||||||
|
# Run with command line arguments
|
||||||
|
config = parse_command_line()
|
||||||
|
handle_args(config)
|
59
sumo_project/templates/simul.netcfg
Normal file
59
sumo_project/templates/simul.netcfg
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<configuration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://sumo.dlr.de/xsd/netconvertConfiguration.xsd">
|
||||||
|
|
||||||
|
<input>
|
||||||
|
<type-files value="typemap/osmNetconvert.typ.xml,typemap/osmNetconvertUrbanDe.typ.xml,typemap/osmNetconvertPedestrians.typ.xml,typemap/osmNetconvertBicycle.typ.xml,typemap/osmBidiRailNetconvert.typ.xml" />
|
||||||
|
<osm-files value="simul.raw.osm" />
|
||||||
|
</input>
|
||||||
|
|
||||||
|
<output>
|
||||||
|
<!--<output-prefix value="simul." />-->
|
||||||
|
<output-file value="simul.net.xml"/>
|
||||||
|
</output>
|
||||||
|
|
||||||
|
<tls_building>
|
||||||
|
<tls.join value="true"/>
|
||||||
|
<tls.guess-signals value="true"/>
|
||||||
|
<tls.discard-simple value="true" />
|
||||||
|
<tls.default-type value="actuated"/>
|
||||||
|
<tls.min-dur value="5"/>
|
||||||
|
<tls.max-dur value="30"/>
|
||||||
|
</tls_building>
|
||||||
|
|
||||||
|
<ramp_guessing>
|
||||||
|
<ramps.guess value="true"/>
|
||||||
|
</ramp_guessing>
|
||||||
|
|
||||||
|
<junctions>
|
||||||
|
<junctions.join value="true"/>
|
||||||
|
</junctions>
|
||||||
|
|
||||||
|
<processing>
|
||||||
|
<geometry.remove value="true"/>
|
||||||
|
<roundabouts.guess value="true"/>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
<junctions.limit-turn-speed value="1"/>
|
||||||
|
<crossings.guess value="true"/>
|
||||||
|
<walkingareas value="false"/>
|
||||||
|
<osm.elevation value="true"/>
|
||||||
|
<no-turnarounds value="false"/>
|
||||||
|
<no-turnarounds.tls value="true"/>
|
||||||
|
<no-turnarounds.except-deadend value="true"/>
|
||||||
|
<no-internal-links value="false"/>
|
||||||
|
<ignore-errors value="false"/>
|
||||||
|
<ignore-errors.connections value="false"/>
|
||||||
|
<show-errors.connections-first-try value="true"/>-->
|
||||||
|
</processing>
|
||||||
|
|
||||||
|
<building_defaults>
|
||||||
|
<default.crossing-width value="2.0"/>
|
||||||
|
</building_defaults>
|
||||||
|
|
||||||
|
<report>
|
||||||
|
<verbose value="true"/>
|
||||||
|
<log value="netconvert.log"/>
|
||||||
|
</report>
|
||||||
|
|
||||||
|
</configuration>
|
24
sumo_project/templates/simul.polycfg
Normal file
24
sumo_project/templates/simul.polycfg
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<configuration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://sumo.dlr.de/xsd/polyconvertConfiguration.xsd">
|
||||||
|
|
||||||
|
<input>
|
||||||
|
<net-file value="simul.net.xml"/>
|
||||||
|
<osm-files value="simul.raw.osm"/>
|
||||||
|
<type-file value="typemap/osmPolyconvert.typ.xml"/>
|
||||||
|
</input>
|
||||||
|
|
||||||
|
<output>
|
||||||
|
<output-file value="simul.poly.xml"/>
|
||||||
|
</output>
|
||||||
|
|
||||||
|
<processing>
|
||||||
|
<ignore-errors value="true"/>
|
||||||
|
</processing>
|
||||||
|
|
||||||
|
<report>
|
||||||
|
<verbose value="true"/>
|
||||||
|
<log value="polyconvert.log"/>
|
||||||
|
</report>
|
||||||
|
|
||||||
|
</configuration>
|
30
sumo_project/templates/simul.sumocfg
Normal file
30
sumo_project/templates/simul.sumocfg
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<configuration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://sumo.dlr.de/xsd/sumoConfiguration.xsd">
|
||||||
|
|
||||||
|
<input>
|
||||||
|
<net-file value="simul.net.xml"/>
|
||||||
|
<route-files value="simul.rou.xml"/>
|
||||||
|
<additional-files value="simul.poly.xml"/>
|
||||||
|
</input>
|
||||||
|
|
||||||
|
<processing>
|
||||||
|
<lateral-resolution value="0.3"/>
|
||||||
|
<ignore-junction-blocker value="60"/>
|
||||||
|
<collision.action value="teleport"/>
|
||||||
|
<time-to-teleport value="180"/>
|
||||||
|
<max-depart-delay value="900"/>
|
||||||
|
<time-to-impatience value="30"/>
|
||||||
|
</processing>
|
||||||
|
|
||||||
|
<report>
|
||||||
|
<verbose value="true" synonymes="v"/>
|
||||||
|
<log value="sim.log" synonymes="l log-file"/>
|
||||||
|
<duration-log.statistics value="true"/>
|
||||||
|
</report>
|
||||||
|
|
||||||
|
<random_number>
|
||||||
|
<seed value="1"/>
|
||||||
|
</random_number>
|
||||||
|
|
||||||
|
</configuration>
|
@ -0,0 +1,7 @@
|
|||||||
|
<types xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://sumo.dlr.de/xsd/types_file.xsd">
|
||||||
|
<type id="railway.rail" oneway="false"/>
|
||||||
|
<type id="railway.tram" oneway="false"/>
|
||||||
|
<type id="railway.light_rail" oneway="false"/>
|
||||||
|
<type id="railway.subway" oneway="false"/>
|
||||||
|
<type id="railway.preserved" oneway="false"/>
|
||||||
|
</types>
|
52
sumo_project/templates/typemap/osmNetconvert.typ.xml
Normal file
52
sumo_project/templates/typemap/osmNetconvert.typ.xml
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
<types xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://sumo.dlr.de/xsd/types_file.xsd">
|
||||||
|
<type id="highway.motorway" numLanes="3" speed="44.44" priority="13" oneway="true" disallow="pedestrian bicycle moped rail rail_urban rail_electric tram ship"/>
|
||||||
|
<type id="highway.motorway_bridge" numLanes="3" speed="44.44" priority="13" oneway="true" disallow="pedestrian bicycle moped rail rail_urban rail_electric tram ship"/>
|
||||||
|
<type id="highway.motorway_tunnel" numLanes="3" speed="44.44" priority="13" oneway="true" disallow="pedestrian bicycle moped rail rail_urban rail_electric tram ship"/>
|
||||||
|
<type id="highway.motorway_link" numLanes="1" speed="22.22" priority="12" oneway="true" disallow="pedestrian bicycle moped rail rail_urban rail_electric tram ship"/>
|
||||||
|
<type id="highway.trunk" numLanes="2" speed="27.78" priority="11" oneway="false" disallow="pedestrian bicycle rail rail_urban rail_electric tram ship"/>
|
||||||
|
<type id="highway.trunk_bridge" numLanes="2" speed="27.78" priority="11" oneway="false" disallow="pedestrian bicycle rail rail_urban rail_electric tram ship"/>
|
||||||
|
<type id="highway.trunk_tunnel" numLanes="2" speed="27.78" priority="11" oneway="false" disallow="pedestrian bicycle rail rail_urban rail_electric tram ship"/>
|
||||||
|
<type id="highway.trunk_link" numLanes="1" speed="22.22" priority="10" oneway="false" disallow="pedestrian bicycle rail rail_urban rail_electric tram ship"/>
|
||||||
|
<type id="highway.primary" numLanes="2" speed="27.78" priority="9" oneway="false" disallow="pedestrian bicycle rail rail_urban rail_electric tram ship"/>
|
||||||
|
<type id="highway.primary_bridge" numLanes="2" speed="27.78" priority="9" oneway="false" disallow="pedestrian bicycle rail rail_urban rail_electric tram ship"/>
|
||||||
|
<type id="highway.primary_tunnel" numLanes="2" speed="27.78" priority="9" oneway="false" disallow="pedestrian bicycle rail rail_urban rail_electric tram ship"/>
|
||||||
|
<type id="highway.primary_link" numLanes="1" speed="22.22" priority="8" oneway="false" disallow="pedestrian bicycle rail rail_urban rail_electric tram ship"/>
|
||||||
|
<type id="highway.secondary" numLanes="2" speed="27.78" priority="7" oneway="false" disallow="pedestrian rail rail_urban rail_electric tram ship"/>
|
||||||
|
<type id="highway.secondary_bridge" numLanes="2" speed="27.78" priority="7" oneway="false" disallow="pedestrian rail rail_urban rail_electric tram ship"/>
|
||||||
|
<type id="highway.secondary_tunnel" numLanes="2" speed="27.78" priority="7" oneway="false" disallow="pedestrian rail rail_urban rail_electric tram ship"/>
|
||||||
|
<type id="highway.secondary_link" numLanes="1" speed="22.22" priority="6" oneway="false" disallow="pedestrian rail rail_urban rail_electric tram ship"/>
|
||||||
|
<type id="highway.tertiary" numLanes="1" speed="22.22" priority="6" oneway="false" disallow="pedestrian rail rail_urban rail_electric tram ship"/>
|
||||||
|
<type id="highway.tertiary_bridge" numLanes="1" speed="22.22" priority="6" oneway="false" disallow="pedestrian rail rail_urban rail_electric tram ship"/>
|
||||||
|
<type id="highway.tertiary_tunnel" numLanes="1" speed="22.22" priority="6" oneway="false" disallow="pedestrian rail rail_urban rail_electric tram ship"/>
|
||||||
|
<type id="highway.tertiary_link" numLanes="1" speed="22.22" priority="5" oneway="false" disallow="pedestrian rail rail_urban rail_electric tram ship"/>
|
||||||
|
<type id="highway.unclassified" numLanes="1" speed="13.89" priority="5" oneway="false" disallow="rail rail_urban rail_electric tram ship"/>
|
||||||
|
<type id="highway.residential" numLanes="1" speed="13.89" priority="4" oneway="false" disallow="rail rail_urban rail_electric tram ship"/>
|
||||||
|
<type id="highway.residential_bridge" numLanes="1" speed="13.89" priority="4" oneway="false" disallow="rail rail_urban rail_electric tram ship"/>
|
||||||
|
<type id="highway.residential_tunnel" numLanes="1" speed="13.89" priority="4" oneway="false" disallow="rail rail_urban rail_electric tram ship"/>
|
||||||
|
<type id="highway.living_street" numLanes="1" speed="2.78" priority="3" oneway="false" disallow="rail rail_urban rail_electric tram ship"/>
|
||||||
|
<type id="highway.track" numLanes="1" speed="5.56" priority="1" oneway="false" disallow="rail rail_urban rail_electric tram ship"/>
|
||||||
|
<type id="highway.unsurfaced" numLanes="1" speed="8.33" priority="1" oneway="false" disallow="rail rail_urban rail_electric tram ship"/>
|
||||||
|
<type id="highway.services" numLanes="1" speed="8.33" priority="1" oneway="false" disallow="rail rail_urban rail_electric tram ship"/>
|
||||||
|
<type id="highway.service" numLanes="1" speed="5.56" priority="1" oneway="false" disallow="rail rail_urban rail_electric tram ship"/>
|
||||||
|
|
||||||
|
<!-- everything which serves mainly pedestrians is oneway because all current pedestrian models do not care about direction -->
|
||||||
|
<type id="highway.footway" numLanes="1" speed="2.78" priority="1" oneway="true" width="2" allow="pedestrian"/>
|
||||||
|
<type id="highway.pedestrian" numLanes="1" speed="2.78" priority="1" oneway="true" width="2" allow="pedestrian bicycle"/>
|
||||||
|
<type id="highway.path" numLanes="1" speed="2.78" priority="1" oneway="true" width="2" allow="pedestrian bicycle"/>
|
||||||
|
<type id="highway.bridleway" numLanes="1" speed="2.78" priority="1" oneway="true" width="2" allow="pedestrian bicycle"/>
|
||||||
|
<type id="highway.cycleway" numLanes="1" speed="5.56" priority="1" oneway="false" width="2" allow="bicycle"/>
|
||||||
|
<type id="highway.step" numLanes="1" speed="1.39" priority="1" oneway="true" width="2" allow="pedestrian"/>
|
||||||
|
<type id="highway.steps" numLanes="1" speed="1.39" priority="1" oneway="true" width="2" allow="pedestrian"/>
|
||||||
|
<type id="highway.stairs" numLanes="1" speed="1.39" priority="1" oneway="true" width="2" allow="pedestrian"/>
|
||||||
|
|
||||||
|
<type id="highway.bus_guideway" numLanes="1" speed="8.33" priority="1" oneway="true" allow="bus"/>
|
||||||
|
<type id="highway.raceway" numLanes="2" speed="83.33" priority="14" oneway="false" allow="vip"/>
|
||||||
|
<type id="highway.ford" numLanes="1" speed="2.78" priority="1" oneway="false" allow="army"/>
|
||||||
|
|
||||||
|
<type id="railway.rail" numLanes="1" speed="83.33" priority="15" oneway="true" allow="rail rail_electric"/>
|
||||||
|
<type id="railway.tram" numLanes="1" speed="13.89" priority="15" oneway="true" allow="tram"/>
|
||||||
|
<type id="railway.light_rail" numLanes="1" speed="27.78" priority="15" oneway="true" allow="rail_urban"/>
|
||||||
|
<type id="railway.subway" numLanes="1" speed="27.78" priority="15" oneway="true" allow="rail_urban"/>
|
||||||
|
<type id="railway.preserved" numLanes="1" speed="27.78" priority="15" oneway="true" allow="rail"/>
|
||||||
|
|
||||||
|
</types>
|
@ -0,0 +1,6 @@
|
|||||||
|
<types xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://sumo.dlr.de/xsd/types_file.xsd">
|
||||||
|
<type id="cycleway.lane" bikeLaneWidth="1.0" allow="bicycle"/>
|
||||||
|
<type id="cycleway.opposite_lane" bikeLaneWidth="1.0" allow="bicycle"/>
|
||||||
|
<type id="cycleway.track" bikeLaneWidth="1.5" allow="bicycle"/>
|
||||||
|
<type id="cycleway.opposite_track" bikeLaneWidth="1.5" allow="bicycle"/>
|
||||||
|
</types>
|
@ -0,0 +1,18 @@
|
|||||||
|
<types xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://sumo.dlr.de/xsd/types_file.xsd">
|
||||||
|
<type id="highway.primary" sidewalkWidth="2" disallow="pedestrian bicycle rail rail_urban rail_electric tram ship"/>
|
||||||
|
<type id="highway.primary_link" sidewalkWidth="2" disallow="pedestrian bicycle rail rail_urban rail_electric tram ship"/>
|
||||||
|
<type id="highway.primary_bridge" sidewalkWidth="2" disallow="pedestrian bicycle rail rail_urban rail_electric tram ship"/>
|
||||||
|
<type id="highway.primary_tunnel" disallow="pedestrian bicycle rail rail_urban rail_electric tram ship"/>
|
||||||
|
<type id="highway.secondary" sidewalkWidth="1.5" disallow="pedestrian rail rail_urban rail_electric tram ship"/>
|
||||||
|
<type id="highway.secondary_link" sidewalkWidth="1.5" disallow="pedestrian rail rail_urban rail_electric tram ship"/>
|
||||||
|
<type id="highway.secondary_bridge" sidewalkWidth="1.5" disallow="pedestrian rail rail_urban rail_electric tram ship"/>
|
||||||
|
<type id="highway.secondary_tunnel" disallow="pedestrian rail rail_urban rail_electric tram ship"/>
|
||||||
|
<type id="highway.tertiary" sidewalkWidth="1.5" disallow="pedestrian rail rail_urban rail_electric tram ship"/>
|
||||||
|
<type id="highway.tertiary_link" sidewalkWidth="1.5" disallow="pedestrian rail rail_urban rail_electric tram ship"/>
|
||||||
|
<type id="highway.tertiary_bridge" sidewalkWidth="1.5" disallow="pedestrian rail rail_urban rail_electric tram ship"/>
|
||||||
|
<type id="highway.tertiary_tunnel" disallow="pedestrian rail rail_urban rail_electric tram ship"/>
|
||||||
|
<type id="highway.unclassified" sidewalkWidth="1.5" disallow="rail rail_urban rail_electric tram ship"/>
|
||||||
|
<type id="highway.residential" sidewalkWidth="1.5" disallow="rail rail_urban rail_electric tram ship"/>
|
||||||
|
<type id="highway.residential_bridge" sidewalkWidth="1.5" disallow="rail rail_urban rail_electric tram ship"/>
|
||||||
|
<type id="highway.residential_tunnel" sidewalkWidth="1.5" disallow="rail rail_urban rail_electric tram ship"/>
|
||||||
|
</types>
|
@ -0,0 +1,5 @@
|
|||||||
|
<types xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://sumo.dlr.de/xsd/types_file.xsd">
|
||||||
|
<type id="waterway.river" width="7" numLanes="1" speed="10" priority="13" oneway="false" allow="ship"/>
|
||||||
|
<type id="waterway.canal" width="5" numLanes="1" speed="10" priority="13" oneway="false" allow="ship"/>
|
||||||
|
<type id="route.ferry" width="5" numLanes="1" speed="10" priority="13" oneway="false" allow="ship"/>
|
||||||
|
</types>
|
12
sumo_project/templates/typemap/osmNetconvertUrbanDe.typ.xml
Normal file
12
sumo_project/templates/typemap/osmNetconvertUrbanDe.typ.xml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<types xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://sumo.dlr.de/xsd/types_file.xsd">
|
||||||
|
<type id="highway.motorway" speed="27.78"/>
|
||||||
|
<type id="highway.motorway_link" speed="16.67"/>
|
||||||
|
<type id="highway.trunk" speed="13.89"/>
|
||||||
|
<type id="highway.trunk_link" speed="13.89"/>
|
||||||
|
<type id="highway.primary" speed="13.89"/>
|
||||||
|
<type id="highway.primary_link" speed="13.89"/>
|
||||||
|
<type id="highway.secondary" speed="13.89"/>
|
||||||
|
<type id="highway.secondary_link" speed="13.89"/>
|
||||||
|
<type id="highway.tertiary" speed="13.89"/>
|
||||||
|
<type id="highway.tertiary_link" speed="13.89"/>
|
||||||
|
</types>
|
@ -0,0 +1,3 @@
|
|||||||
|
<polygonTypes>
|
||||||
|
<polygonType id="boundary" name="boundary" color="1,0,0" layer="100" fill="false"/>
|
||||||
|
</polygonTypes>
|
40
sumo_project/templates/typemap/osmPolyconvert.typ.xml
Normal file
40
sumo_project/templates/typemap/osmPolyconvert.typ.xml
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
<polygonTypes>
|
||||||
|
<polygonType id="waterway" name="water" color=".71,.82,.82" layer="4" discard="true"/>
|
||||||
|
<polygonType id="natural" name="natural" color=".55,.77,.42" layer="4" discard="true"/>
|
||||||
|
<polygonType id="natural.water" name="water" color=".71,.82,.82" layer="4" discard="true"/>
|
||||||
|
<polygonType id="natural.wetland" name="water" color=".71,.82,.82" layer="4" discard="true"/>
|
||||||
|
<polygonType id="natural.wood" name="forest" color=".55,.77,.42" layer="4" discard="true"/>
|
||||||
|
<polygonType id="natural.land" name="land" color=".98,.87,.46" layer="4" discard="true"/>
|
||||||
|
|
||||||
|
<polygonType id="landuse" name="landuse" color=".76,.76,.51" layer="3"/>
|
||||||
|
<polygonType id="landuse.forest" name="forest" color=".55,.77,.42" layer="3"/>
|
||||||
|
<polygonType id="landuse.park" name="park" color=".81,.96,.79" layer="3"/>
|
||||||
|
<polygonType id="landuse.residential" name="residential" color=".92,.92,.89" layer="3"/>
|
||||||
|
<polygonType id="landuse.commercial" name="commercial" color=".82,.82,.80" layer="3"/>
|
||||||
|
<polygonType id="landuse.industrial" name="industrial" color=".82,.82,.80" layer="3"/>
|
||||||
|
<polygonType id="landuse.military" name="military" color=".60,.60,.36" layer="3"/>
|
||||||
|
<polygonType id="landuse.farm" name="farm" color=".95,.95,.80" layer="3"/>
|
||||||
|
<polygonType id="landuse.greenfield" name="farm" color=".95,.95,.80" layer="3"/>
|
||||||
|
<polygonType id="landuse.village_green" name="farm" color=".95,.95,.80" layer="3"/>
|
||||||
|
|
||||||
|
<polygonType id="tourism" name="tourism" color=".81,.96,.79" layer="2"/>
|
||||||
|
<polygonType id="military" name="military" color=".60,.60,.36" layer="2"/>
|
||||||
|
<polygonType id="sport" name="sport" color=".31,.90,.49" layer="2"/>
|
||||||
|
<polygonType id="leisure" name="leisure" color=".81,.96,.79" layer="2"/>
|
||||||
|
<polygonType id="leisure.park" name="tourism" color=".81,.96,.79" layer="2"/>
|
||||||
|
<polygonType id="aeroway" name="aeroway" color=".50,.50,.50" layer="2"/>
|
||||||
|
<polygonType id="aerialway" name="aerialway" color=".20,.20,.20" layer="2"/>
|
||||||
|
|
||||||
|
<polygonType id="shop" name="shop" color=".93,.78,1.0" layer="1"/>
|
||||||
|
<polygonType id="historic" name="historic" color=".50,1.0,.50" layer="1"/>
|
||||||
|
<polygonType id="man_made" name="building" color="1.0,.90,.90" layer="1"/>
|
||||||
|
<polygonType id="building" name="building" color="1.0,.50,.50" layer="1"/>
|
||||||
|
<polygonType id="amenity" name="amenity" color=".93,.78,.78" layer="1"/>
|
||||||
|
<polygonType id="amenity.parking" name="parking" color=".72,.72,.70" layer="1"/>
|
||||||
|
<polygonType id="power" name="power" color=".10,.10,.30" layer="1" discard="true"/>
|
||||||
|
<polygonType id="highway" name="highway" color=".10,.10,.10" layer="1" discard="true"/>
|
||||||
|
|
||||||
|
<polygonType id="boundary" name="boundary" color="1.0,.10,.10" layer="0" fill="false"/>
|
||||||
|
<polygonType id="admin_level" name="admin_level" color="1.0,.33,.33" layer="0" fill="false" discard="true"/>
|
||||||
|
<polygonType id="place" name="admin_level" color="1.0,.33,.33" layer="0" fill="false" discard="true"/>
|
||||||
|
</polygonTypes>
|
143
sumo_project/tests/configurator_tests.py
Normal file
143
sumo_project/tests/configurator_tests.py
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
import io
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
import tempfile
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
import configurator
|
||||||
|
|
||||||
|
# Absolute path of the directory the script is in
|
||||||
|
SCRIPTDIR = os.path.dirname(__file__)
|
||||||
|
|
||||||
|
|
||||||
|
class TemplateTests(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.sim_name = 'test_simulation'
|
||||||
|
self.sim_path = '/test_simulation'
|
||||||
|
self.log_path = '/test_simulation/log'
|
||||||
|
|
||||||
|
def test_load_netconvert_template(self):
|
||||||
|
tree = configurator.load_netconvert_template('test.osm', 'test_simulation')
|
||||||
|
self.assertEqual(tree.find('input/osm-files').get('value'), 'test.osm')
|
||||||
|
self.assertEqual(tree.find('output/output-file').get('value'), f'{self.sim_name}.net.xml')
|
||||||
|
self.assertEqual(tree.find('report/log').get('value'), f'{self.sim_name}.netconvert.log')
|
||||||
|
|
||||||
|
def test_load_sumoconfig_template_default(self):
|
||||||
|
tree = configurator.load_sumoconfig_template(self.sim_name)
|
||||||
|
self.assertEqual(tree.find('input/net-file').get('value'), f'{self.sim_name}.net.xml')
|
||||||
|
self.assertEqual(tree.find('input/route-files').get('value'), f'{self.sim_name}.rou.xml')
|
||||||
|
self.assertEqual(tree.find('report/log').get('value'), f'{self.sim_name}.log')
|
||||||
|
|
||||||
|
def test_load_sumoconfig_template_with_polygons(self):
|
||||||
|
tree = configurator.load_sumoconfig_template(self.sim_name, generate_polygons=True)
|
||||||
|
self.assertEqual(tree.find('input/net-file').get('value'), f'{self.sim_name}.net.xml')
|
||||||
|
self.assertEqual(tree.find('input/route-files').get('value'), f'{self.sim_name}.rou.xml')
|
||||||
|
self.assertEqual(tree.find('report/log').get('value'), f'{self.sim_name}.log')
|
||||||
|
self.assertEqual(tree.find('input/additional-files').get('value'), f'{self.sim_name}.poly.xml')
|
||||||
|
|
||||||
|
def test_load_sumoconfig_template_with_routefiles(self):
|
||||||
|
routefiles = (f'{self.sim_name}.bus.rou.xml', f'{self.sim_name}.passenger.rou.xml')
|
||||||
|
tree = configurator.load_sumoconfig_template(self.sim_name, routefiles)
|
||||||
|
self.assertEqual(tree.find('input/net-file').get('value'), f'{self.sim_name}.net.xml')
|
||||||
|
self.assertEqual(tree.find('input/route-files').get('value'), ','.join(routefiles))
|
||||||
|
self.assertEqual(tree.find('report/log').get('value'), f'{self.sim_name}.log')
|
||||||
|
|
||||||
|
def test_load_sumoconfig_template_with_seed(self):
|
||||||
|
routefiles = (f'{self.sim_name}.bus.rou.xml', f'{self.sim_name}.passenger.rou.xml')
|
||||||
|
tree = configurator.load_sumoconfig_template(self.sim_name, routefiles, seed=42)
|
||||||
|
self.assertEqual(tree.find('random_number/seed').get('value'), 42)
|
||||||
|
|
||||||
|
def test_load_polyconvert_template(self):
|
||||||
|
tree = configurator.load_polyconvert_template(
|
||||||
|
osm_file=f'{self.sim_name}.osm',
|
||||||
|
type_file='typemap/test.typ.xml',
|
||||||
|
scenario_name=f'{self.sim_name}'
|
||||||
|
)
|
||||||
|
self.assertEqual(tree.find('input/osm-files').get('value'), f'{self.sim_name}.osm')
|
||||||
|
self.assertEqual(tree.find('input/net-file').get('value'), f'{self.sim_name}.net.xml')
|
||||||
|
self.assertEqual(tree.find('input/type-file').get('value'), 'typemap/test.typ.xml')
|
||||||
|
self.assertEqual(tree.find('output/output-file').get('value'), f'{self.sim_name}.poly.xml')
|
||||||
|
self.assertEqual(tree.find('report/log').get('value'), f'{self.sim_name}.polyconvert.log')
|
||||||
|
|
||||||
|
|
||||||
|
class GenerationTests(unittest.TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.base_path = tempfile.mkdtemp()
|
||||||
|
self.sim_name = 'test_simulation'
|
||||||
|
self.sim_path = os.path.join(self.base_path, self.sim_name)
|
||||||
|
self.log_path = os.path.join(self.sim_name, 'log')
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
shutil.rmtree(self.base_path)
|
||||||
|
|
||||||
|
def test_generate_scenario(self):
|
||||||
|
osm_file = os.path.join(SCRIPTDIR, 'sample.osm')
|
||||||
|
configurator.generate_scenario(osm_file, self.sim_path, self.sim_name, generate_polygons=False)
|
||||||
|
self.assert_is_file(os.path.join(self.sim_path, f'{self.sim_name}.net.xml'))
|
||||||
|
|
||||||
|
def test_generate_scenario_with_polygons(self):
|
||||||
|
osm_file = os.path.join(SCRIPTDIR, 'sample.osm')
|
||||||
|
configurator.generate_scenario(osm_file, self.sim_path, self.sim_name, generate_polygons=True)
|
||||||
|
self.assert_is_dir(self.sim_path)
|
||||||
|
generated_files = [
|
||||||
|
f'{self.sim_name}.poly.xml',
|
||||||
|
f'{self.sim_name}.net.xml'
|
||||||
|
]
|
||||||
|
for f in generated_files:
|
||||||
|
self.assert_is_file(os.path.join(self.sim_path, f))
|
||||||
|
|
||||||
|
def test_generate_mobility(self):
|
||||||
|
# The scenario must be generated before the mobility
|
||||||
|
osm_file = os.path.join(SCRIPTDIR, 'sample.osm')
|
||||||
|
trips_file = os.path.join(self.sim_path, f'{self.sim_name}.trips.xml')
|
||||||
|
configurator.generate_scenario(osm_file, self.sim_path, self.sim_name)
|
||||||
|
classes = {'passenger': 10, 'truck': 1}
|
||||||
|
routefiles = configurator.generate_mobility(self.sim_path, self.sim_name, vclasses=classes, end_time=200)
|
||||||
|
|
||||||
|
self.assert_is_file(trips_file)
|
||||||
|
for f in routefiles:
|
||||||
|
self.assert_is_file(os.path.join(self.sim_path, f))
|
||||||
|
|
||||||
|
def assert_exists(self, path):
|
||||||
|
self.assertTrue(os.path.exists(path), msg=f'{path} does not exist')
|
||||||
|
|
||||||
|
def assert_is_file(self, path):
|
||||||
|
self.assert_exists(path)
|
||||||
|
self.assertTrue(os.path.isfile(path), msg=f'{path} is not a file')
|
||||||
|
|
||||||
|
def assert_is_dir(self, path):
|
||||||
|
self.assert_exists(path)
|
||||||
|
self.assertTrue(os.path.isdir(path), msg=f'{path} is not a directory')
|
||||||
|
|
||||||
|
|
||||||
|
class InputTests(unittest.TestCase):
|
||||||
|
def test_commandline(self):
|
||||||
|
options = ['--name', 'test-config', '--path', '/some/path', '--vclass', 'passenger=10', 'truck=1', '--', 'test.osm']
|
||||||
|
actual_conf = configurator.parse_command_line(options)
|
||||||
|
self.assertEqual(actual_conf.name, 'test-config')
|
||||||
|
self.assertEqual(actual_conf.osmfile, 'test.osm')
|
||||||
|
self.assertEqual(actual_conf.path, '/some/path')
|
||||||
|
self.assertEqual(actual_conf.vclasses, {'passenger': '10', 'truck': '1'})
|
||||||
|
|
||||||
|
def test_from_config_file(self):
|
||||||
|
options = """
|
||||||
|
{
|
||||||
|
"name": "test-config",
|
||||||
|
"path": "/some/path",
|
||||||
|
"vclasses": {
|
||||||
|
"passenger": 10,
|
||||||
|
"truck": 1
|
||||||
|
},
|
||||||
|
"osmfile": "test.osm"
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
actual_conf = configurator.parse_json(io.StringIO(options))
|
||||||
|
self.assertEqual(actual_conf.name, 'test-config')
|
||||||
|
self.assertEqual(actual_conf.osmfile, 'test.osm')
|
||||||
|
self.assertEqual(actual_conf.path, '/some/path')
|
||||||
|
self.assertEqual(actual_conf.vclasses, {'passenger': 10, 'truck': 1})
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
49966
sumo_project/tests/sample.osm
Normal file
49966
sumo_project/tests/sample.osm
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user