Routing¶
At a branching node, a routing policy decides which outbound link each vehicle
takes. Because every vehicle carries its own mutable route, routing is a thin
layer around the flow arithmetic — it only chooses next links and never changes
the model dynamics. See Vehicles & routing.
The three options¶
Static routes (default)¶
With no policy, StaticRoutePolicy reads each vehicle's own route. Give each
vehicle a route over real link ids and the network follows it:
This reproduces the paper's behaviour exactly.
Shortest path¶
ShortestPathPolicy plans each vehicle's path over the live network graph (via
NetworkX) toward its destination. Pass it to compile():
from mesoltm import grid_network, ShortestPathPolicy
net = grid_network(4, 4, link_length=200.0, all_nodes_od=True)
# ... set origins/destinations ...
sim = net.compile(time_step=1.0, total_time=400.0,
routing_policy=ShortestPathPolicy(dynamic=True))
dynamic=True rebuilds the routing graph on every decision, so a changing cost
takes effect immediately (rerouting happens automatically).
Your own policy¶
Any object implementing the RoutingPolicy protocol —
a single next_link(vehicle, current_link_id, node, state) -> int | None — can be
used.
Congestion-aware cost¶
By default ShortestPathPolicy minimises continuous free-flow travel time
(state.continuous_free_flow_time(link_id), i.e. length / v_f). Supply a cost
callback cost(link_id, state) -> float to route on live conditions — the state
is the NetworkState, so you can read
occupancy, density, or cumulative flows:
def congestion_cost(link_id, state):
# free-flow time plus a penalty that grows with the link's current load
return state.continuous_free_flow_time(link_id) + 0.5 * state.occupancy(link_id)
policy = ShortestPathPolicy(cost=congestion_cost, dynamic=True)
This spreads traffic onto slower lanes and detours as they become the faster
choice. See parallel_links_demo.py and
congestion_aware_routing.py.
Planning full routes¶
ShortestPathPolicy also exposes a route(state, from_node, to_node) planner that
returns the full ordered list of real link ids — useful to seed a vehicle's route
before injecting it, or inside a
rerouting plugin. When re-planning many vehicles against the same
live state in one step, call refresh(state) once and temporarily set
dynamic=False so the lookups reuse one graph build.
Reactive rerouting¶
For rerouting driven by events rather than a static cost — coin-toss access control, closing a link, re-planning at every node — use a plugin. It runs first each step and can rewrite any in-network vehicle's route.