Simulation core¶
Core classes of the Python-based simulation engine.
World¶
- class unsim.World(name='', deltat=None, tmax=2000, print_mode=1, save_mode=1, show_mode=0, reaction_time=1, random_seed=None, auto_diverge=False, route_choice=None, logit_temperature=60.0, **kwargs)¶
Simulation world managing nodes, links, demand, and execution.
- Parameters:
name (str, optional) – Scenario name.
deltat (float or None, optional) – Simulation timestep width (s). None (default) for automatic setting as min(d_l/u_l) across all links.
tmax (float, optional) – Total simulation duration (s).
print_mode (int, optional) – Print progress messages. Default 1.
save_mode (int, optional) – Save results. Default 1.
reaction_time (float, optional) – Reaction time for FD computation (s). Default 1.
auto_diverge (bool, optional) – If True, automatically compute diverge/absorption ratios from OD demand composition and shortest paths. If False (default), use ratios specified in addNode (diverge_ratio, absorption_ratio).
- addLink(name, start_node, end_node, length, free_flow_speed=20, jam_density=0.2, merge_priority=1, capacity_out=10000000000.0, capacity_in=10000000000.0, capacity=None, backward_wave_speed=None, congestion_pricing=None, **kwargs)¶
Add a link to the network.
FD is triangular. By default, derived from free_flow_speed, jam_density, and reaction_time. Optionally override capacity and/or backward_wave_speed directly; jam_density is then recomputed for consistency.
- Parameters:
name (str) – Link name.
start_node (Node or str) – Upstream node (or its name).
end_node (Node or str) – Downstream node (or its name).
length (float) – Link length (m).
free_flow_speed (float, optional) – Free flow speed u (m/s). Default 20.
jam_density (float, optional) – Jam density kappa (veh/m). Default 0.2.
merge_priority (float, optional) – Merge priority weight. Default 1.
capacity_out (float, optional) – Maximum outflow rate (veh/s). Default 1e10 (inactive).
capacity_in (float, optional) – Maximum inflow rate (veh/s). Default 1e10 (inactive).
capacity (float or None, optional) – Link capacity q* (veh/s). Overrides the default q*=u*w*kappa/(u+w).
backward_wave_speed (float or None, optional) – Congestion wave speed w (m/s). Overrides w=1/(tau*kappa).
congestion_pricing (callable or None, optional) – Dynamic congestion pricing function. Takes time (s) as input, returns toll value in seconds (time equivalent). Used as additional cost in DUO route choice. Default None (no toll).
- Returns:
The created link.
- Return type:
- addNode(name, x=0, y=0, flow_capacity=10000000000.0, diverge_ratio=None, absorption_ratio=None, turning_fractions=None, **kwargs)¶
Add a node to the network.
- Parameters:
name (str) – Node name.
x (float, optional) – X coordinate for visualization.
y (float, optional) – Y coordinate for visualization.
flow_capacity (float, optional) – Maximum flow rate through this node (veh/s). Default 1e10 (inactive).
diverge_ratio (dict[str, float] or None, optional) – Diverge ratios {outlink_name: ratio}. Used when auto_diverge=False.
absorption_ratio (float or None, optional) – Fraction of inflow absorbed at this node. Used when auto_diverge=False.
turning_fractions (dict[str, dict[str, float]] or None, optional) – Turning fraction matrix for general nodes. Format: {inlink_name: {outlink_name: fraction}}.
- Returns:
The created node.
- Return type:
- adddemand(orig, dest, t_start, t_end, flow=-1, volume=-1, **kwargs)¶
Add OD traffic demand.
- Parameters:
orig (str or Node) – Origin node (name or object).
dest (str or Node) – Destination node (name or object).
t_start (float) – Demand start time (s).
t_end (float) – Demand end time (s).
flow (float, optional) – Demand flow rate (veh/s). Specify either flow or volume.
volume (float, optional) – Total demand volume (veh). Converted to flow internally.
- check_simulation_ongoing()¶
Check if there are remaining timesteps to simulate.
- Returns:
True if simulation has not reached TMAX.
- Return type:
bool
- exec_simulation(duration_t=None)¶
Run the LTM simulation.
Executes the main loop: compute demand/supply, apply node models, update cumulative counts. For route_choice=”duo”, runs the DUO reactive assignment loop.
- Parameters:
duration_t (float or None, optional) – Duration to simulate (s). None runs to completion.
- finalize_scenario()¶
Finalize scenario setup before simulation.
If deltat is None, automatically sets it to min(d_l/u_l) across all links. Validates deltat constraint, initializes arrays, computes shortest paths, diverge/absorption ratios, and creates Analyzer.
- Raises:
ValueError – If deltat exceeds d_l/u_l for any link.
- get_link(name)¶
Get a link by name.
Node¶
- class unsim.Node(W, name, x, y, flow_capacity=10000000000.0, diverge_ratio=None, absorption_ratio=None, turning_fractions=None)¶
Network node.
- Parameters:
W (World) – Parent world.
name (str) – Node name.
x (float) – X coordinate for visualization.
y (float) – Y coordinate for visualization.
flow_capacity (float, optional) – Maximum flow rate through this node (veh/s). Default 1e10 (inactive).
diverge_ratio (dict[str, float] or None, optional) – Diverge ratios {outlink_name: ratio}. Used when auto_diverge=False. Ratios for pass-through flow should sum to 1.0. None for equal split.
absorption_ratio (float or None, optional) – Fraction of inflow absorbed (destined for this node). 0 for pass-through. Used when auto_diverge=False. None defaults to 0.
turning_fractions (dict[str, dict[str, float]] or None, optional) – Turning fraction matrix for general nodes (>=2 inlinks, >=2 outlinks). Format: {inlink_name: {outlink_name: fraction}}. Used by the INM (Incremental Node Model).
- demand_queue¶
Vertical queue length at origin nodes (veh).
- Type:
float
- diverge_ratios¶
Fraction of pass-through flow going to each outlink.
- Type:
dict[str, float]
- absorption_ratio¶
Fraction of inflow destined for this node (0 for pass-through).
- Type:
float
- absorbed_count¶
Cumulative absorbed vehicles (veh).
- Type:
float
- build_turning_fraction_matrix()¶
Build the I x J turning fraction matrix from user specification.
Called by
World.finalize_scenario()for general nodes. If turning_fractions is not specified, defaults to equal split 1/J.
- compute_transfer(t_index, demands, supplies)¶
Compute flow rates at this node for one timestep.
Dispatches to the appropriate node model based on node type.
- get_demand_at(t)¶
Get external demand flow rate at time t.
- Parameters:
t (float) – Time in seconds.
- Returns:
Total demand flow rate (veh/s).
- Return type:
float
- node_type()¶
Classify node type from link topology.
- Returns:
One of “origin”, “destination”, “dummy”, “merge”, “diverge”, “general”.
- Return type:
str
Link¶
- class unsim.Link(W, name, start_node, end_node, length, free_flow_speed=20, jam_density=0.2, merge_priority=1, capacity_out=10000000000.0, capacity_in=10000000000.0, capacity=None, backward_wave_speed=None, congestion_pricing=None)¶
Network link with triangular fundamental diagram.
- Parameters:
W (World) – Parent world.
name (str) – Link name.
start_node (Node or str) – Upstream node (or its name).
end_node (Node or str) – Downstream node (or its name).
length (float) – Link length (m).
free_flow_speed (float, optional) – Free flow speed u (m/s). Default 20.
jam_density (float, optional) – Jam density kappa (veh/m). Default 0.2.
merge_priority (float, optional) – Merge priority weight at downstream merge nodes. Default 1.
capacity_out (float, optional) – Maximum outflow rate (veh/s). Default 1e10 (inactive).
capacity_in (float, optional) – Maximum inflow rate (veh/s). Default 1e10 (inactive).
capacity (float or None, optional) – Link capacity q* (veh/s). Overrides default derivation.
backward_wave_speed (float or None, optional) – Congestion wave speed w (m/s). Overrides default derivation.
congestion_pricing (callable or None, optional) – Dynamic congestion pricing function. Takes time (s) as input, returns toll value in seconds (time equivalent). Used as additional cost in DUO route choice. Default None (no toll).
- u¶
Free flow speed (m/s).
- Type:
float
- w¶
Congestion wave speed (m/s).
- Type:
float
- kappa¶
Jam density (veh/m).
- Type:
float
- q_star¶
Capacity (veh/s).
- Type:
float
- k_star¶
Critical density (veh/m).
- Type:
float
- cum_arrival¶
Cumulative inflow count N_U at each timestep.
- Type:
list[float]
- cum_departure¶
Cumulative outflow count N_D at each timestep.
- Type:
list[float]
- compute_N(t_seconds, x)¶
Compute cumulative count N(t, x) using Newell’s simplified KW theory.
N(t,x) = min{N_U(t - x/u), N_D(t - (d-x)/w) + kappa*(d-x)}
- Parameters:
t_seconds (float) – Time in seconds.
x (float) – Position from upstream end (m). 0 <= x <= length.
- Returns:
Cumulative vehicle count.
- Return type:
float
- compute_demand(t_index)¶
Compute sending flow (demand) D_l(t).
D_l(t) = min{(N_U(t+dt-d/u) - N_D(t)) / dt, q*, capacity_out}
- Parameters:
t_index (int) – Current timestep index.
- Returns:
Demand flow rate (veh/s).
- Return type:
float
- compute_supply(t_index)¶
Compute receiving flow (supply) S_l(t).
S_l(t) = min{(N_D(t+dt-d/w) + kappa*d - N_U(t)) / dt, q*, capacity_in}
- Parameters:
t_index (int) – Current timestep index.
- Returns:
Supply flow rate (veh/s).
- Return type:
float
- get_toll(t)¶
Get congestion toll at time t.
- Parameters:
t (float) – Time in seconds.
- Returns:
Toll value in seconds (time equivalent).
- Return type:
float
- init_after_scenario()¶
Initialize cumulative count arrays and precompute offsets.
Called by
World.finalize_scenario().
- instantaneous_travel_time(t_seconds, method='multipoint', n_segments=10)¶
Compute instantaneous link travel time.
- Parameters:
t_seconds (float) – Current time (s).
method (str, optional) – “avg_density” – single average density k_avg=(N_U-N_D)/L -> FD -> tau=L/v. “multipoint” – spatial integration with N(t,x) curves (default).
n_segments (int, optional) – Number of segments for multipoint method. Default 10.
- Returns:
Instantaneous travel time (s).
- Return type:
float
- k(t, x=None)¶
Compute density k = -dN/dx (veh/m) using Newell’s formula.
Averages are computed directly from N differences: - k(t, [x0,x1]) = (N(t,x0) - N(t,x1)) / (x1-x0) - k([t0,t1], [x0,x1]) = Edie’s k from 4-corner N values.
- Parameters:
t (float or list[float]) – Time (s). Scalar for a point, [t0, t1] for time-range average.
x (float or list[float] or None, optional) – Position from upstream end (m). Scalar for a point, [x0, x1] for space-range average. None for link midpoint.
- Returns:
Density, or average density over the specified range.
- Return type:
float
- q(t, x=None)¶
Compute flow rate q = dN/dt (veh/s) using Newell’s formula.
Averages are computed directly from N differences: - q([t0,t1], x) = (N(t1,x) - N(t0,x)) / (t1-t0) - q([t0,t1], [x0,x1]) = Edie’s q from 4-corner N values.
- Parameters:
t (float or list[float]) – Time (s). Scalar for a point, [t0, t1] for time-range average.
x (float or list[float] or None, optional) – Position from upstream end (m). Scalar for a point, [x0, x1] for space-range average. None for link midpoint.
- Returns:
Flow rate, or average flow rate over the specified range.
- Return type:
float
- v(t, x=None)¶
Compute speed v = q/k (m/s) using Newell’s formula.
For point queries, uses analytical FD-consistent computation. For range queries, v = q_range / k_range (space-mean speed).
- Parameters:
t (float or list[float]) – Time (s). Scalar for a point, [t0, t1] for time-range average.
x (float or list[float] or None, optional) – Position from upstream end (m). Scalar for a point, [x0, x1] for space-range average. None for link midpoint.
- Returns:
Speed, or average speed over the specified range.
- Return type:
float