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>'))
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()
[ ]: