1
0
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:
Thibaud Gasser 2019-02-04 11:24:18 +01:00 committed by GitHub
commit 1d5c0ec576
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 50765 additions and 0 deletions

116
.gitignore vendored Normal file
View 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/

View 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)

View 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>

View 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>

View 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>

View File

@ -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>

View 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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View 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>

View File

@ -0,0 +1,3 @@
<polygonTypes>
<polygonType id="boundary" name="boundary" color="1,0,0" layer="100" fill="false"/>
</polygonTypes>

View 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>

View 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

File diff suppressed because it is too large Load Diff