Project Scenarios#

In this example, we show how to use AequilibraE’s scenario system to manage multiple model variants within a single project, using different example networks to demonstrate scenario isolation and management.

# Imports
from uuid import uuid4
from tempfile import gettempdir
from pathlib import Path

from aequilibrae.utils.create_example import create_example
from aequilibrae import TrafficAssignment, TrafficClass
# We create the example project inside our temp folder.
fldr = Path(gettempdir()) / uuid4().hex
project = create_example(fldr, "sioux_falls")

Working with scenarios#

Let’s first see what scenarios exist in our project

project.list_scenarios()
scenario_name description
0 root The default, and root, scenario for an Aequilb...


The root scenario is always present and represents the base model. Let’s examine the current scenario’s network

print(f"Current scenario network has {len(project.network.links.data)} links")
print(f"Current scenario network has {len(project.network.nodes.data)} nodes")
Current scenario network has 76 links
Current scenario network has 24 nodes

Creating new scenarios#

We can create empty scenarios or clone existing ones

# Create an empty scenario to manually populate with a future/different network
project.create_empty_scenario("test_modifications", "Scenario for testing network modifications")

# Clone the root scenario to preserve the original network
project.clone_scenario("limited_capacity", "Testing different assignment parameters")

Let’s see our updated scenario list

project.list_scenarios()
scenario_name description
0 root The default, and root, scenario for an Aequilb...
1 test_modifications Scenario for testing network modifications
2 limited_capacity Testing different assignment parameters


Switching between scenarios#

Each scenario operates independently with its own data

# Switch to the cloned scenario
project.use_scenario("limited_capacity")
print(f"This scenario has {len(project.network.links.data)} links")

# Modify the network
with project.db_connection as conn:
    conn.execute("UPDATE links SET capacity_ab=capacity_ab/2, capacity_ba=capacity_ba/2 WHERE link_id > 20 AND link_id < 50")
This scenario has 76 links

Let’s perform a traffic assignment in this scenario with lowered capacity

# Build the network graph
project.network.build_graphs(fields=["distance", "capacity_ab", "capacity_ba"], modes=["c"])
graph = project.network.graphs["c"]
graph.set_graph("distance")
graph.set_blocked_centroid_flows(False)

# Get the demand matrix
mat = project.matrices.get_matrix("demand_omx")
mat.computational_view()

# Create traffic assignment with alternative parameters
assigclass = TrafficClass("car", graph, mat)
assignment = TrafficAssignment(project)
assignment.add_class(assigclass)
assignment.set_vdf("BPR")

assignment.set_vdf_parameters({"alpha": 0.15, "beta": 4.0})
assignment.set_capacity_field("capacity")
assignment.set_time_field("distance")
assignment.max_iter = 10
assignment.set_algorithm("msa")

assignment.execute()

# Save results specific to this scenario
assignment.save_results("alternative_assignment")

print(f"Assignment completed. Total flow: {assigclass.results.total_link_loads.sum():.2f}")
/home/runner/work/aequilibrae/aequilibrae/aequilibrae/paths/graph.py:218: ChainedAssignmentError: A value is being set on a copy of a DataFrame or Series through chained assignment.
Such chained assignment never works to update the original DataFrame or Series, because the intermediate object on which we are setting values always behaves as a copy (due to Copy-on-Write).

Try using '.loc[row_indexer, col_indexer] = value' instead, to perform the assignment in a single step.

See the documentation for a more detailed explanation: https://pandas.pydata.org/pandas-docs/stable/user_guide/copy_on_write.html#chained-assignment
  build_compressed_graph(self, remove_dead_ends)

car                                               :   0%|          | 0/24 [00:00<?, ?it/s]
Equilibrium Assignment                            :   0%|          | 0/10 [00:00<?, ?it/s]
All-or-Nothing - Traffic Class: car               :  10%|█         | 1/10 [00:00<00:00, 36792.14it/s]
All-or-Nothing - Traffic Class: car               :  10%|█         | 1/10 [00:00<00:00, 8456.26it/s]
All-or-Nothing - Traffic Class: car               :   0%|          | 0/10 [00:00<?, ?it/s]
All-or-Nothing - Traffic Class: car - Zones: 0/24 :   0%|          | 0/10 [00:00<?, ?it/s]
All-or-Nothing - Traffic Class: car - Zones: 10/24:   0%|          | 0/10 [00:00<?, ?it/s]
All-or-Nothing - Traffic Class: car - Zones: 20/24:   0%|          | 0/10 [00:00<?, ?it/s]
All-or-Nothing - Traffic Class: car - Zones: 24/24:   0%|          | 0/10 [00:00<?, ?it/s]
Equilibrium Assignment - Iteration: 1/10 - RGap: inf:   0%|          | 0/10 [00:00<?, ?it/s]
Equilibrium Assignment                            :  20%|██        | 2/10 [00:00<00:00, 176.96it/s]
All-or-Nothing - Traffic Class: car               :  20%|██        | 2/10 [00:00<00:00, 175.63it/s]
All-or-Nothing - Traffic Class: car               :  20%|██        | 2/10 [00:00<00:00, 174.42it/s]
All-or-Nothing - Traffic Class: car               :   0%|          | 0/10 [00:00<?, ?it/s]
All-or-Nothing - Traffic Class: car - Zones: 0/24 :   0%|          | 0/10 [00:00<?, ?it/s]
All-or-Nothing - Traffic Class: car - Zones: 10/24:   0%|          | 0/10 [00:00<?, ?it/s]
All-or-Nothing - Traffic Class: car - Zones: 20/24:   0%|          | 0/10 [00:00<?, ?it/s]
All-or-Nothing - Traffic Class: car - Zones: 24/24:   0%|          | 0/10 [00:00<?, ?it/s]
Equilibrium Assignment - Iteration: 2/10 - RGap: 0.717655:   0%|          | 0/10 [00:00<?, ?it/s]
Equilibrium Assignment                            :  30%|███       | 3/10 [00:00<00:00, 107.50it/s]
All-or-Nothing - Traffic Class: car               :  30%|███       | 3/10 [00:00<00:00, 107.19it/s]
All-or-Nothing - Traffic Class: car               :  30%|███       | 3/10 [00:00<00:00, 106.92it/s]
All-or-Nothing - Traffic Class: car               :   0%|          | 0/10 [00:00<?, ?it/s]
All-or-Nothing - Traffic Class: car - Zones: 0/24 :   0%|          | 0/10 [00:00<?, ?it/s]
All-or-Nothing - Traffic Class: car - Zones: 10/24:   0%|          | 0/10 [00:00<?, ?it/s]
All-or-Nothing - Traffic Class: car - Zones: 20/24:   0%|          | 0/10 [00:00<?, ?it/s]
All-or-Nothing - Traffic Class: car - Zones: 24/24:   0%|          | 0/10 [00:00<?, ?it/s]
Equilibrium Assignment - Iteration: 3/10 - RGap: 0.943093:   0%|          | 0/10 [00:00<?, ?it/s]
Equilibrium Assignment                            :  40%|████      | 4/10 [00:00<00:00, 95.67it/s]
All-or-Nothing - Traffic Class: car               :  40%|████      | 4/10 [00:00<00:00, 95.47it/s]
All-or-Nothing - Traffic Class: car               :  40%|████      | 4/10 [00:00<00:00, 95.30it/s]
All-or-Nothing - Traffic Class: car               :   0%|          | 0/10 [00:00<?, ?it/s]
All-or-Nothing - Traffic Class: car - Zones: 0/24 :   0%|          | 0/10 [00:00<?, ?it/s]
All-or-Nothing - Traffic Class: car - Zones: 10/24:   0%|          | 0/10 [00:00<?, ?it/s]
All-or-Nothing - Traffic Class: car - Zones: 20/24:   0%|          | 0/10 [00:00<?, ?it/s]
All-or-Nothing - Traffic Class: car - Zones: 24/24:   0%|          | 0/10 [00:00<?, ?it/s]
Equilibrium Assignment - Iteration: 4/10 - RGap: 0.750474:   0%|          | 0/10 [00:00<?, ?it/s]
Equilibrium Assignment                            :  50%|█████     | 5/10 [00:00<00:00, 148.14it/s]
All-or-Nothing - Traffic Class: car               :  50%|█████     | 5/10 [00:00<00:00, 147.78it/s]
All-or-Nothing - Traffic Class: car               :  50%|█████     | 5/10 [00:00<00:00, 147.47it/s]
All-or-Nothing - Traffic Class: car               :   0%|          | 0/10 [00:00<?, ?it/s]
All-or-Nothing - Traffic Class: car - Zones: 0/24 :   0%|          | 0/10 [00:00<?, ?it/s]
All-or-Nothing - Traffic Class: car - Zones: 10/24:   0%|          | 0/10 [00:00<?, ?it/s]
All-or-Nothing - Traffic Class: car - Zones: 20/24:   0%|          | 0/10 [00:00<?, ?it/s]
All-or-Nothing - Traffic Class: car - Zones: 24/24:   0%|          | 0/10 [00:00<?, ?it/s]
Equilibrium Assignment - Iteration: 5/10 - RGap: 0.688544:   0%|          | 0/10 [00:00<?, ?it/s]
Equilibrium Assignment                            :  60%|██████    | 6/10 [00:00<00:00, 275.52it/s]
All-or-Nothing - Traffic Class: car               :  60%|██████    | 6/10 [00:00<00:00, 274.49it/s]
All-or-Nothing - Traffic Class: car               :  60%|██████    | 6/10 [00:00<00:00, 273.61it/s]
All-or-Nothing - Traffic Class: car               :   0%|          | 0/10 [00:00<?, ?it/s]
All-or-Nothing - Traffic Class: car - Zones: 0/24 :   0%|          | 0/10 [00:00<?, ?it/s]
All-or-Nothing - Traffic Class: car - Zones: 10/24:   0%|          | 0/10 [00:00<?, ?it/s]
All-or-Nothing - Traffic Class: car - Zones: 20/24:   0%|          | 0/10 [00:00<?, ?it/s]
All-or-Nothing - Traffic Class: car - Zones: 24/24:   0%|          | 0/10 [00:00<?, ?it/s]
Equilibrium Assignment - Iteration: 6/10 - RGap: 0.556378:   0%|          | 0/10 [00:00<?, ?it/s]
Equilibrium Assignment                            :  70%|███████   | 7/10 [00:00<00:00, 159.75it/s]
All-or-Nothing - Traffic Class: car               :  70%|███████   | 7/10 [00:00<00:00, 159.43it/s]
All-or-Nothing - Traffic Class: car               :  70%|███████   | 7/10 [00:00<00:00, 159.16it/s]
All-or-Nothing - Traffic Class: car               :   0%|          | 0/10 [00:00<?, ?it/s]
All-or-Nothing - Traffic Class: car - Zones: 0/24 :   0%|          | 0/10 [00:00<?, ?it/s]
All-or-Nothing - Traffic Class: car - Zones: 10/24:   0%|          | 0/10 [00:00<?, ?it/s]
All-or-Nothing - Traffic Class: car - Zones: 20/24:   0%|          | 0/10 [00:00<?, ?it/s]
All-or-Nothing - Traffic Class: car - Zones: 24/24:   0%|          | 0/10 [00:00<?, ?it/s]
Equilibrium Assignment - Iteration: 7/10 - RGap: 0.418738:   0%|          | 0/10 [00:00<?, ?it/s]
Equilibrium Assignment                            :  80%|████████  | 8/10 [00:00<00:00, 243.41it/s]
All-or-Nothing - Traffic Class: car               :  80%|████████  | 8/10 [00:00<00:00, 242.72it/s]
All-or-Nothing - Traffic Class: car               :  80%|████████  | 8/10 [00:00<00:00, 242.14it/s]
All-or-Nothing - Traffic Class: car               :   0%|          | 0/10 [00:00<?, ?it/s]
All-or-Nothing - Traffic Class: car - Zones: 0/24 :   0%|          | 0/10 [00:00<?, ?it/s]
All-or-Nothing - Traffic Class: car - Zones: 10/24:   0%|          | 0/10 [00:00<?, ?it/s]
All-or-Nothing - Traffic Class: car - Zones: 20/24:   0%|          | 0/10 [00:00<?, ?it/s]
All-or-Nothing - Traffic Class: car - Zones: 24/24:   0%|          | 0/10 [00:00<?, ?it/s]
Equilibrium Assignment - Iteration: 8/10 - RGap: 0.262796:   0%|          | 0/10 [00:00<?, ?it/s]
Equilibrium Assignment                            :  90%|█████████ | 9/10 [00:00<00:00, 322.15it/s]
All-or-Nothing - Traffic Class: car               :  90%|█████████ | 9/10 [00:00<00:00, 321.21it/s]
All-or-Nothing - Traffic Class: car               :  90%|█████████ | 9/10 [00:00<00:00, 320.39it/s]
All-or-Nothing - Traffic Class: car               :   0%|          | 0/10 [00:00<?, ?it/s]
All-or-Nothing - Traffic Class: car - Zones: 0/24 :   0%|          | 0/10 [00:00<?, ?it/s]
All-or-Nothing - Traffic Class: car - Zones: 10/24:   0%|          | 0/10 [00:00<?, ?it/s]
All-or-Nothing - Traffic Class: car - Zones: 20/24:   0%|          | 0/10 [00:00<?, ?it/s]
All-or-Nothing - Traffic Class: car - Zones: 24/24:   0%|          | 0/10 [00:00<?, ?it/s]
Equilibrium Assignment - Iteration: 9/10 - RGap: 0.199138:   0%|          | 0/10 [00:00<?, ?it/s]
Equilibrium Assignment                            : 100%|██████████| 10/10 [00:00<00:00, 298.52it/s]
All-or-Nothing - Traffic Class: car               : 100%|██████████| 10/10 [00:00<00:00, 297.58it/s]
All-or-Nothing - Traffic Class: car               : 100%|██████████| 10/10 [00:00<00:00, 296.70it/s]
All-or-Nothing - Traffic Class: car               :   0%|          | 0/10 [00:00<?, ?it/s]
All-or-Nothing - Traffic Class: car - Zones: 0/24 :   0%|          | 0/10 [00:00<?, ?it/s]
All-or-Nothing - Traffic Class: car - Zones: 10/24:   0%|          | 0/10 [00:00<?, ?it/s]
All-or-Nothing - Traffic Class: car - Zones: 20/24:   0%|          | 0/10 [00:00<?, ?it/s]
All-or-Nothing - Traffic Class: car - Zones: 24/24:   0%|          | 0/10 [00:00<?, ?it/s]
Equilibrium Assignment - Iteration: 10/10 - RGap: 0.174405:   0%|          | 0/10 [00:00<?, ?it/s]

Assignment completed. Total flow: 1136690.00

Switch to empty scenario for modifications

project.use_scenario("test_modifications")
print(f"Empty scenario has {len(project.network.links.data)} links")

# This scenario starts with an empty network, suitable for building from scratch
# or testing specific network configurations
Empty scenario has 0 links

Scenario isolation demonstration#

Let’s switch back to root and show that scenarios are isolated

project.use_scenario("root")
print(f"Back to root scenario with {len(project.network.links.data)} links")

# Check results - only root scenario results should be visible
root_results = project.results.list()
print(f"Root scenario has {len(root_results)} result tables")

# Switch to alternative scenario and check its results
project.use_scenario("limited_capacity")
alt_results = project.results.list()
print(f"Alternative scenario has {len(alt_results)} result tables")

# Each scenario maintains its own results database
alternative_assignment_exists = "alternative_assignment" in alt_results["table_name"].values
print(f"Alternative assignment result exists in this scenario: {alternative_assignment_exists}")
Back to root scenario with 76 links
Root scenario has 0 result tables
Alternative scenario has 1 result tables
Alternative assignment result exists in this scenario: True

Best practices for scenario management#

# Always return to root when doing project-wide operations
project.use_scenario("root")

# List scenarios for reference
final_scenarios = project.list_scenarios()
print("\nFinal scenario summary:")
for _, scenario in final_scenarios.iterrows():
    project.use_scenario(scenario['scenario_name'])
    link_count = len(project.network.links.data)
    result_count = len(project.results.list())
    print(f"  {scenario['scenario_name']}: {link_count} links, {result_count} results")
    print(f"    Description: {scenario['description']}")
Final scenario summary:
  root: 76 links, 0 results
    Description: The default, and root, scenario for an AequilbraE project. The name "root" is treat as special case.
  test_modifications: 0 links, 0 results
    Description: Scenario for testing network modifications
  limited_capacity: 76 links, 1 results
    Description: Testing different assignment parameters

Clean up

project.use_scenario("root")  # Always end on root scenario
mat.close()
project.close()

Total running time of the script: (0 minutes 4.973 seconds)

Gallery generated by Sphinx-Gallery