Note
Go to the end to download the full example code.
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.
References
See also
Several functions, methods, classes and modules are used in this example:
aequilibrae.Project.list_scenarios()
aequilibrae.Project.use_scenario()
aequilibrae.Project.create_empty_scenario()
aequilibrae.Project.clone_scenario()
# Imports
from uuid import uuid4
from tempfile import gettempdir
from pathlib import Path
from os.path import join
import pandas as pd
from aequilibrae.utils.create_example import create_example
from aequilibrae import TrafficAssignment, TrafficClass
No pre-existing parameter file exists for this project. Will use default
# 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()
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")
No pre-existing parameter file exists for this project. Will use default
Let’s see our updated scenario list
project.list_scenarios()
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}")
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, 30393.51it/s]
All-or-Nothing - Traffic Class: car : 10%|█ | 1/10 [00:00<00:00, 7681.88it/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, 378.97it/s]
All-or-Nothing - Traffic Class: car : 20%|██ | 2/10 [00:00<00:00, 370.64it/s]
All-or-Nothing - Traffic Class: car : 20%|██ | 2/10 [00:00<00:00, 364.77it/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, 654.95it/s]
All-or-Nothing - Traffic Class: car : 30%|███ | 3/10 [00:00<00:00, 641.85it/s]
All-or-Nothing - Traffic Class: car : 30%|███ | 3/10 [00:00<00:00, 630.72it/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, 808.38it/s]
All-or-Nothing - Traffic Class: car : 40%|████ | 4/10 [00:00<00:00, 792.84it/s]
All-or-Nothing - Traffic Class: car : 40%|████ | 4/10 [00:00<00:00, 779.50it/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, 1136.61it/s]
All-or-Nothing - Traffic Class: car : 50%|█████ | 5/10 [00:00<00:00, 1113.55it/s]
All-or-Nothing - Traffic Class: car : 50%|█████ | 5/10 [00:00<00:00, 1093.46it/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, 1348.29it/s]
All-or-Nothing - Traffic Class: car : 60%|██████ | 6/10 [00:00<00:00, 1321.04it/s]
All-or-Nothing - Traffic Class: car : 60%|██████ | 6/10 [00:00<00:00, 1297.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: 6/10 - RGap: 0.556378: 0%| | 0/10 [00:00<?, ?it/s]
Equilibrium Assignment : 70%|███████ | 7/10 [00:00<00:00, 1514.81it/s]
All-or-Nothing - Traffic Class: car : 70%|███████ | 7/10 [00:00<00:00, 1484.63it/s]
All-or-Nothing - Traffic Class: car : 70%|███████ | 7/10 [00:00<00:00, 1458.53it/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, 1829.28it/s]
All-or-Nothing - Traffic Class: car : 80%|████████ | 8/10 [00:00<00:00, 1791.96it/s]
All-or-Nothing - Traffic Class: car : 80%|████████ | 8/10 [00:00<00:00, 1728.90it/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, 2039.92it/s]
All-or-Nothing - Traffic Class: car : 90%|█████████ | 9/10 [00:00<00:00, 1999.30it/s]
All-or-Nothing - Traffic Class: car : 90%|█████████ | 9/10 [00:00<00:00, 1963.73it/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, 2170.85it/s]
All-or-Nothing - Traffic Class: car : 100%|██████████| 10/10 [00:00<00:00, 2129.74it/s]
All-or-Nothing - Traffic Class: car : 100%|██████████| 10/10 [00:00<00:00, 2093.38it/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()
This project at /tmp/c209fbddcf054b1b94a3bcbccd398a83 is already closed
Total running time of the script: (0 minutes 3.385 seconds)