Tutorial 12: Inflows

This tutorial walks you through the process of introducing inflows of vehicles into a network. Inflows allow us to simulate open networks where vehicles may enter (and potentially exit) the network consanstly, such as a section of a highway or of an intersection.

The rest of this tutorial is organized as follows:

  • In section 1, we introduce inflows and show how to create them into Flow.
  • In section 2, we simulate the merge network in the presence of inflows.
  • In section 3, we explain the different options you have to customize inflows.

1. Creating inflows in Flow

For this tutorial, we will simulate inflows through a highway network with an entrance ramp (an on-merge). As we will see, the perturbations caused by the vehicles entering through the ramp leads to the formation of congested waves downstream in the main highway.

We begin by importing the merge scenario class provided by Flow.


In [ ]:
from flow.scenarios import MergeScenario

A schematic of the above network is displayed in the figure below. As we can see, the edges at the start of the main highway and of the on-merge are named inflow_highway and inflow_merge respectively. These names will be important when we begin creating our inflows, as we will need to specify by which edges the vehicles should enter the network.

We also need to define the types of the vehicles that are placed in the network through our inflows. These types are string values that allow us to distinguish between vehicles. For instance, we could have two types of vehicles entering through the main highway, one for human-driven vehicles and one for RL-driven vehicles.

For this tutorial, we will only use one type of vehicles, with the vehicle identifier human:


In [ ]:
from flow.core.params import VehicleParams
from flow.controllers import IDMController
from flow.core.params import SumoCarFollowingParams

# create an empty vehicles object
vehicles = VehicleParams()

# add some vehicles to this object of type "human"
vehicles.add("human",
             acceleration_controller=(IDMController, {}),
             car_following_params=SumoCarFollowingParams(
                 speed_mode="obey_safe_speed",  
                 # we use the speed mode "obey_safe_speed" for better dynamics at the merge
             ),
             num_vehicles=20)

We have created a new type of vehicle, called human, and we directly inserted 20 vehicles of this type into the network. These vehicles will already be on the network when the simulation starts, contrary to the vehicles added by the inflow which will only start coming in the network after the simulation starts.

Note that it is not necessary to add vehicles at the start. If you don't wish that to happen, you can set num_vehicles=0, which is the default value if you don't specify num_vehicles at all.

Next, we are ready to import and create an empty InFlows object.


In [ ]:
from flow.core.params import InFlows

inflow = InFlows()

In order to add new inflows of vehicles of pre-defined types onto specific edges and lanes in the network, we use the InFlows object's add method. This function requires at least the following parameters (more will be shown in section 3):

  • veh_type: the type of the vehicles the inflow will create (this must match one of the types set in the VehicleParams object),
  • edge: the name of the edge (in the network) where the inflow will insert vehicles,
  • vehs_per_hour: the number of vehicles entering from the edge per hour at most (it may not be achievable due to congestion and safe driving behavior).

More options are shown in section 3.

We begin by creating an inflow of vehicles at a rate of 2000 vehicules per hour on the main highway:


In [ ]:
inflow.add(veh_type="human",
           edge="inflow_highway",
           vehs_per_hour=2000)

Next, we create a second inflow of vehicles on the on-merge lane at a lower rate of 100 vehicules par hour.


In [ ]:
inflow.add(veh_type="human",
           edge="inflow_merge",
           vehs_per_hour=100)

In the next section, we will add our inflows to our network and run a simulation to see them in action.

2. Running simulations with inflows

In the next section, we will add our inflows to our network and run a simulation to see them in action.

2. Running simulations with inflows

We are now ready to test our inflows in a simulation. Introducing these inflows into the network is handled by the backend scenario generation processes during the instantiation of the scenario object. To make this work, the InFlows object should be given as a parameter to the NetParams object, in addition to all other network-specific parameters.

For the merge network, this is done as follows:


In [ ]:
from flow.scenarios.merge import ADDITIONAL_NET_PARAMS
from flow.core.params import NetParams

additional_net_params = ADDITIONAL_NET_PARAMS.copy()
# make the part of the highway after the merge longer
additional_net_params['post_merge_length'] = 350  
# make the number of lanes on the highway be just one
additional_net_params['highway_lanes'] = 1

net_params = NetParams(inflows=inflow,  # our inflows
                       additional_params=additional_net_params)

Finally, we create and start the simulation, following what is explained in tutorial 1.

  • If the simulation in SUMO is going too fast, you can slow it down by sliding the "Delay" cursor from left to right.
  • Don't worry about potential warnings that might come up in the log while runing the simulation.

In [ ]:
from flow.core.params import SumoParams, EnvParams, InitialConfig
from flow.envs.loop.loop_accel import AccelEnv, ADDITIONAL_ENV_PARAMS
from flow.core.experiment import Experiment

sumo_params = SumoParams(render=True,
                         sim_step=0.2)

env_params = EnvParams(additional_params=ADDITIONAL_ENV_PARAMS)

initial_config = InitialConfig()

scenario = MergeScenario(name="merge-example",
                         vehicles=vehicles,
                         net_params=net_params,
                         initial_config=initial_config)

env = AccelEnv(env_params, sumo_params, scenario)

exp = Experiment(env)

_ = exp.run(1, 10000)

Running this simulation, we can see that a large number of vehicles are entering from the main highway, while only a sparse number of vehicles are entering from the on-merge, as we specified in the inflows. Feel free to try different vehs_per_hour values so as to have different inflow rates.

In the next section, we will see how to exploit the full capabilities of inflows.

3. Customizing inflows

If you run the previous simulation carefully, you will see that the vehicles entering the network start with no speed. Besides, if you replace additional_net_params['highway_lanes'] = 1 by additional_net_params['highway_lanes'] = 2 in section 1, thus making the highway two-lane-wide, you will see that vehicles only enter on the right lane.

In this section, we will see how to solve these issues, and how to customize inflows.

We saw that you can create an inflow by doing the following:


In [ ]:
inflow.add(veh_type="human",
           edge="inflow_highway",
           vehs_per_hour=2000)

However, this add method has a lot more parameters, which we will talk about now.

Let's start with parameters that allow you to specify the inflow rate, i.e. how many vehicles the inflow will add into the network.

There are 3 parameters to do this:

  • vehs_per_hour: we have seen this one before, this is the number of vehicles that should enter the network, in vehicles per hour, equally spaced. For example, as there are $60 \times 60 = 3600$ seconds in one hour, setting this parameter to $\frac{3600}{5}=720$ will result in vehicles entering the network every $5$ seconds.

  • probability: this is the probability (between 0 and 1) of a vehicle entering the network every second. For example, if we set this to $0.2$, then at each second of the simulation, a vehicle will enter the network with probability $\frac{1}{5}$.

  • period: this is the time in seconds between two vehicles are inserted. For example, setting this to $5$ would result in vehicles entering the network every $5$ seconds (which is effectively the same as setting vehs_per_hour to $720$).

Note that all these rates are maximum rates, meaning that if adding vehicles at the current rate would result in vehicles between too close to each other or colliding, then the rate will automatically be reduced.

Exactly one of these 3 parameters should be set, no more nor less. You can choose how you would rather have your vehicles enter the network. With vehs_per_hour and period (which are proportional to each other, use whichever is more convenient to define), vehicles will enter the network equally spaced, while the vehicles will be more randomly separated if you use probability.


Now let's look into where and how fast vehicles enter the network.

There are 2 parameters taking care of this:

  • depart_lane: this parameter lets you specify in which lane vehicles are inserted when they enter the network on an edge consisting of several lanes. It should be a positive int, 0 being the rightmost lane. However most of the time, you don't want vehicles entering through only one lane (although you could create one inflow for each lane). That's why there are other options for this parameter, which are the following strings:

    • "random": vehicles will enter on a random lane
    • "free": vehicles will enter on the least occupied lane
    • "best": vehicles will enter on the "free" lane among those which allow the vehicle the longest ride without needing to change lane
    • "first": vehicles will enter on the rightmost lane they can use

    By default, depart_lane is set to "free", which is why vehicles were only using the rightmost lane on the highway, if several lanes were available.

  • depart_speed: this parameter lets you specify the speed at which the vehicles will enter the network. It should be a positive float, in meters per second. If this speed is unsafe, the departure of the vehicles is delayed. Just like for depart_lane, there are other options for this parameter, which are the following strings:

    • "random": vehicles enter the edge with a random speed between 0 and the speed limit on the edge. The entering speed may be adapted to ensure that a safe distance to the leading vehicle is kept
    • "speedLimit": vehicles enter the edge with the maximum speed that is allowed on this edge. If that speed is unsafe, the departure is delayed.

By default, depart_speed is set to 0.


Finally, let's look at the rest of the parameters available:

  • name (str): a name for the inflow, which will also be used as a prefix for the ids of the vehicles created by it . This is set to "flow" by default.
  • begin (float): the time of the simulation, in seconds, at which the inflow should start producing vehicles. This is set to 1 second by default, which is the minimum value (setting it to 0 could cause collisions with vehicles that are manually added into the network).
  • end (float): the time of the simulation, in seconds, at which the inflow should stop producing vehicles. This is set to 24 hours (86400 seconds) by default.
  • number (int): the number of vehicles that should be procuded by the inflow. This is set to None by default, which make the inflow keep producing vehicles indefinitely until end is reached. If this parameter is specified, the end parameter won't be used. Note that if this number is small, it might not be enforced accurately due to rounding up.
  • kwargs (dict): you can specify additional parameters if you need to. These can include, for instance, a specific route for the vehicles to follow, an arrival speed, an arrival lane, or even a color for the vehicles, etc. For more information on all the available parameters, and more details on the existing parameters, see here.

Let us finish this section with a more complex example. This is what we want:

  • We will use the merge scenario, with no vehicles being manually pre-inserted into the network.

  • There will be 4 lanes on the main highway and 2 on the on-merge.

  • (1) Every hour, 10000 vehicles will enter the highway at maximum speed on a random lane, from the start of the simulation up until the end. These vehicles should be colored in white

  • (2) Every two seconds, a vehicle will enter the on-merge with no speed, on the right lane, from the start of the simulation up until the end. These vehicles should be colored in green.

  • (3) Every second, a vehicle should enter with probability 0.1 on the left lane of the on-merge, with random speed. These vehicles should only start entering the network after the first minute of simulation time, and there should be at most 30 of them throughout the whole simulation. These vehicles should be colored in red.

Note: for the colors, you will need to use the kwargs parameter. Also, set color_vehicles to False in the simulation parameters so that the vehicles are not colored automatically according to their types.

The result should look something like this:

You can try to do it yourself as an exercise if you want.

Here is a solution code:


In [ ]:
from flow.core.experiment import Experiment
from flow.core.params import NetParams, EnvParams, InitialConfig, InFlows, \
                             VehicleParams, SumoParams, SumoCarFollowingParams
from flow.controllers import IDMController
from flow.scenarios import MergeScenario
from flow.scenarios.merge import ADDITIONAL_NET_PARAMS
from flow.envs.loop.loop_accel import AccelEnv, ADDITIONAL_ENV_PARAMS


# create a vehicle type
vehicles = VehicleParams()
vehicles.add("human",
             acceleration_controller=(IDMController, {}),
             car_following_params=SumoCarFollowingParams(
                 speed_mode="obey_safe_speed"))


# create the inflows
inflows = InFlows()

# inflow for (1)
inflows.add(veh_type="human",
            edge="inflow_highway",
            vehs_per_hour=10000,
            depart_lane="random",
            depart_speed="speedLimit",
            color="white")

# inflow for (2)
inflows.add(veh_type="human",
            edge="inflow_merge",
            period=2,
            depart_lane=0,  # right lane
            depart_speed=0,
            color="green")

# inflow for (3)
inflows.add(veh_type="human",
           edge="inflow_merge",
           probability=0.1,
           depart_lane=1,  # left lane
           depart_speed="random",
           begin=60,  # 1 minute
           number=30,
           color="red")


# modify the network accordingly to instructions
# (the available parameters can be found in flow/scenarios/merge.py)
additional_net_params = ADDITIONAL_NET_PARAMS.copy()
additional_net_params['post_merge_length'] = 350  # this is just for visuals
additional_net_params['highway_lanes'] = 4
additional_net_params['merge_lanes'] = 2


# setup and run the simulation
net_params = NetParams(inflows=inflows,
                       additional_params=additional_net_params)

sim_params = SumoParams(render=True,
                         sim_step=0.2)
sim_params.color_vehicles = False

env_params = EnvParams(additional_params=ADDITIONAL_ENV_PARAMS)

initial_config = InitialConfig()

scenario = MergeScenario(name="merge-example",
                         vehicles=vehicles,
                         net_params=net_params,
                         initial_config=initial_config)

env = AccelEnv(env_params, sim_params, scenario)

exp = Experiment(env)

_ = exp.run(1, 10000)

In [ ]: