NetworkX graphΒΆ

WNTR uses NetworkX data objects to store network connectivity as a graph. 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.

Water networks are stored as directed multigraphs. 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. In WNTR, the graph stores the start and end node of each link, node coordinates, and node and link types (i.e., tank, reservoir, valve). WNTR updates the graph as elements are added and removed from the water network model.

Directed multigraph

Figure 5 Example directed multigraph.

NetworkX includes numerous methods to analyze the structure of complex networks. For more information on NetworkX, see https://networkx.github.io/. WNTR includes a custom Graph Class, WntrMultiDiGraph. This class inherits from NetworkX MultiDigraph and includes additional methods that are specific to WNTR. The example networkx_graph.py can be used to generate a graph from a water network model.

A copy of the graph can an be obtained using the following function:

G = wn.get_graph_deep_copy()

The graph is stored as a nested dictionary. The nodes and links (note that links are called edges in NetworkX) can be accessed using the following:

node_name = '123'
print(G.node[node_name])
print(G.edge[node_name])

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

import networkx as nx
node_degree = G.degree()
bet_cen = nx.betweenness_centrality(G)
wntr.graphics.plot_network(wn, node_attribute=bet_cen, node_size=30, 
                        title='Betweenness Centrality')

Some methods in NetworkX require that networks are undirected. 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()

Some methods in NetworkX require that networks are connected. 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:

print(nx.is_connected(uG))

Some methods in NetworkX can use weighted graphs. A weighted graph is a graph in which each link is given a weight. The WNTR method weight_graph can be used to weight the graph by any attribute. 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')
G.weight_graph(link_attribute = length)