logo Netzschleuder network catalog, repository, and centrifuge

History of water_distribution_exeter

The changes to the source code of this entry in the repository, newest first, each with the differences it made to the entry's files. They are also listed on GitLab.

[entries] Use American spelling in the descriptions by Tiago de Paula Peixoto 802d564
British spellings in the titles and descriptions of 69 entries (e.g.
labelled, organisation, millimetres, centres, anonymised, neighbours,
analysed, modelled, colour, licence) are replaced by the American ones.
Proper names keep their spelling (Otago Harbour, the Centre for Water
Systems, the Centre jeunesse de Montréal, the Dutch Ministry of Defence),
as do quoted upstream terms, citations, and property names.
diff --git a/entries/water_distribution_exeter/__init__.py b/entries/water_distribution_exeter/__init__.py
index e8d699a..2a5d941 100644
--- a/entries/water_distribution_exeter/__init__.py
+++ b/entries/water_distribution_exeter/__init__.py
@@ -28,7 +28,7 @@ description = """Water distribution networks used as benchmark problems for the
 - `d_town`: D-Town, the network of the Battle of the Water Networks II (BWN-II) design competition (five district metered areas and a new zone).
 - `anytown`: Anytown, a classic synthetic expansion benchmark (Walski et al., 1987).
 - the networks of the two-objective design benchmarks of Wang et al. (2015), with their acronyms: `two_reservoir` (TRN, Gessler 1985), `two_loop` (TLN), `bakryun` (BAK), `new_york_tunnels` (NYT), `blacksburg` (BLA), `hanoi` (HAN), `goyang` (GOY), `fossolo` (FOS), `pescara` (PES), `modena` (MOD) and `balerma` (BIN, the Balerma irrigation network, Almería, Spain). The files of the expansion problems `two_reservoir`, `new_york_tunnels` and `anytown` include the candidate pipes of the design problem, i.e. new pipes and duplicates (parallel pipes) of existing pipes whose diameters are to be chosen, with a placeholder diameter of 0.0001 in the file (given here as NaN); these are marked by the edge property `candidate` (see below): in `two_reservoir`, the five new pipes (marked as new in the file) and the duplicates of three existing pipes, i.e. 8 of its 17 pipes (the Centre for Water Systems also distributed this network without the duplicates, as `gessler1985.inp`); in `new_york_tunnels`, a duplicate of each of the 21 tunnels (the version without duplicates, `nytun.inp`, is otherwise identical); in `anytown`, the six new pipes (marked as new in the file; the duplication of existing pipes, also part of the problem, is not represented). The other networks have no such property: `two_loop` and `hanoi` are designs of whole new networks, in which all pipes have the placeholder diameter; in `bakryun`, nine of the 58 pipes (six of them parallel to existing pipes) are new pipes to be sized, but they cannot be identified from the file, in which all pipes have diameters; in the remaining design benchmarks all pipes are sized, or have fixed diameters; and in `exnet`, the 567 existing pipes considered for duplication are tagged in comments of the file, but the duplicates themselves are not included.
-- `bwsn_network_1` and `bwsn_network_2`: the two networks of the Battle of the Water Sensor Networks (BWSN, Ostfeld et al. 2008), a design competition for the placement of contamination warning sensors held at the 8th Water Distribution Systems Analysis Symposium (Cincinnati, 2006), from the archive of the BWSN files distributed by the Centre for Water Systems ("Sensor Placement (BWSN)" on its benchmark page). Network 1 is a hypothetical network with 126 junctions, one reservoir, two tanks, 168 pipes, two pumps and eight valves; Network 2 is based on a real-world system (not identified) and has 12,523 junctions, two reservoirs, two tanks, 14,822 pipes, four pumps and five valves. (The same two networks are also distributed by the University of Kentucky in its "Battle of the Water Network Models" collection, under a CC BY-NC 4.0 licence.)
+- `bwsn_network_1` and `bwsn_network_2`: the two networks of the Battle of the Water Sensor Networks (BWSN, Ostfeld et al. 2008), a design competition for the placement of contamination warning sensors held at the 8th Water Distribution Systems Analysis Symposium (Cincinnati, 2006), from the archive of the BWSN files distributed by the Centre for Water Systems ("Sensor Placement (BWSN)" on its benchmark page). Network 1 is a hypothetical network with 126 junctions, one reservoir, two tanks, 168 pipes, two pumps and eight valves; Network 2 is based on a real-world system (not identified) and has 12,523 junctions, two reservoirs, two tanks, 14,822 pipes, four pumps and five valves. (The same two networks are also distributed by the University of Kentucky in its "Battle of the Water Network Models" collection, under a CC BY-NC 4.0 license.)
 
 Other files of the collection are not included: the modified and output versions of the Wolf-Cordera Ranch model (`wolf-modified-fig.inp`, `wolf-output-fig.inp`, `bocika-output.inp`) are the same network with 124 artificial tanks connected via flow control valves, added to simulate simultaneous fire flows, and differ among themselves only in pipe diameters; the EXNET file of the Pareto-front benchmarks (`EXN.inp`) is `exnet` with candidate duplicate pipes.
 
@@ -36,7 +36,7 @@ The networks have the following properties:
 
 - Nodes: `name`, the node ID in the EPANET file; `type`, "junction", "reservoir" or "tank"; `elevation`, the elevation of a junction or tank, or the (total) head of a reservoir; `demand`, the base demand of a junction (NaN for reservoirs and tanks); `coordinates`, the $(x, y)$ position of the node in the drawing of the network.
 - Edges: `name`, the link ID; `type`, "pipe", "check valve pipe", "pump" or "valve"; `length`, `diameter` and `roughness` of pipes (NaN for other links; `diameter` is also given for valves, and is NaN for candidate pipes); `valve_type`, the type of a valve (e.g. "PRV", "TCV"); `candidate` (only in `two_reservoir`, `new_york_tunnels` and `anytown`), true for the candidate pipes of the design problem (new or duplicate pipes, whose `diameter` is NaN, since the file gives only a placeholder), false for the existing links.
-- Graph: `flow_units`, the flow units of the file ("GPM", "CFS", "LPS", "CMH", ...). Following EPANET's conventions, with US flow units (GPM, CFS) lengths and elevations are in feet and diameters in inches, and with SI flow units (LPS, CMH) lengths and elevations are in metres and diameters in millimetres; demands are in the flow units.[^icon]
+- Graph: `flow_units`, the flow units of the file ("GPM", "CFS", "LPS", "CMH", ...). Following EPANET's conventions, with US flow units (GPM, CFS) lengths and elevations are in feet and diameters in inches, and with SI flow units (LPS, CMH) lengths and elevations are in meters and diameters in millimeters; demands are in the flow units.[^icon]
 
 [^icon]: Description obtained in part from the [ICON](https://icon.colorado.edu) project."""
 tags = ['Technological', 'Weighted', 'Spatial', 'Metadata']
[entries] Lay out spatial networks with cfd_layout() without the SBM partition by Tiago de Paula Peixoto 9db8d77
Road, power grid, public transport, water and river networks and physical
meshes override get_pos() with the default parameters of cfd_layout(),
without grouping by the partition of the SBM fit.
diff --git a/entries/water_distribution_exeter/__init__.py b/entries/water_distribution_exeter/__init__.py
index 814217a..e8d699a 100644
--- a/entries/water_distribution_exeter/__init__.py
+++ b/entries/water_distribution_exeter/__init__.py
@@ -150,3 +150,9 @@ def parse(alts=None):
             # the placeholder diameter of the candidate pipes is not a value
             g.ep.diameter.a[g.ep.candidate.a.astype(bool)] = numpy.nan
         yield alt, g
+
+
+def get_pos(g, sbm_fit):
+    # Spatial network: laid out with the default parameters of cfd_layout(),
+    # without the partition of the SBM fit
+    return cfd_layout(g)
[entries] New entry: water_distribution_exeter by Tiago de Paula Peixoto b82125c
diff --git a/entries/water_distribution_exeter/__init__.py b/entries/water_distribution_exeter/__init__.py
new file mode 100644
index 0000000..814217a
--- /dev/null
+++ b/entries/water_distribution_exeter/__init__.py
@@ -0,0 +1,152 @@
+#! /usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2020-2026 Tiago de Paula Peixoto <tiago@skewed.de>
+#
+# This program is free software: you can redistribute it and/or modify it under
+# the terms of the GNU Affero General Public License as published by the Free
+# Software Foundation, either version 3 of the License, or (at your option) any
+# later version.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Affero General Public License along
+# with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+
+from .. import *
+
+title = "Water distribution networks (Exeter benchmarks)"
+description = """Water distribution networks used as benchmark problems for the design, expansion and operation of water supply systems, distributed as EPANET input files by the Centre for Water Systems of the University of Exeter. Nodes are junctions (pipe intersections and demand points), reservoirs (sources with a fixed head) and storage tanks, and a directed edge is a link (a pipe, pump or valve) between two nodes; the direction is that of the link's definition in the EPANET file (from its start to its end node), which for pipes is only the reference direction of the flow (water may flow either way), but is the flow direction for pumps, check-valve pipes and most valves. The networks are:
+
+- `richmond` and `richmond_skeleton`: the water distribution system of Richmond (Yorkshire Water, UK), as used in a study of operational optimization (K. van Zyl, Exeter, 2001); the skeleton version is a simplified schematic representation, not a hydraulically equivalent model.
+- `exnet`: EXNET, a large real network serving about 400,000 people, used for an expansion (reinforcement) benchmark of the Centre for Water Systems (one of its nodes has no links).
+- `wolf_cordera_ranch`: the network of the Wolf-Cordera Ranch development of Colorado Springs Utilities (USA).
+- `d_town`: D-Town, the network of the Battle of the Water Networks II (BWN-II) design competition (five district metered areas and a new zone).
+- `anytown`: Anytown, a classic synthetic expansion benchmark (Walski et al., 1987).
+- the networks of the two-objective design benchmarks of Wang et al. (2015), with their acronyms: `two_reservoir` (TRN, Gessler 1985), `two_loop` (TLN), `bakryun` (BAK), `new_york_tunnels` (NYT), `blacksburg` (BLA), `hanoi` (HAN), `goyang` (GOY), `fossolo` (FOS), `pescara` (PES), `modena` (MOD) and `balerma` (BIN, the Balerma irrigation network, Almería, Spain). The files of the expansion problems `two_reservoir`, `new_york_tunnels` and `anytown` include the candidate pipes of the design problem, i.e. new pipes and duplicates (parallel pipes) of existing pipes whose diameters are to be chosen, with a placeholder diameter of 0.0001 in the file (given here as NaN); these are marked by the edge property `candidate` (see below): in `two_reservoir`, the five new pipes (marked as new in the file) and the duplicates of three existing pipes, i.e. 8 of its 17 pipes (the Centre for Water Systems also distributed this network without the duplicates, as `gessler1985.inp`); in `new_york_tunnels`, a duplicate of each of the 21 tunnels (the version without duplicates, `nytun.inp`, is otherwise identical); in `anytown`, the six new pipes (marked as new in the file; the duplication of existing pipes, also part of the problem, is not represented). The other networks have no such property: `two_loop` and `hanoi` are designs of whole new networks, in which all pipes have the placeholder diameter; in `bakryun`, nine of the 58 pipes (six of them parallel to existing pipes) are new pipes to be sized, but they cannot be identified from the file, in which all pipes have diameters; in the remaining design benchmarks all pipes are sized, or have fixed diameters; and in `exnet`, the 567 existing pipes considered for duplication are tagged in comments of the file, but the duplicates themselves are not included.
+- `bwsn_network_1` and `bwsn_network_2`: the two networks of the Battle of the Water Sensor Networks (BWSN, Ostfeld et al. 2008), a design competition for the placement of contamination warning sensors held at the 8th Water Distribution Systems Analysis Symposium (Cincinnati, 2006), from the archive of the BWSN files distributed by the Centre for Water Systems ("Sensor Placement (BWSN)" on its benchmark page). Network 1 is a hypothetical network with 126 junctions, one reservoir, two tanks, 168 pipes, two pumps and eight valves; Network 2 is based on a real-world system (not identified) and has 12,523 junctions, two reservoirs, two tanks, 14,822 pipes, four pumps and five valves. (The same two networks are also distributed by the University of Kentucky in its "Battle of the Water Network Models" collection, under a CC BY-NC 4.0 licence.)
+
+Other files of the collection are not included: the modified and output versions of the Wolf-Cordera Ranch model (`wolf-modified-fig.inp`, `wolf-output-fig.inp`, `bocika-output.inp`) are the same network with 124 artificial tanks connected via flow control valves, added to simulate simultaneous fire flows, and differ among themselves only in pipe diameters; the EXNET file of the Pareto-front benchmarks (`EXN.inp`) is `exnet` with candidate duplicate pipes.
+
+The networks have the following properties:
+
+- Nodes: `name`, the node ID in the EPANET file; `type`, "junction", "reservoir" or "tank"; `elevation`, the elevation of a junction or tank, or the (total) head of a reservoir; `demand`, the base demand of a junction (NaN for reservoirs and tanks); `coordinates`, the $(x, y)$ position of the node in the drawing of the network.
+- Edges: `name`, the link ID; `type`, "pipe", "check valve pipe", "pump" or "valve"; `length`, `diameter` and `roughness` of pipes (NaN for other links; `diameter` is also given for valves, and is NaN for candidate pipes); `valve_type`, the type of a valve (e.g. "PRV", "TCV"); `candidate` (only in `two_reservoir`, `new_york_tunnels` and `anytown`), true for the candidate pipes of the design problem (new or duplicate pipes, whose `diameter` is NaN, since the file gives only a placeholder), false for the existing links.
+- Graph: `flow_units`, the flow units of the file ("GPM", "CFS", "LPS", "CMH", ...). Following EPANET's conventions, with US flow units (GPM, CFS) lengths and elevations are in feet and diameters in inches, and with SI flow units (LPS, CMH) lengths and elevations are in metres and diameters in millimetres; demands are in the flow units.[^icon]
+
+[^icon]: Description obtained in part from the [ICON](https://icon.colorado.edu) project."""
+tags = ['Technological', 'Weighted', 'Spatial', 'Metadata']
+url = ['https://web.archive.org/web/20170914223105/http://emps.exeter.ac.uk/engineering/research/cws/resources/benchmarks/design-resiliance-pareto-fronts/summary-of-benchmark-problems/',
+       'https://web.archive.org/web/20140108061328/http://emps.exeter.ac.uk/engineering/research/cws/resources/benchmarks/']
+citation = [('A. Yazdani, P. Jeffrey, "Complex network analysis of water distribution systems." Chaos 21(1), 016111 (2011)', 'https://doi.org/10.1063/1.3540339'),
+            ('Q. Wang, M. Guidolin, D. Savic, Z. Kapelan, "Two-objective design of benchmark problems of a water distribution system via MOEAs: Towards the best-known approximation of the true Pareto front." Journal of Water Resources Planning and Management 141(3), 04014060 (2015)', 'https://doi.org/10.1061/(ASCE)WR.1943-5452.0000460'),
+            ('A. Ostfeld et al., "The Battle of the Water Sensor Networks (BWSN): A Design Challenge for Engineers and Algorithms." Journal of Water Resources Planning and Management 134(6), 556-568 (2008)', 'https://doi.org/10.1061/(ASCE)0733-9496(2008)134:6(556)')]
+icon_hash = '56a85c8e26855e083a2f7961'
+upstream_license = None
+# The benchmark pages of the Centre for Water Systems no longer link the
+# files; they are obtained from the Internet Archive.
+upstream_prefix = 'https://web.archive.org/web'
+_D = 'http://emps.exeter.ac.uk:80/media/universityofexeter/emps/research/cws/downloads'
+_files = {
+    'richmond': ('20160612133417', 'Richmond_standard.inp'),
+    'richmond_skeleton': ('20170714112341', 'Richmond_skeleton.inp'),
+    'exnet': ('20170802084754', 'exnet.inp'),
+    'wolf_cordera_ranch': ('20170802012656', 'wolf-initial-fig.inp'),
+    'd_town': ('20170714085154', 'd-town.inp'),
+    'anytown': ('20150515033355', 'anytown.inp'),
+    'two_reservoir': ('20191009061911', 'data/3-epanet/TRN.inp'),
+    'two_loop': ('20190113090834', 'data/3-epanet/TLN.inp'),
+    'bakryun': ('20191009061816', 'data/3-epanet/BAK.inp'),
+    'new_york_tunnels': ('20191009061856', 'data/3-epanet/NYT.inp'),
+    'blacksburg': ('20191009061826', 'data/3-epanet/BLA.inp'),
+    'hanoi': ('20191009061846', 'data/3-epanet/HAN.inp'),
+    'goyang': ('20191009061841', 'data/3-epanet/GOY.inp'),
+    'fossolo': ('20190820201111', 'data/3-epanet/FOS.inp'),
+    'pescara': ('20191009061901', 'data/3-epanet/PES.inp'),
+    'modena': ('20191009061851', 'data/3-epanet/MOD.inp'),
+    'balerma': ('20191009061821', 'data/3-epanet/BIN.inp')}
+archived_urls = {f'{alt}.inp': f'https://web.archive.org/web/{ts}id_/{_D}/{path}'
+                 for alt, (ts, path) in _files.items()}
+# The BWSN networks are two members of a large (168 MB) archive, which also
+# contains simulation results and an audio recording; only the
+# two members are fetched, with HTTP range requests, given their local header
+# offsets, compressed sizes and CRC-32 checksums in the archive's central
+# directory.
+_bwsn_zip = 'https://web.archive.org/web/20240619180054id_/https://emps.exeter.ac.uk/media/universityofexeter/emps/research/cws/downloads/Ostfeld_et_al._BWSN_files.zip'
+_bwsn = {
+    'bwsn_network_1': ('BWSN_Manuscript_Files_Ostfeld_et_al/2_BWSN_Network_1.inp',
+                       61419844, 8120, 0x40f0198c),
+    'bwsn_network_2': ('BWSN_Manuscript_Files_Ostfeld_et_al/3_BWSN_Network_2.inp',
+                       61428050, 451282, 0xf446a241)}
+files = [(f'{alt}.inp', alt, None) for alt in list(_files) + list(_bwsn)]
+# Expansion problems whose files include the candidate pipes, identified by
+# their placeholder diameter (consistently with the comments of the files and
+# with the duplicate-free versions gessler1985.inp and nytun.inp), with their
+# expected numbers.
+_candidates = {'two_reservoir': 8, 'new_york_tunnels': 21, 'anytown': 6}
+
+def _fetch_zip_member(url, member, offset, csize, crc):
+    import struct, zlib
+    with open_url(url, headers={"Range": f"bytes={offset}-{offset + csize + 1023}"},
+                  timeout=300) as f:
+        data = f.read()
+        partial = f.status == 206
+    if not partial:
+        # the server ignored the range: this is the whole archive
+        with zipfile.ZipFile(io.BytesIO(data)) as z:
+            data = z.read(member)
+    else:
+        (sig, _, _, method, _, _, _, _, _, fnl,
+         exl) = struct.unpack("<IHHHHHIIIHH", data[:30])
+        if sig != 0x04034b50 or data[30:30 + fnl].decode() != member:
+            raise RuntimeError(f"unexpected local header for {member}")
+        data = data[30 + fnl + exl:30 + fnl + exl + csize]
+        if method == 8:
+            data = zlib.decompress(data, -15)
+    if zlib.crc32(data) != crc:
+        raise RuntimeError(f"CRC-32 mismatch for {member}")
+    return data
+
+def fetch_upstream(force=False):
+    name = __name__.split(".")[-1]
+    fetch_archived_files(name, archived_urls, force, tries=4)
+    for alt, (member, offset, csize, crc) in _bwsn.items():
+        fname = f'{alt}.inp'
+        if not force:
+            try:
+                with open_upstream_file(name, fname, "rb"):
+                    continue
+            except (FileNotFoundError, IOError):
+                pass
+        data = retry_download(_fetch_zip_member, _bwsn_zip, member, offset,
+                              csize, crc, tries=4)
+        if not data.lstrip().startswith(b"[TITLE]"):
+            raise RuntimeError(f"unexpected content for {fname}")
+        with open_upstream_file(name, fname, "wb") as output:
+            output.write(data)
+
+@cache_network()
+@coerce_props(vforce={"name": "string"}, eforce={"name": "string"})
+@annotate()
+def parse(alts=None):
+    global files
+    name = __name__.split(".")[-1]
+    for fname, alt, fmt in files:
+        if alts is not None and alt not in alts:
+            continue
+        with open_upstream_file(name, fname, "rb") as f:
+            g = read_epanet(f)
+        if alt in _candidates:
+            g.ep.candidate = g.new_ep("bool")
+            for e in g.edges():
+                g.ep.candidate[e] = (g.ep.type[e] == "pipe" and
+                                     g.ep.diameter[e] == 0.0001)
+            if g.ep.candidate.a.sum() != _candidates[alt]:
+                raise ValueError(f"unexpected number of candidate pipes in {alt}")
+            # the placeholder diameter of the candidate pipes is not a value
+            g.ep.diameter.a[g.ep.candidate.a.astype(bool)] = numpy.nan
+        yield alt, g