Working with the Network Topology

[1]:
from IPython.display import display, HTML
display(HTML('<a target="_blank" href="https://colab.research.google.com/github/WaterFutures/EPyT-Flow/blob/main/docs/examples/network_topology.ipynb"><img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab"/></a>'))
Open In Colab

This example demonstrates how to retrieve detailed information about the topology of a WDN and how to perform some common tasks such as finding shortest paths.

[2]:
%pip install epyt-flow --quiet
Note: you may need to restart the kernel to use updated packages.
[3]:
from epyt_flow.data.networks import load_net1
from epyt_flow.simulation import ScenarioSimulator, EpanetConstants
from epyt_flow.topology import flowunit_to_str

Load the Net1 network by calling load_net1():

[4]:
network_config = load_net1(verbose=False)

Create dummy scenario simulation

[5]:
wdn = ScenarioSimulator(scenario_config=network_config)

Get the network topology by calling get_topology():

[6]:
topo = wdn.get_topology()

List all edges/links:

[7]:
print(topo.edges)
[('10', '11'), ('10', '9'), ('11', '12'), ('11', '21'), ('12', '13'), ('12', '2'), ('12', '22'), ('13', '23'), ('21', '22'), ('21', '31'), ('22', '23'), ('22', '32'), ('31', '32')]

List all nodes:

[8]:
print(topo.nodes)
['10', '11', '12', '13', '21', '22', '23', '31', '32', '9', '2']

Find the shortest path between nodes “2” and “22” by utilizing the get_shortest_path() function:

[9]:
print(topo.get_shortest_path("2", "22"))
['2', '12', '22']

Compute the adjacency matrix of the WDN by calling get_adj_matrix():

[10]:
print(topo.get_adj_matrix().todense())
[[1. 1. 0. 0. 0. 0. 0. 0. 0. 1. 0.]
 [1. 1. 1. 0. 1. 0. 0. 0. 0. 0. 0.]
 [0. 1. 1. 1. 0. 1. 0. 0. 0. 0. 1.]
 [0. 0. 1. 1. 0. 0. 1. 0. 0. 0. 0.]
 [0. 1. 0. 0. 1. 1. 0. 1. 0. 0. 0.]
 [0. 0. 1. 0. 1. 1. 1. 0. 1. 0. 0.]
 [0. 0. 0. 1. 0. 1. 1. 0. 0. 0. 0.]
 [0. 0. 0. 0. 1. 0. 0. 1. 1. 0. 0.]
 [0. 0. 0. 0. 0. 1. 0. 1. 1. 0. 0.]
 [1. 0. 0. 0. 0. 0. 0. 0. 0. 1. 0.]
 [0. 0. 1. 0. 0. 0. 0. 0. 0. 0. 1.]]

Show information associated with node “2” by utilizing the get_node_info() function:

[11]:
print(topo.get_node_info("2"))
{'elevation': 850.0, 'coord': [50.0, 90.0], 'comment': '', 'type': 2, 'base_demand': 0.0, 'diameter': 50.5, 'max_level': 150.0, 'min_level': 100.0, 'min_vol': 200296.16662043423, 'mixing_fraction': 1.0, 'mixing_model': 0, 'init_vol': 240355.39994452108, 'cylindric': True, 'can_overflow': False, 'vol_curve_id': ''}

Show information associated with link “10” by utilizing the get_link_info() function:

[12]:
print(topo.get_link_info("10"))
{'nodes': ['10', '11'], 'type': 1, 'diameter': 18.0, 'length': 10530.0, 'roughness_coeff': 100.0, 'bulk_coeff': -0.5, 'wall_coeff': -1.0, 'loss_coeff': 0.0, 'init_setting': 100.0, 'init_status': 1}

Get topology as a geopandas.GeoDataFrame instance by calling to_gis():

[13]:
# Get topology as GeoDataFrame
geo_data = topo.to_gis()

# Show GeoDataFrame for nodes
geo_data["nodes"]
[13]:
id type elevation geometry
0 10 0 710.0 POINT (20 70)
1 11 0 710.0 POINT (30 70)
2 12 0 700.0 POINT (50 70)
3 13 0 695.0 POINT (70 70)
4 21 0 700.0 POINT (30 40)
5 22 0 695.0 POINT (50 40)
6 23 0 690.0 POINT (70 40)
7 31 0 700.0 POINT (30 10)
8 32 0 710.0 POINT (50 10)
9 9 1 800.0 POINT (10 70)
10 2 2 850.0 POINT (50 90)

Which flow units are used in this NetworkTopology instance?

We can find out by checking the property flow_units and convert it to a human-radable format by calling flowunit_to_str():

[14]:
print(flowunit_to_str(topo.flow_units))
gal/min

Convert units to SI METRIC – i.e. flow units to cubic meter per hours and pressure to meter. This will results yield pipe diameter in millimeter, pipe length in meter, node elevation in meter, …

See EPANET documentation for details.

Units in a NetworkTopology instance can be changed by calling convert_units():

[15]:
new_topo = topo.convert_units(flow_units=EpanetConstants.EN_CMH, pressure_units=EpanetConstants.EN_METERS)

# Show information associated with node "2"
print(new_topo.get_node_info("2"))

# Show information associated with link "10"
print(new_topo.get_link_info("10"))
{'elevation': 259.08000000000004, 'coord': [50.0, 90.0], 'comment': '', 'type': 2, 'base_demand': 0.0, 'diameter': 15.3924, 'max_level': 45.72, 'min_level': 30.48, 'min_vol': 5671.755823154675, 'mixing_fraction': 1.0, 'mixing_model': 0, 'init_vol': 240355.39994452108, 'cylindric': True, 'can_overflow': False, 'vol_curve_id': ''}
{'nodes': ['10', '11'], 'type': 1, 'diameter': 457.2, 'length': 3209.5440000000003, 'roughness_coeff': 100.0, 'bulk_coeff': -0.5, 'wall_coeff': -1.0, 'loss_coeff': 0.0, 'init_setting': 100.0, 'init_status': 1}

Convert units back to US CUSTOMARY – i.e., flow units should be gallons per minute and pressure in psi:

[16]:
new_topo = new_topo.convert_units(flow_units=EpanetConstants.EN_GPM, pressure_units=EpanetConstants.EN_PSI)

print(new_topo.get_node_info("2"))
print(new_topo.get_link_info("10"))
{'elevation': 850.0, 'coord': [50.0, 90.0], 'comment': '', 'type': 2, 'base_demand': 0.0, 'diameter': 50.49999999999999, 'max_level': 149.99999999999997, 'min_level': 99.99999999999999, 'min_vol': 200296.16662043423, 'mixing_fraction': 1.0, 'mixing_model': 0, 'init_vol': 240355.39994452108, 'cylindric': True, 'can_overflow': False, 'vol_curve_id': ''}
{'nodes': ['10', '11'], 'type': 1, 'diameter': 18.0, 'length': 10530.0, 'roughness_coeff': 100.0, 'bulk_coeff': -0.5, 'wall_coeff': -1.0, 'loss_coeff': 0.0, 'init_setting': 100.0, 'init_status': 1}

Do not forget to close the simulator!

[17]:
wdn.close()
[ ]: