Tutorial 07: Networks from OpenStreetMap

In this tutorial, we discuss how networks that have been imported from OpenStreetMap can be integrated and run in Flow. This will all be presented via the Bay Bridge network, seen in the figure below. Networks from OpenStreetMap are commonly used in many traffic simulators for the purposes of replicating traffic in realistic traffic geometries. This is true in both SUMO and Aimsun (which are both supported in Flow), with each supporting several techniques for importing such network files. This process is further simplified and abstracted in Flow, with users simply required to specify the path to the osm file in order to simulate traffic in the network.

**Figure 1**: Snapshot of the Bay Bridge from OpenStreetMap

Before we begin, let us import all relevant Flow parameters as we have done for previous tutorials. If you are unfamiliar with these parameters, you are encouraged to review tutorial 1.


In [ ]:
# the TestEnv environment is used to simply simulate the network
from flow.envs import TestEnv

# the Experiment class is used for running simulations
from flow.core.experiment import Experiment

# all other imports are standard
from flow.core.params import VehicleParams
from flow.core.params import NetParams
from flow.core.params import InitialConfig
from flow.core.params import EnvParams
from flow.core.params import SumoParams

1. Running a Default Simulation

In order to create a scenario object in Flow with network features depicted from OpenStreetMap, we will use the base Scenario class. This class can sufficiently support the generation of any .osm file.


In [ ]:
from flow.scenarios import Scenario

In order to recreate the network features of a specific osm file, the path to the osm file must be specified in NetParams. For this example, we will use an osm file extracted from the section of the Bay Bridge as depicted in Figure 1.

In order to specify the path to the osm file, simply fill in the osm_path attribute with the path to the .osm file as follows:


In [ ]:
net_params = NetParams(
    osm_path='networks/bay_bridge.osm'
)

Next, we create all other parameters as we have in tutorials 1 and 2. For this example, we will assume a total of 1000 are uniformly spread across the Bay Bridge. Once again, if the choice of parameters is unclear, you are encouraged to review Tutorial 1.


In [ ]:
# create the remainding parameters
env_params = EnvParams()
sim_params = SumoParams(render=True)
initial_config = InitialConfig()
vehicles = VehicleParams()
vehicles.add('human', num_vehicles=100)

# create the scenario
scenario = Scenario(
    name='bay_bridge',
    net_params=net_params,
    initial_config=initial_config,
    vehicles=vehicles
)

We are finally ready to test our scenario in simulation. In order to do so, we create an Experiment object and run the simulation for a number of steps. This is done in the cell below.


In [ ]:
# create the environment
env = TestEnv(
    env_params=env_params,
    sim_params=sim_params,
    scenario=scenario
)

# run the simulation for 1000 steps
exp = Experiment(env=env)
exp.run(1, 1000)

2. Customizing the Scenario

While the above example does allow you to view the network within Flow, the simulation is limited for two reasons. For one, vehicles are placed on all edges within the network; if we wished to simulate traffic solely on the on the bridge and do not care about the artireols, for instance, this would result in unnecessary computational burdens. Next, as you may have noticed if you ran the above example to completion, routes in the base scenario class are defaulted to consist of the vehicles' current edges only, meaning that vehicles exit the network as soon as they reach the end of the edge they are originated on. In the next subsections, we discuss how the scenario can be modified to resolve these issues.

2.1 Specifying Traversable Edges

In order to limit the edges vehicles are placed on to the road sections edges corresponding to the westbound Bay Bridge, we define an EDGES_DISTRIBUTION variable. This variable specifies the names of the edges within the network that vehicles are permitted to originated in, and is assigned to the scenario via the edges_distribution component of the InitialConfig input parameter, as seen in the code snippet below. Note that the names of the edges can be identified from the .osm file or by right clicking on specific edges from the SUMO gui (see the figure below).

**Figure 2**: Name of an edge from SUMO

In [ ]:
# we define an EDGES_DISTRIBUTION variable with the edges within 
# the westbound Bay Bridge 
EDGES_DISTRIBUTION = [
    "11197898",
    "123741311", 
    "123741303",
    "90077193#0",
    "90077193#1", 
    "340686922", 
    "236348366", 
    "340686911#0",
    "340686911#1",
    "340686911#2",
    "340686911#3",
    "236348361", 
    "236348360#0", 
    "236348360#1"
]

# the above variable is added to initial_config
new_initial_config = InitialConfig(
    edges_distribution=EDGES_DISTRIBUTION
)

2.2 Creating Custom Routes

Next, we choose to specify the routes of vehicles so that they can traverse the entire Bay Bridge, instead of the only the edge they are currently on. In order to this, we create a new scenario class that inherits all its properties from Scenario and simply redefine the routes by modifying the specify_routes variable. This method was originally introduced in Tutorial 07: Creating Custom Scenarios. The new scenario class looks as follows:


In [ ]:
# we create a new scenario class to specify the expected routes
class BayBridgeOSMScenario(Scenario):

    def specify_routes(self, net_params):
        return {
            "11197898": [
                "11197898", "123741311", "123741303", "90077193#0", "90077193#1", 
                "340686922", "236348366", "340686911#0", "340686911#1",
                "340686911#2", "340686911#3", "236348361", "236348360#0", "236348360#1",
            ],
            "123741311": [
                "123741311", "123741303", "90077193#0", "90077193#1", "340686922", 
                "236348366", "340686911#0", "340686911#1", "340686911#2",
                "340686911#3", "236348361", "236348360#0", "236348360#1"
            ],
            "123741303": [
                "123741303", "90077193#0", "90077193#1", "340686922", "236348366",
                "340686911#0", "340686911#1", "340686911#2", "340686911#3", "236348361",
                "236348360#0", "236348360#1"
            ],
            "90077193#0": [
                "90077193#0", "90077193#1", "340686922", "236348366", "340686911#0",
                "340686911#1", "340686911#2", "340686911#3", "236348361", "236348360#0",
                "236348360#1"
            ],
            "90077193#1": [
                "90077193#1", "340686922", "236348366", "340686911#0", "340686911#1",
                "340686911#2", "340686911#3", "236348361", "236348360#0", "236348360#1"
            ],
            "340686922": [
                "340686922", "236348366", "340686911#0", "340686911#1", "340686911#2",
                "340686911#3", "236348361", "236348360#0", "236348360#1"
            ],
            "236348366": [
                "236348366", "340686911#0", "340686911#1", "340686911#2", "340686911#3",
                "236348361", "236348360#0", "236348360#1"
            ],
            "340686911#0": [
                "340686911#0", "340686911#1", "340686911#2", "340686911#3", "236348361",
                "236348360#0", "236348360#1"
            ],
            "340686911#1": [
                "340686911#1", "340686911#2", "340686911#3", "236348361", "236348360#0",
                "236348360#1"
            ],
            "340686911#2": [
                "340686911#2", "340686911#3", "236348361", "236348360#0", "236348360#1"
            ],
            "340686911#3": [
                "340686911#3", "236348361", "236348360#0", "236348360#1"
            ],
            "236348361": [
                "236348361", "236348360#0", "236348360#1"
            ],
            "236348360#0": [
                "236348360#0", "236348360#1"
            ],
            "236348360#1": [
                "236348360#1"
            ]
        }

2.3 Rerunning the SImulation

We are now ready to rerun the simulation with fully defined vehicle routes and a limited number of traversable edges. If we run the cell below, we can see the new simulation in action.


In [ ]:
# create the scenario
new_scenario = BayBridgeOSMScenario(
    name='bay_bridge',
    net_params=net_params,
    initial_config=new_initial_config,
    vehicles=vehicles,
)

# create the environment
env = TestEnv(
    env_params=env_params,
    sim_params=sim_params,
    scenario=new_scenario
)

# run the simulation for 1000 steps
exp = Experiment(env=env)
exp.run(1, 10000)

3. Other Tips

This tutorial introduces how to incorporate OpenStreetMap files in Flow. This feature, however, does not negate other features that are introduced in other tutorials and documentation. For example, if you would like to not have vehicles be originated side-by-side within a network, this can still be done by specifying a "random" spacing for vehicles as follows:

initial_config = InitialConfig(
    spacing="random",
    edges_distribution=EDGES_DISTRIBUTION
)

In addition, inflows of vehicles can be added to networks imported from OpenStreetMap as they are for any other network (see the tutorial on adding inflows for more on this).


In [ ]: