Static Traffic Assignment

Static Traffic Assignment#

We can also perform static traffic assignment using Open-Source libraries for back-of-the-envelop analysis during debugging efforts

Exporting matrices#

sphinx_gallery_thumbnail_path = ‘../../examples/modelling_like_the_old_days/sta_results.png’

from pathlib import Path

from polaris.analyze.trip_metrics import TripMetrics
from polaris.runs.convergence.convergence_iteration import ConvergenceIteration
from polaris.runs.static_skimmer.static_assign import static_assignment
from polaris.runs.static_skimmer.static_graph import build_graph

Matrix#

We get the demand matrices for the AM peak for one iteration

project_dir = Path("/tmp/Bloomington")
supply_pth = project_dir / "Bloomington-Supply.sqlite"

iteration_3 = ConvergenceIteration.from_dir(project_dir / "Bloomington_iteration_3")
tm3 = TripMetrics(supply_pth, iteration_3.files.demand_db)

# Let's say that one afternoon peak hour is from 16:45AM to 17:45AM, so we egt trips starting during that time
matrix = tm3.vehicle_trip_matrix(from_start_time=16.75 * 3600, to_start_time=17.75 * 3600)

# This matrix has multiple vehicle types, and we could separate them to make sure we observe
# link type constraints, but that shouldn't be needed in a back-of-the-envelope exercise
# Instead, we will just multiply the PCEs for each matrix to the matrices themselves

pces = {"SOV_0": 1.0, "TAXI_9": 1.0, "MD_TRUCK_17": 2.5, "HD_TRUCK_18": 4.0, "BPLATE_19": 2.0, "LD_TRUCK_20": 1.8}
for i, mat in enumerate(matrix.names):
    matrix.matrices[:, :, i] *= pces[mat]

Graph#

We build an AequilibraE graph using the underlying Polaris supply model

This procedure asserts some things about the links so we can get everything we need for a static traffic assignment Assumptions are made about (HOURLY) capacities and centroid connector placements

graph = build_graph(supply_pth)

One can see the results of these assumptions in the graph object

graph.network.head()
link_id distance a_node b_node capacity_ab capacity_ba time_ab time_ba direction connector_penalty source id
0 4 118.540138 304 305 300 300 0.147315 0.147315 0 0.0 NaN NaN
1 6 102.954767 305 307 300 300 0.127946 0.127946 0 0.0 NaN NaN
2 10 76.423068 310 311 300 300 0.094974 0.094974 0 0.0 NaN NaN
3 11 295.416116 312 310 300 300 0.367126 0.367126 0 0.0 NaN NaN
4 12 187.871361 311 313 300 300 0.233476 0.233476 0 0.0 NaN NaN


Assignment#

We perform traffic assignment and skimming using the AequilibraE library

We can load the assignment parameters from the default values and change them

from polaris.runs.static_skimmer.static_skimmer_inputs import STAInputs

sta_pars = STAInputs()

# Not sure why somewhat would want msa over bi-conjugate Frank-Wolfe, but...
sta_pars.assignment_algorithm = "msa"
sta_pars.max_iterations = 10
sta_pars.rgap = 0.01

# By default assignment uses BPR, but we can change the parameters
sta_pars.bpr_alpha = 0.14
sta_pars.bpr_beta = 3.9

No turning constraints are observed in this assignment

assig = static_assignment(graph, matrix, sta_pars)
combined                                          :   0%|          | 0/185 [00:00<?, ?it/s]
Equilibrium Assignment                            :   0%|          | 0/10 [00:00<?, ?it/s]

Then we can see the results

link_loads = assig.results()
link_loads.head()
SOV_0_ab SOV_0_ba SOV_0_tot TAXI_9_ab TAXI_9_ba TAXI_9_tot Preload_AB Preload_BA Preload_tot Congested_Time_AB Congested_Time_BA Congested_Time_Max Delay_factor_AB Delay_factor_BA Delay_factor_Max VOC_AB VOC_BA VOC_max PCE_AB PCE_BA PCE_tot
link_id
4 74.666667 69.333333 144.0 4.0 0.0 4.0 0.0 0.0 0.0 0.147426 0.147383 0.147426 1.000757 1.000462 1.000757 0.262222 0.231111 0.262222 78.666667 69.333333 148.0
6 74.666667 69.333333 144.0 4.0 0.0 4.0 0.0 0.0 0.0 0.128043 0.128005 0.128043 1.000757 1.000462 1.000757 0.262222 0.231111 0.262222 78.666667 69.333333 148.0
10 0.000000 0.000000 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.094974 0.094974 0.094974 1.000000 1.000000 1.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.0
11 0.000000 0.000000 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.367126 0.367126 0.367126 1.000000 1.000000 1.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.0
12 0.000000 0.000000 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.233476 0.233476 0.233476 1.000000 1.000000 1.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.0


And get the skims

assig_class = assig.classes[0]
skim = assig_class.results.skims
# And show some elements
skim.time[:10, :10]
array([[ 0.        , 10.72760513, 11.20617489,  3.05766833,  9.56641341,
        12.06173296,  7.45214589,  8.55200264, 18.9720379 , 17.17400118],
       [ 9.90874479,  0.        ,  6.95467387,  7.99508093,  9.51255336,
         4.37168556,  3.95590967,  2.60239532, 10.99189049,  8.77673166],
       [ 6.13458828,  5.90068792,  0.        ,  4.22092442,  5.40889134,
         8.0112748 ,  5.20155633,  6.24198456, 12.61845729, 10.40329846],
       [ 3.0876974 ,  8.84397034,  9.3225401 ,  0.        ,  7.68277862,
        10.17809817,  5.5685111 ,  6.66836785, 17.0884031 , 15.29036639],
       [14.96908699, 13.62285316, 15.88315152, 13.05542312,  0.        ,
        15.73344004, 14.03605503, 13.9641498 , 20.34062254, 18.1254637 ],
       [ 9.14546826,  6.63200265,  3.58620029,  7.2318044 ,  8.41977131,
         0.        ,  8.21243631,  6.9732993 , 13.34977203, 11.1346132 ],
       [ 7.48213478,  4.80185237,  8.57545896,  5.56847092,  7.14113506,
         6.1359802 ,  0.        ,  2.47452003, 13.46340725, 11.24824842],
       [ 8.55973784,  3.44953778,  7.36665393,  6.64607398,  8.21873812,
         4.78366561,  2.47571979,  0.        , 12.11109266,  9.89593383],
       [12.67450177,  6.00695205,  8.61448033, 10.76083791, 12.27831034,
         6.03149201,  6.72166665,  5.3681523 ,  0.        ,  7.86616924],
       [18.74260674, 12.59716769, 15.20469597, 16.82894288, 15.04775945,
        12.62170766, 13.3118823 , 11.95836795, 10.08493359,  0.        ]])

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

Gallery generated by Sphinx-Gallery