User reference

dyntapy.assignments

The DiGraph format of networkx is very flexible in its formatting. We describe below the semantics and labelling requirements for the DiGraph in order to use the assignments in dyntapy.

All nodes and links need to have fully specified attributes for a subset of the General Modeling Network Specification (GMNS), see https://github.com/zephyr-data-specs/GMNS.

For the links we need: ‘from_node_id’, ‘to_node_id’, ‘link_id’, ‘lanes’, ‘capacity’, ‘length’, ‘free_speed’

optional are:

‘geometry’: shapely.geometry.LineString

if it is not set we assume a straight line between the two nodes.

‘link_type’: int,

set to 1 for source connectors, -1 for sinks, 0 otherwise.

‘connector’: bool,

True if the link is a connector

For the nodes: ‘node_id’, ‘x_coord’, ‘y_coord’, ‘ctrl_type’, ‘node_type’

optional are:

‘centroid’: bool,

True if the node is a centroid

The inclusion of the ‘link_type’, ‘connector’ and ‘centroid’ attributes are deviations from GMNS.

The graph’s nodes and edges need to be labelled consecutively and starting from 0. Many of the assignment algorithms also implicitly assume that the graph is strongly connected. This can be verified with networkx:

>>> networkx.strongly_connected_components(g)

If there is only a single element returned as the list of components, the graph is strongly connected.

All of these requirements are met if dyntapy’s functions for extracting the network from OpenStreetMap are used.

class dyntapy.assignments.DynamicAssignment(network, dynamic_demand, simulation_time)

This class stores all the information needed for the assignment itself. upon initialisation both the network and dynamic demand are transformed into internal representations.

run(method: str = 'i_ltm_aon')
Parameters:

method ({'i_ltm_aon','incremental_assignment'})

Returns:

dyntapy.results.DynamicResult

Notes

All the presented options utilize the same dynamic network loading (DNL) and route choice component, that is the iterative link transmission model [1] and an iterative procedure to update a time-dependent arrival map, see [2].

‘i_ltm_aon’ refers to a dynamic deterministic user equilibrium solution, note that for congested networks this is not guaranteed to converge below a gap of 0.01.

‘incremental_assignment’ assigns the demands in chunks and updates the both costs and route choice after each DNL.

References

class dyntapy.assignments.StaticAssignment(g, od_graph)

This class stores all the information needed for the assignment itself. Upon initialisation both the network and demand are transformed into internal representations.

Parameters:
  • g (networkx.DiGraph) – road network graph with attributes and labelling as specified in the module description.

  • od_graph (networkx.DiGraph) – graph with centroids as nodes with specified coordinates as ‘x_coord’ and ‘y_coord’. For each OD pair with a non-zero demand there is a link with a corresponding ‘flow’ element.

run(method, store_iterations=False, **kwargs)
Parameters:
  • method ({'dial_b', 'msa', 'sun', 'sue'})

  • store_iterations (bool) – set to True to get information on the individual iterations

Returns:

Notes

‘msa’ and ‘dial_b’ try to find the static deterministic user equilibrium.

‘msa’ refers to the Method of Successive Averages, a well known method in Traffic Assignments that tends to zig-zag around equilibrium.

‘dial_b’ refers to Dial’s Algorithm B, a bush-based assignment algorithm [3].

‘sun’ returns a stochastic uncongested assignment of flows on the free-flow travel times that are determined by the lengths and speeds of the links. It is based on Dial’s method, see [4]. It does not consider the whole path set and rests the definition of ‘efficient links’ to allow for computations on an acyclic graph.

‘sun’ and ‘msa’ are included for educational use.

‘dial_b’ has been optimized and converges quickly even for large networks with thousands of links.

References

dyntapy.demand_data

dyntapy.demand_data.add_centroids(g, X, Y, k=1, method='turn', euclidean=False, on_top=False, **kwargs)

Adds centroids to g.

Parameters:
  • g (networkx.Digraph) – road network graph, containing only road network edges and nodes

  • X (numpy.ndarray) – float, 1D - lon of centroids

  • Y (numpy.ndarray) – float, 1D - lat of centroids

  • k (int) – number of road network nodes to connect to per centroid.

  • method ({'turn', 'link'}) – whether to add link or turn connectors

  • euclidean (bool, optional) – set to True for toy networks that use the euclidean coordinate system

  • on_top (bool, optional) – set to True if extra nodes are made on top of each other

  • **kwargs (iterable, optional) – any keyword arguments are passed as additional attributes into the graph and appear as attributes of the centroids. They are assumed to be iterable and of the same length as X.

Returns:

networkx.DiGraph – new graph with centroids and connectors

Notes

if method is ‘link’ k*2 connectors are added per centroid, one for each direction. if method is ‘turn’k*2+2 connectors are added per centroid. There is another artificial node between the centroid and the first intersection node. All connector turns share the first starting link from centroid to this artificial node.

The route choice algorithms for DTA within dyntapy rely on iterative computations on the link-turn graph rather than the node-link graph. Within the network one can take the current link and evaluate the options as the set of all outgoing turns. Evaluating the choice of the next turn to take from a centroid node without a dummy starting link and turns is cumbersome because the structure differs. We add these dummy turns to keep the algorithms simpler.

dyntapy.demand_data.add_connectors(x, y, u, k, g, new_g, euclidean)

adding connectors to new_g from starting node u with coordinates x and y to nearest k intersection nodes in g.

Parameters:
  • x (float) – lon

  • y (float) – lat

  • u (int) – connector’s from_node in new_g

  • k (int) – number of (bidirectional) connectors to add

  • g (networkx.DiGraph) – containing all road network nodes

  • new_g (networkx.DiGraph) – containing at least u and all nodes of g

  • euclidean (bool) – whether x and y are euclidean

Notes

default attributes of the connectors (speed, capacity, lanes) can be changed in dyntapy.settings.

dyntapy.demand_data.auto_configured_centroids(place, buffer_dist_close, buffer_dist_extended, inner_city_centroid_spacing=500)

generates centroids for the inner and extended study area from OpenStreetMap. The inner area is filled with a grid. The outer buffers are queried for settlements via OSMs ‘place’ tag.

Parameters:
  • place (str) – name of the city or region to buffer around.

  • buffer_dist_close (float) – width of the inner buffer

  • buffer_dist_extended (float) – width of the outer buffer

  • inner_city_centroid_spacing (float, optional) – distance between two adjacent centroids on the grid

Returns:

  • X (numpy.ndarray) – float, 1D lon of centroid locations

  • Y (numpy.ndarray) – float, 1D lat of centroid locations

  • name (list of strings) – name of the place as specified in OSM

  • place (list of strings) – values for OSMs place tag

Notes

The inner buffer is queried for places that are tagged as ‘village’, ‘city’, or ‘town’. The outer buffer is just querying for ‘city’ or ‘town’.

dyntapy.demand_data.find_nearest_centroids(X, Y, centroid_graph: networkx.DiGraph)

finds the nearest centroids in the graph for a set of locations

Parameters:
  • X (numpy.ndarray) – longitude of points

  • Y (numpy.ndarray) – latitude of points

  • centroid_graph (networkx.DiGraph) – with existing centroids, coordinates stored as ‘x_coord’ and ‘y_coord’ assumed to be lon and lat

Returns:

  • nearest_centroids, numpy.ndarray – int, 1D

  • distances, numpy.ndarray – in meter

dyntapy.demand_data.generate_od_xy(tot_ods, name: str, max_flow=2000, seed=0)

generate random demand for a place in geojson format

Parameters:
  • tot_ods (int) – total number of OD pairs to be generated

  • name (str) – name of the city or region to geocode and sample from

  • max_flow (float, optional) – maximum demand for any OD pair

  • seed (int, optional) – random seed

Returns:

geojson – containing LineStrings with a ‘flow’ attribute

dyntapy.demand_data.generate_random_od_graph(tot_ods, name, g, max_flow=2000, seed=0)

generates a random od-graph for a place

Parameters:
  • tot_ods (int) – total number of OD pairs to be generated

  • name (str) – name of the city or region to geocode and sample from

  • g (networkx.DiGraph)

  • max_flow (float, optional) – maximum demand for any OD pair

  • seed (int, optional) – random seed

Returns:

od_graph (networkx.DiGraph) – graph with centroids as nodes with specified coordinates as ‘x_coord’ and ‘y_coord’. For each OD pair with a non-zero demand there is a link with a corresponding ‘flow’ element as read from the OD matrix.

dyntapy.demand_data.get_centroid_grid_coords(name: str, buffer_dist=0, spacing=500)

creates centroids on a grid that overlap with the polygon that is associated with city or region specified

Parameters:
  • name (str,) – name of the city to be used as reference polygon

  • buffer_dist (float, optional)

  • spacing (float, optional) – distance between two adjacent centroids on the grid

Returns:

  • X (numpy.ndarray) – float, 1D lon of centroid locations

  • Y (numpy.ndarray) – float, 1D lat of centroid locations

dyntapy.demand_data.od_graph_from_matrix(od_matrix: numpy.ndarray, X, Y)

creates od_graph from od_matrix and centroid locations

Parameters:
  • od_matrix (numpy.ndarray) – float, 2D

  • X (numpy.ndarray) – float, 1D - lon of centroid locations

  • Y (numpy.ndarray) – float, 1D - lat of centroid locations

Returns:

od_graph (networkx.DiGraph) – graph with centroids as nodes with specified coordinates as ‘x_coord’ and ‘y_coord’. For each OD pair with a non-zero demand there is a link with a corresponding ‘flow’ element as read from the OD matrix.

dyntapy.demand_data.od_matrix_from_dataframes(od_table: pandas.DataFrame, zoning: geopandas.GeoDataFrame, origin_column: str, destination_column: str, zone_column: str, flow_column: str, return_relabelling=False)

extracts an OD matrix and X and Y coordinates as arrays from a pandas.DataFrame and zoning provided as a geopandas.GeoDataFrame.

It is rather common to receive OD tables in the form of .csv files and zoning in the form of .shp files. This function enables one to extract the full OD matrix after loading these files with pandas and geopandas, respectively.

Parameters:
  • od_table (pandas.DataFrame) – each row should represent one entry in the OD matrix, with origin_column, destination_column and flow_column as the relevant columns

  • zoning (gpd.GeoDataFrame) – specifies geometries of the zoning, assumed to be in lon lat. The entries in zone_column should correspond to the entries in origin_column and destination_column in the od_table

  • origin_column (str)

  • destination_column (str)

  • zone_column (str)

  • flow_column (str)

  • return_relabelling (bool, optional) – whether to return the mapping between the original zone labels in ‘zone_column’ and the indexes in the returned OD matrix

Returns:

  • od_matrix (numpy.ndarray) – float, 2D

  • X (np.ndarray) – float, 1D, lon of centroids

  • Y (np.ndarray) – float, 1D, lat of centroids

  • mapping (dict, optional)

dyntapy.demand_data.parse_demand(data: str, g)

Maps travel demand to existing closest centroids in g. The returned demand pattern is expressed as its own directed graph.

Parameters:
  • data (geojson) – that contains lineStrings (WGS84) as features, each line has an associated ‘flow’ stored in the properties dictionary

  • g (networkx.Digraph)

Returns:

od_graph (networkx.DiGraph) – graph with centroids as nodes with specified coordinates as ‘x_coord’ and ‘y_coord’. For each OD pair with a non-zero demand there is a link with a corresponding ‘flow’ element as read from the OD matrix.

Notes

There’s no checking on whether the data and g correspond to the same geo-coded region.

The corresponding OD table can be retrieved through calling

>>> networkx.to_scipy_sparse_matrix(od_graph,weight='flow')

dyntapy.supply_data

dyntapy.supply_data.build_network(g, u_turns=False)

creates internal network representation

Parameters:

g (networkx.DiGraph) – road network graph

Returns:

dyntapy.supply.Network

dyntapy.supply_data.get_toy_network(name)

retrieves toy network by name.

Options are: ‘cascetta’,’simple_merge’, ‘simple_diverge’, ‘simple_bottleneck’, ‘chicagosketch’ ‘chicagoregional’ ‘siouxfalls’ ‘birmingham’

Parameters:

name (str)

Returns:

networkx.DiGraph

References

The source of ‘chicagosketch’ ‘chicagoregional’ ‘siouxfalls’ ‘birmingham’ is Ben Stabler et al. see : https://github.com/bstabler/TransportationNetworks

The ‘cascetta’ network is from:

Cascetta, Ennio. Transportation systems analysis: models and applications. Vol. 29. Springer Science & Business Media, 2009. Page 304.

The remaining networks were set up by the authors.

dyntapy.supply_data.relabel_graph(g, return_inverse=False)

relabels graph’s links and nodes consecutively starting from 0.

Graphs obtained from external sources have labels that are often neither stable nor continuous. We relabel nodes and edges with our internal ids. The first C nodes in the network are centroids, with C the total number of centroids. The first K links in the network are source connectors, as link labelling is consecutive by the start node ids. Sink connector ids are therefore random.

Parameters:

g (networkx.DiGraph)

Returns:

  • new_g (networkx.Digraph) – with continuously labelled nodes, consistent with internal notation

  • inverse (dict, optional) – a dictionary which maps each of the old node ids to the new ones

dyntapy.supply_data.road_network_from_place(place, buffer_dist_close=20000, buffer_dist_extended=None)

retrieves road_network from OSM for driving.

Detailed network for the inner polygon given by querying OSM. The buffer values determine surrounding polygons for which we acquire a coarser network.

Parameters:
  • place (str) – name of the city or region

  • buffer_dist_close (float) – meters to buffer around, retain all roads with ‘highway’ = {‘trunk’, ‘motorway’, ‘primary’}

  • buffer_dist_extended (float) – meters to buffer around, retain all roads with ‘highway’ = {‘trunk’, ‘motorway’, }

Notes

The filters for the buffers can be adjusted in the settings file.

Returns:

networks.DiGraph

dyntapy.demand

class dyntapy.demand.DynamicDemand(od_graphs, insertion_times)
Parameters:
  • od_graphs (list of networkx.DiGraph)

  • insertion_times (numpy.ndarray) – times for the demand to be loaded into the network

Notes

The insertion times need to be within the bounds of the defined simulation time that is passed to the DynamicAssignment

See also

dyntapy.assignments.DynamicAssignment, dyntapy.demand.time.SimulationTime

class dyntapy.demand.InternalDynamicDemand(demands, tot_time_steps, tot_centroids, in_links: numba.experimental.jitclass)

internal specification of dynamic demand

should be initialized with build_dynamic_demand function

Parameters:
  • demands (list of InternalStaticDemand)

  • tot_time_steps (int)

  • tot_centroids (int)

  • in_links (UI32CSRMatrix) – in_links for all nodes in the networks

class dyntapy.demand.InternalStaticDemand(to_origins: numba.experimental.jitclass, to_destinations: numba.experimental.jitclass, origins, destinations, time_step)

internal specification of static demand

Parameters:
  • to_origins (F32CSRMatrix) – sparse OD matrix destinations to origins

  • to_destinations (F32CSRMatrix) – sparse OD matrix destinations to origins

  • origins (numpy.ndarray) – all origins with non-zero flow

  • destinations (numpy.ndarray) – all destinations with non-zero flow

  • time_step (int)

class dyntapy.demand.SimulationTime(start, end, step_size)

specification of time discretization, units are always assumed in hours

Parameters:
  • start (int)

  • end (int)

  • step_size (float)

dyntapy.demand.build_internal_dynamic_demand(dynamic_demand: DynamicDemand, simulation_time: numba.experimental.jitclass, network: numba.experimental.jitclass)

instantiates InternalDynamicDemand

Parameters:
dyntapy.demand.build_internal_static_demand(od_graph: networkx.DiGraph)

builds InternalStaticDemand

Parameters:

od_graph (networkx.DiGraph)

dyntapy.supply

after initializing either a dyntapy.assignments.StaticAssignment or dyntapy.assignments.DynamicAssignment we have access to a compiled dyntapy.supply.Network object. Alternatively, this can be build using dyntapy.supply_data.build_network

>>> network = dyntapy.supply_data.build_network(g)

The structure of this network object is described below. It gives access to a Links, Nodes and Turns object such that one can easily retrieve any network information rather intuitively.

For example, if one wanted to get the free flow travel times for all links, simply query the underlying links object.

>>> free_flow_costs = network.links.length/network.links.free_speed

specifies internal Links object

Parameters:
  • length (numpy.ndarray) – float, 1D

  • from_node (numpy.ndarray) – int, 1D

  • to_node (numpy.ndarray) – int, 1D

  • capacity (numpy.ndarray) – float, 1D

  • free_speed (numpy.ndarray) – float, 1D

  • out_turns (dyntapy.csr.UI32CSRMatrix)

  • in_turns (dyntapy.csr.UI32CSRMatrix)

  • lanes (numpy.ndarray) – int, 1D

  • link_type (numpy.ndarray) – int, 1D

Notes

should not be initialized by the user, use dyntapy.supply_data.build_network

out_turns and in_turns are sparse matrices in CSR format that indicate connected turns and their links. Both have the same shape (network.tot_turns, network.tot_links) with the indexes indicating the link_id and the values the to- and from_link, respectively. There’s duplication to avoid on-the-fly transformations.

class dyntapy.supply.Network(links, nodes, turns, tot_links, tot_nodes, tot_turns)

specifies internal Network object

Parameters:

Notes

should be initialized with dyntapy.supply_data.build_network

class dyntapy.supply.Nodes(out_links: numba.experimental.jitclass, in_links: numba.experimental.jitclass, tot_out_links, tot_in_links, control_type, capacity, is_centroid, x_coord, y_coord)

specifies internal Nodes object

Parameters:
  • out_links (dyntapy.csr.UI32CSRMatrix)

  • in_links (dyntapy.csr.UI32CSRMatrix)

  • tot_out_links (numpy.ndarray) – int, 1D - number of outgoing links

  • tot_in_links (numpy.ndarray) – int, 1D - number of outgoing links

  • control_type (numpy.ndarray) – int, 1D

  • capacity (numpy.ndarray) – float, 1D

  • is_centroid (numpy.ndarray) – bool, 1D

  • x_coord (numpy.ndarray) – float, 1D

  • y_coord (numpy.ndarray) – float, 1D

Notes

should not be initialized by the user, use dyntapy.supply_data.build_network

out_links and in_links are sparse matrices in CSR format that indicate connected links and their nodes. Both have the same shape (network.tot_nodes, network.tot_links) with the indexes indicating the link_id and the values the to- and from_node, respectively. There’s duplication to avoid on-the-fly transformations.

class dyntapy.supply.Turns(penalty, capacity, from_node, via_node, to_node, from_link, to_link, turn_type)

specifies internal Turns object should not be initialized by the user, use dyntapy.supply_data.build_network

Parameters:
  • penalty (numpy.ndarray) – float, 1D

  • capacity (numpy.ndarray) – float, 1D

  • from_node (numpy.ndarray) – int, 1D

  • via_node (numpy.ndarray) – int, 1D

  • to_node (numpy.ndarray) – int, 1D

  • from_link (numpy.ndarray) – int, 1D

  • to_link (numpy.ndarray) – int, 1D

  • turn_type (numpy.ndarray) – int, 1D

Notes

should not be initialized by the user, use dyntapy.supply_data.build_network

dyntapy.graph_utils

dyntapy.graph_utils.dijkstra_all(costs, out_links: numba.experimental.jitclass, source, is_centroid)

compiled one to all shortest path computation

Parameters:
  • costs (numpy.ndarray) – float, 1D

  • out_links (dyntapy.csr.UI32CSRMatrix)

  • source (int)

  • is_centroid (numpy.ndarray) – bool, 1D

Returns:

  • distances (numpy.ndarray) – float, 1D

  • predecessors (numpy.ndarray) – int, 1D - predecessor for each node that is closest to source.

dyntapy.graph_utils.dijkstra_with_targets(costs, out_links: numba.experimental.jitclass, source, is_centroid, targets)

compiled one to many shortest path computation, terminates once distance array has been filled for all target nodes.

Parameters:
  • costs (numpy.ndarray) – float, 1D

  • out_links (dyntapy.csr.UI32CSRMatrix)

  • source (int)

  • is_centroid (numpy.ndarray) – bool, 1D

  • targets (numpy.ndarray) – int, 1D

Returns:

  • distances (numpy.ndarray) – float, 1D

  • predecessors (numpy.ndarray) – int, 1D - predecessor for each node that is closest to source.

Notes

depending on how many targets there are to be found it can be faster to use dyntapy.graph_utils.dijkstra_all

dyntapy.graph_utils.get_all_shortest_paths(g, source, costs=None)

one to all shortest path computation

Parameters:
  • g (networkx.DiGraph) – as specified for assignments

  • source (int) – node id

  • costs (numpy.ndarray, optional) – if not set, free flow travel times are used based on defined length and speed

Returns:

  • distances (numpy.ndarray) – float, 1D

  • predecessors (numpy.ndarray) – int, 1D - predecessor for each node that is closest to source.

Notes

convenience function, the compiled functions cannot deal with branching on types

dyntapy.graph_utils.get_k_shortest_paths(g, source, target, costs=None, k=3, sim_threshold=0.75, detour_rejection=0.5)

computes k-shortest paths with a maximum overlap of sim_threshold

Parameters:
  • g (networkx.DiGraph) – as specified for assignments

  • source (int) – node id

  • target (int) – node id

  • costs (numpy.ndarray, optional) – if not set, free flow travel times are used based on defined length and speed

  • k (int) – number of the shortest paths to return

  • sim_threshold (float) – threshold for similarity between paths in the solution set, [0,1]

  • detour_rejection (float) – path quality criteria

Returns:

  • solution_paths (list of list) – each entry is a solution path

  • path_lengths (list) – length of each solution path as the sum of traversed link costs

Notes

detour_rejection has been added by the developers to prune bad solutions. A value of 0.10 indicates that paths can be at most 10 percent worse than the shortest path solution. Similar to a lower sim_threshold this setting may affect the completeness of the results.

dyntapy.graph_utils.get_shortest_paths(g, source, targets, costs=None, return_paths=False)

one to many shortest path computation

Parameters:
  • g (networkx.DiGraph) – as specified for assignments

  • source (int) – node id

  • targets (numpy.ndarray) – int, 1D

  • costs (numpy.ndarray, optional) – if not set, free flow travel times are used based on defined length and speed

  • return_paths (bool, optional) – set to true to get paths to each target

Returns:

  • distances (numpy.ndarray) – float, 1D - distance to each target

  • paths (list of list) – path to each target

Notes

convenience function, the compiled functions cannot deal with branching on types

dyntapy.graph_utils.kspwlo_esx(costs, out_links, source, target, k, is_centroid, sim_threshold, detour_rejection=0.5)

computes k-shortest paths with a maximum overlap of sim_threshold.

Parameters:
  • costs (numpy.ndarray) – float, 1D - cost for each link

  • out_links (dyntapy.csr.UI32CSRMatrix) – adjacency structure

  • source (int) – source node

  • target (int) – target node

  • k (int) – number of paths to generate

  • is_centroid (np.ndarray) – bool, 1D - centroids are ignored for routing

  • sim_threshold (float) – threshold for similarity between paths in the solution set, [0,1]

  • detour_rejection (float) – path quality criteria

Returns:

  • solution_paths (list of list) – each entry is a solution path

  • path_lengths (list) – length of each solution path as the sum of traversed link costs

Notes

detour_rejection has been added by the developers to prune bad solutions. A value of 0.10 indicates that paths can be at most 10 percent worse than the shortest path solution. Similar to a lower sim_threshold this setting may affect the completeness of the results, see [5].

References

dyntapy.graph_utils.pred_to_path(predecessors, source, target, out_links: numba.experimental.jitclass)

converts optimal predecessor arrays to an arc-path between source and target

Parameters:
  • predecessors (numpy.ndarray) – int, 1D - predecessor of each node that is closest to source

  • source (int)

  • target (int)

  • out_links (dyntapy.csr.UI32CSRMatrix)

Returns:

numba.typed.List

dyntapy.graph_utils.pred_to_paths(predecessors, source, targets, out_links: numba.experimental.jitclass, reverse=False)

converts optimal predecessor arrays to paths between source and targets

Parameters:
  • predecessors (numpy.ndarray) – int, 1D - predecessor of each node that is closest to source

  • source (int)

  • targets (numpy.ndarray)

  • out_links (dyntapy.csr.UI32CSRMatrix)

  • reverse (bool, default True) – if predecessors array is a successor array.

Returns:

numba.typed.List

dyntapy.results

class dyntapy.results.DynamicResult(link_costs: numpy.ndarray, cvn_up: numpy.ndarray, cvn_down: numpy.ndarray, con_up: numpy.ndarray, con_down: numpy.ndarray, turning_fractions: numpy.ndarray, turn_costs: numpy.ndarray, flows: numpy.ndarray, commodity_type: str, origins: numpy.ndarray, destinations: numpy.ndarray, skim: Optional[numpy.ndarray] = None, gap_definition: Optional[str] = None, iterations: Optional[numpy.ndarray] = None)

Class for keeping all the outputs of a dynamic assignment

class dyntapy.results.StaticResult(link_costs: numpy.ndarray, flows: numpy.ndarray, origins: numpy.ndarray, destinations: numpy.ndarray, origin_flows: Optional[numpy.ndarray] = None, destination_flows: Optional[numpy.ndarray] = None, skim: Optional[numpy.ndarray] = None, gap_definition: Optional[str] = None, gap: Optional[numpy.ndarray] = None, od_flows: Optional[list] = None)

Class for keeping all the outputs of a static assignment

dyntapy.results.get_od_flows(assignment, result: StaticResult, return_as_matrix=False)

reconstructs origin destination flows for a static assignment result

Parameters:
Returns:

  • od_flow (list, optional) – each element is a list of tuples (origin, destination, flow), one for each link

  • od_mat (numpy.ndarray, optional) – float, 3D, (tot_origins, tot_destinations, tot_links)

Notes

only yields entropy maximised solution if the origin flows or destination flows are also entropy maximised.

filters origin destination flows for elements that flow past link

Parameters:
Returns:

sla (list) – each element is a list of tuples (origin, destination, flow), one for each link

dyntapy.results.get_skim(link_costs, demand: numba.experimental.jitclass, network: numba.experimental.jitclass)

get skim matrix in dense format from link costs

Parameters:
Returns:

skim (numpy.ndarray) – float, 2D

Examples

get skim matrices in dense format such that

>>> skim[0, 10]

is the impedance between the first and the eleventh zone corresponding to nodes

>>> demand.origins[0]
>>> demand.destinations[10]

in the graph

dyntapy.csr

This module provides a simple interface for creating CSR formatted sparse matrices that can be used in Numba. Namely, one can import F32CSRMatrix, UI32CSRMatrix, UI8CSRMatrix from this module with the starting letters indicating the item type of the sparse matrix. F32 stands for float32, UI32 for unsigned int32 and UI8 for unsigned int8.

Because of the way these classes are build we cannot just integrate the docs for them in sphinx, the source code itself however has extensive comments in the defined CSRMatrix.

dyntapy.csr.BCSRMatrix

alias of CSRMatrix

dyntapy.csr.F32CSRMatrix

alias of CSRMatrix

dyntapy.csr.UI32CSRMatrix

alias of CSRMatrix

dyntapy.csr.UI8CSRMatrix

alias of CSRMatrix

dyntapy.csr.csr_prep(index_array, values, shape, unsorted=True)

processes index array and values by sorting them and casts them into values, col and row arrays than can be used directly to instantiate a CSRMatrix

Parameters:
  • index_array (numpy.ndarray) – uint32, 2D - array with each row containing the indexes of nnz element

  • values (numpy.ndarray) – any, 1D - array with corresponding value

  • shape (tuple) – uint32 or uint64 ,shape of sparse matrix (rows, columns)

  • unsorted (bool, optional) – index_array and values sorted or not

Returns:

  • values (numpy.ndarray)

  • col (numpy.ndarray)

  • row (numpy.ndarray)

dyntapy.csr.csr_sort(index_array, values, tot_columns)

sorts index_array and values by rows, ties are broken by the columns

Parameters:
  • index_array (numpy.ndarray) – uint32, 2D - with each row containing the indexes of nnz element

  • values (numpy.ndarray) – int or float, 1D - corresponding value for each nnz element

Returns:

  • sorted_index_array (numpy.ndarray)

  • sorted_values (numpy.ndarray)

Examples

example for sorting index_array.

before:

array([[2, 3],[1, 480640], [2, 356104], [0, 1], dtype=uint32)

after:

array([[0, 1], [1, 480640], [2, 3], [2, 356104], dtype=uint32)

dyntapy.visualization

dyntapy.visualization.show_demand(g, title=None, notebook=False, euclidean=False, toy_network=False, highlight_nodes=[], return_plot=False, max_edge_width=1)

visualize demand on a map

Parameters:
  • g (networkx.DiGraph)

  • title (str)

  • notebook (bool, optional) – set to True if the plot should be rendered in a notebook.

  • euclidean (bool, optional) – set to True, if ‘x_coord’ and ‘y_coord’ in g are euclidean.

  • toy_network (bool, optional) – deprecated, use euclidean instead

  • highlight_nodes (numpy.ndarray or list, optional) – int, 1D - nodes to highlight

  • return_plot (bool, optional) – set to True if the plot object should be returned instead of showing it.

  • max_edge_width (float, optional) – defaults to 1, changes the width of the edges by the set factor

Examples

Given an od_matrix and coordinates in longitude X and latitude Y it is straightforward to visualize the travel pattern.

>>> od_graph_from_matrix(od_matrix, X, Y)
>>> show_demand(g)
dyntapy.visualization.show_dynamic_network(g, time, flows=None, link_kwargs={}, node_kwargs={}, toy_network=False, euclidean=False, highlight_nodes=numpy.array, highlight_links=numpy.array, title=None, notebook=False, show_nodes=True, return_plot=False, max_edge_width=1)

Visualizing a network with dynamic attributes in a .html.

Parameters:
  • g (networkx.DiGraph)

  • time (dyntapy.demand.SimulationTime)

  • flows (numpy.ndarray, optional) – float, 2D - time-dependent flows to be visualized

  • link_kwargs (dict, optional) – additional time-dependent link information to be displayed key: str, value: np.ndarray - additional time-dependent link information to be displayed

  • node_kwargs (dict, optional) – key: str, value: np.ndarray - additional time-dependent node information to be displayed

  • highlight_links (numpy.ndarray, optional) – int, 1D or 2D - links to highlight

  • highlight_nodes (numpy.ndarray, optional) – int, 1D or 2D - nodes to highlight

  • euclidean (bool, optional) – set to True if coordinates in graph are euclidean.

  • toy_network (bool, optional) – deprecated, use euclidean instead.

  • title (str, optional)

  • notebook (bool, optional) – set to True if the plot should be rendered in a notebook.

  • show_nodes (bool, optional) – whether to render nodes

  • return_plot (bool, optional) – set to True if the plot object should be returned instead of showing it.

  • max_edge_width (float, optional) – defaults to 1, changes the width of the edges by the set factor

Examples

highlighting works just as in show_network and is not time dependent.

>>> foo = np.arange((g.number_of_edges(), time.tot_time_steps))
>>> bar = np.arange((g.number_of_edges(), time.tot_time_steps))
>>> show_dynamic_network(g, link_kwargs={'foo': foo, 'bar':bar})

Will generate a plot where respective values for foo and bar can be inspected by hovering over the link. The values are updated as the time slider is moved.

Note that the string attribute names cannot contain spaces and that the arrays must have the correct dimension.

node_kwargs can be passed on analogously.

Notes

highlight colors can be altered in the settings and have been chosen to still offer visibility in a graph with loaded traffic in a green-to-red color map.

Visualizing a network with origin destination flows for each link in a .html.

Parameters:
  • g (networkx.DiGraph)

  • od_flows (list) – origin destination flows for each link

  • kwargs (any) – all the arguments of show_network are valid, except for flows

dyntapy.visualization.show_network(g, flows=None, link_kwargs={}, node_kwargs={}, highlight_links=numpy.array, highlight_nodes=numpy.array, euclidean=False, toy_network=False, title=None, notebook=False, show_nodes=True, return_plot=False, max_edge_width=1)

Visualizing a network with static attributes in a .html.

Parameters:
  • g (networkx.DiGraph)

  • flows (numpy.ndarray, optional) – float, 1D - flows to be visualized

  • link_kwargs (dict, optional) – additional link information to be displayed key: str, value: numpy.ndarray - additional link information to be displayed

  • node_kwargs (dict, optional) – key: str, value: numpy.ndarray - additional node information to be displayed

  • highlight_links (numpy.ndarray or list, optional) – int, 1D or 2D - links to highlight

  • highlight_nodes (numpy.ndarray or list, optional) – int, 1D or 2D - nodes to highlight

  • euclidean (bool, optional) – set to True if coordinates in graph are euclidean.

  • toy_network (bool, optional) – deprecated, use euclidean instead.

  • title (str, optional)

  • notebook (bool, optional) – set to True if the plot should be rendered in a notebook.

  • show_nodes (bool, optional) – whether to render nodes

  • return_plot (bool, optional) – set to True if the plot object should be returned instead of showing it.

  • max_edge_width (float, optional) – defaults to 1, changes the width of the edges by the set factor

Examples

>>> show_network(g, highlight_links=[[2,4],[3,6]])

will plot the network and highlight links [2,4] in neon pink, and [3, 6] in cyan. The order of highlight colors is neon pink, cyan, lime green, light blue, orange, gray

Node highlighting works analogously.

>>> foo = np.arange(g.number_of_edges())
>>> bar = np.arange(g.number_of_edges())
>>> show_network(g, link_kwargs={'foo': foo, 'bar':bar})

will generate a plot where respective values for foo and bar can be inspected by hovering over the link. Note that the string attribute names cannot contain spaces and that the arrays must have the correct dimension.

node_kwargs can be passed on analogously.

Notes

highlight colors can be altered in the settings and have been chosen to still offer visibility in a graph with loaded traffic in a green-to-red color map.

Debugging Assignments

By default most of dyntapy’s assignment algorithms utilize Numba to accelerate computations. It is not possible to use breakpoints inside of code that bas been JIT-compiled. We first need to disable JIT compilation to do so:

>>> from numba import config
>>> config.DISABLE_JIT =1

Make sure that the above is put on top of the script that you’re running the assignment from, before all other imports. Importing numba and changing this variable after doing so yields rather confusing errors.

For more details on other debug settings for Numba see https://numba.readthedocs.io/en/stable/reference/envvars.html.

When working with breakpoints in the assignment algorithms it is advantageous to have access to the assignment object in order to visualize the network or get additional information that may not be available in the context where your breakpoint is set. From the debugger one can always import the latest instantiated assignment object as shown below:

>>> from dyntapy._context import running_assignment

The running_assignment object is either a dyntapy.StaticAssignment or a dyntapy .DynamicAssignment, both share the network attribute.

>>> from dyntapy import show_network
>>> g = running_assignment.network
>>> show_network(g)

For more details on how to visualize link and node attributes do check the documentation.

Adding Assignments

Instances of dyntapy’s internal demand and supply objects, specified in dyntapy.supply and dyntapy.demand, are made available for both static and dynamic assignment instances.

If we have a dyntapy.StaticAssignment object given we can access the internal_network and demand attributes.

>>> from dyntapy import StaticAssignment
>>> assignment: Static Assignment
>>> def my_assignment_algorithm(network, demand):
>>>     tot_links = network.tot_links
>>>     free_flow_travel_times = network.links.length/network.links.free_speed
>>>     destination_nodes = demand.destinations
>>>     ...
>>> my_assignment_algorithm(assignment.internal_network, assignment.demand)

Note that assignment algorithms that are implemented using the internal demand and supply objects can be accelerated using Numba, which is not possible for generic python objects.

You can always visualize the network and any link and node attributes that are generated during computations.

Once your algorithm runs there is still some boilerplate code needed to fully integrate in dyntapy. For details do take a look at the existing assignments in dyntapy.assignments. The structure will essentially be the same for all static and dynamic assignments, respectively. Your compiled assignment routine returns all the arrays needed to fill the dyntapy.results.StaticResults or dyntapy.results.DynamicResults. The outer shell function creates the result object and returns it.

Dynamic Assignments - Known Pitfalls

The dynamic assignment routines presented here work for the shown example(s) in the tutorials, however they are not guaranteed to produce reliable result or fail gracefully for any arbitrary network, travel demand and time configuration. If the demand that you feed exceeds the local infrastructure and there is spillback into the origin do not expect reasonable outputs. The same holds for demand that cannot leave the network during the simulation, there should always be some time periods in the dynamic assignment in which all the queues can resolve and all vehicles can reach their destination. This is very much following the principle of garbage-in-garbage-out.

It is best practice to first explore a small example and build some intuition for DTA before moving on to more complex scenarios which slow you down because of their larger computation time.

The complexity in DTA is mainly driven by the number of OD pairs, their intensity and induced congestion, the network’s size (in number of links and nodes) and the number of time steps. Ideally, your example to experiment with should be low in complexity in all of those metrics.