NetworkX graph

WNTR can generate a NetworkX data object that stores network connectivity as a graph. The ability to easily integrate NetworkX with WNTR facilitates the use of numerous standard graph algorithms, including algorithms that describe network structure.

A graph is a collection of nodes that are connected by links. For water networks, nodes represent junctions, tanks, and reservoirs while links represent pipes, pumps, and valves. The NetworkX graph can be used to analyze network structure.

The type of NetworkX graph generated by WNTR is a directed multigraph. A directed multigraph is a graph with direction associated with links and the graph can have multiple links with the same start and end node. A simple example is shown in Figure 5. For water networks, the link direction is from the start node to the end node. The link direction is used as a reference to track flow direction in the network. For example, positive flow indicates that the flow direction is from the start node to the end node while negative flow indicates that the flow direction is from the end node to the start node. Multiple links with the same start and end node can be used to represent redundant pipes or backup pumps.

A NetworkX graph generated from a water network model stores the start and end node of each link, node coordinates, and node and link types (i.e., tank, reservoir, valve). NetworkX includes numerous methods to analyze the structure of complex networks. For more information on NetworkX, see https://networkx.github.io/.

Directed multigraph

Figure 5 Example directed multigraph.

A NetworkX directed multigraph can an be obtained from a WaterNetworkModel using the following function:

>>> import wntr 

>>> wn = wntr.network.WaterNetworkModel('networks/Net3.inp') 
>>> G = wn.get_graph() # directed multigraph

The graph is stored as a nested dictionary. The nodes and links can be accessed using the graph’s node and adj attribute (adj is used to get adjacent nodes and links).

>>> node_name = '123'
>>> G.nodes[node_name] 
>>> G.adj[node_name] 

The graph can be used to access NetworkX methods, for example:

>>> import networkx as nx

>>> node_degree = G.degree()
>>> closeness_centrality = nx.closeness_centrality(G)
>>> ax = wntr.graphics.plot_network(wn, node_attribute=closeness_centrality)

See Topographic metrics for more information.

Additional network types

Some methods in NetworkX require that networks are undirected, connected, weighted, or have only one edge between nodes.

An undirected graph is a graph with no direction associated with links. The following NetworkX method can be used to convert a directed graph to an undirected graph:

>>> uG = G.to_undirected() # undirected multigraph

A connected graph is a graph where a path exists between every node in the network (i.e., no node is disconnected). The following NetworkX method can be used to check if a graph is connected:

>>> nx.is_connected(uG)
True

A weighted graph is a graph in which each node and/or link is given a weight. The WNTR method get_graph can be used to weight the graph by node and/or link attributes. In the following example, the graph is weighted by length. This graph can then be used to compute path lengths:

>>> length = wn.query_link_attribute('length')
>>> wG = wn.get_graph(wn, link_weight=length) # weighted directed multigraph

A simple graph is a graph with one edge between nodes. The following NetworkX method can be used to convert a multigraph to a simple graph:

>>> sG = nx.Graph(G) # directed simple graph