Skip to content

Commit

Permalink
Merge remote-tracking branch 'usepa/main' into gis_plotting
Browse files Browse the repository at this point in the history
  • Loading branch information
kbonney committed Nov 5, 2024
2 parents 1eaaade + 9a2a18f commit f0c32d4
Show file tree
Hide file tree
Showing 13 changed files with 262 additions and 68 deletions.
6 changes: 4 additions & 2 deletions .github/workflows/build_deploy_pages.yml
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
# This is a basic workflow to help you get started with Actions

name: docs

on:
push:
branches: [main]
pull_request:
branches: [main]
workflow_dispatch:

jobs:
build:
name: Build the documentation with Sphinx
Expand Down Expand Up @@ -36,6 +37,7 @@ jobs:
deploy:
name: Deploy documentation to GitHub Pages
needs: build
if: github.event_name == 'push'
permissions:
contents: read
pages: write # to deploy to Pages
Expand Down
78 changes: 23 additions & 55 deletions .github/workflows/build_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ jobs:
os: [windows-latest, macOS-13, ubuntu-latest]
fail-fast: false
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
Expand All @@ -37,7 +37,7 @@ jobs:
python setup.py bdist_wheel
ls dist/*
- name: Save wheel
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: wntr_${{ matrix.python-version }}_${{ matrix.os }}.whl
path: dist/wntr*
Expand All @@ -52,11 +52,11 @@ jobs:
fail-fast: false
steps:
- name: Set up Python
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Download wheel
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4
with:
name: wntr_${{ matrix.python-version }}_${{ matrix.os }}.whl
- name: Install wntr
Expand All @@ -76,9 +76,9 @@ jobs:
os: [windows-latest, macOS-13, ubuntu-latest]
fail-fast: false
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
Expand All @@ -94,33 +94,35 @@ jobs:
coverage run --context=${{ matrix.os }}.py${{ matrix.python-version }} --source=wntr --omit="*/tests/*","*/sim/network_isolation/network_isolation.py","*/sim/aml/evaluator.py" --append -m pytest --doctest-glob="*.rst" documentation
env:
COVERAGE_FILE: .coverage.${{ matrix.python-version }}.${{ matrix.os }}

- name: Save coverage
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v4
with:
name: coverage
name: .coverage.${{ matrix.python-version }}.${{ matrix.os }}
path: .coverage.${{ matrix.python-version }}.${{ matrix.os }}
include-hidden-files: true

combine_reports:
needs: [ pytest_coverage ]
runs-on: ubuntu-latest
steps:
- name: Set up Python
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: 3.11
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- name: Install coverage
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
python -m pip install -e .
# pip install coveralls
pip install coveralls
- name: Download coverage artifacts from test matrix
uses: actions/download-artifact@v2
uses: actions/download-artifact@v4
with:
name: coverage
pattern: .coverage.*.ubuntu-latest # coverage from other OS cause problems
- name: Setup coverage and combine reports
run: coverage combine .coverage.*.ubuntu-latest
- name: Create coverage report
run: |
echo "[paths]" > .coveragerc
echo "source = " >> .coveragerc
Expand All @@ -129,55 +131,21 @@ jobs:
echo " D:\\a\\WNTR\\WNTR\\wntr" >> .coveragerc
echo " /home/runner/work/WNTR/WNTR/wntr" >> .coveragerc
echo " /Users/runner/work/WNTR/WNTR/wntr" >> .coveragerc
coverage combine
- name: Create coverage report
run: |
echo " ${{ github.workspace }}/wntr" >> .coveragerc
coverage report
coverage json --pretty-print
coverage html --show-contexts
- name: Save coverage JSON
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v4
with:
name: coverage
name: coverage-json
path: coverage.json
- name: Save coverage html
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v4
with:
name: coverage
name: coverage-html
path: htmlcov

combine_reports_upload_coveralls:
needs: [ pytest_coverage ]
runs-on: ubuntu-latest
continue-on-error: true
steps:
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: 3.11
- uses: actions/checkout@v2
- name: Install coverage
run: |
python -m pip install --upgrade pip
pip install coveralls
pip install -r requirements.txt
python -m pip install -e .
- name: Download coverage artifacts from test matrix
uses: actions/download-artifact@v2
with:
name: coverage
- name: Setup coverage and combine reports
run: |
echo "[paths]" > .coveragerc
echo "source = " >> .coveragerc
echo " wntr/" >> .coveragerc
echo " wntr\\" >> .coveragerc
echo " D:\\a\\WNTR\\WNTR\\wntr" >> .coveragerc
echo " /home/runner/work/WNTR/WNTR/wntr" >> .coveragerc
echo " /Users/runner/work/WNTR/WNTR/wntr" >> .coveragerc
coverage combine
- name: Push to coveralls
run: |
coveralls --service=github
run: coveralls --service=github --rcfile=.coveragerc
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
4 changes: 3 additions & 1 deletion .github/workflows/quick_check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ jobs:
strategy:
matrix:
python-version: ['3.9', '3.11']
fail-fast: false
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
Expand All @@ -33,7 +34,8 @@ jobs:
python -m pip install -e .
- name: Run tests and coverage (unittests plus doctests)
run: |
coverage run --source=wntr --omit="*/tests/*","*/sim/network_isolation/network_isolation.py","*/sim/aml/evaluator.py" -m pytest -m "not time_consuming" --doctest-modules --doctest-glob="*.rst" wntr
coverage run --source=wntr --omit="*/tests/*","*/sim/network_isolation/network_isolation.py","*/sim/aml/evaluator.py" -m pytest -m "not time_consuming" --doctest-modules --doctest-glob="*.rst" wntr
coverage run --source=wntr --omit="*/tests/*","*/sim/network_isolation/network_isolation.py","*/sim/aml/evaluator.py" --append -m pytest --doctest-glob="*.rst" documentation
coverage report --fail-under=70
# coverage run --source=wntr --omit="*/tests/*" --append -m pytest --doctest-glob="*.rst" documentation

1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ temp*

examples/*.inp
wntr/tests/*.png
wntr/tests/*.tif

documentation/_local
documentation/apidoc
Binary file added documentation/figures/sample_elevations.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
107 changes: 106 additions & 1 deletion documentation/gis.rst
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@
>>> hydrant_data = gpd.read_file(examples_dir+'/data/Net1_hydrant_data.geojson')
>>> valve_data = gpd.read_file(examples_dir+'/data/Net1_valve_data.geojson')

.. doctest::
:hide:
:skipif: gpd is None or rasterio is None

>>> elevation_data_path = examples_dir+'/data/Net1_elevation_data.tif'

.. _geospatial:

Geospatial capabilities
Expand All @@ -47,7 +53,8 @@ The following section describes capabilities in WTNR that use GeoPandas GeoDataF

.. note::
Functions that use GeoDataFrames require the Python package **geopandas** :cite:p:`jvfm21`
and **rtree** :cite:p:`rtree`. Both are optional dependencies of WNTR.
and **rtree** :cite:p:`rtree`, and functions that use raster files require the
Python package **rasterio**. All three are optional dependencies of WNTR.
Note that **shapely** is installed with geopandas.

The following examples use a water network generated from Net1.inp.
Expand Down Expand Up @@ -822,3 +829,101 @@ the census tracts (polygons) is different than the junction and pipe attributes.
:alt: Intersection of junctions and pipes with mean income demographic data in EPANET example Net1

Net1 with mean income demographic data intersected with junctions and pipes.

Sample raster at points geometries
--------------------------------------

The :class:`~wntr.gis.sample_raster` function can be used to sample a raster file at point geometries,
such as the nodes of a water network. A common use case for this function is to assign elevation to the
nodes of a water network model, however other geospatial information such as climate or hazard data could be sampled
using this function.

The network file, Net1.inp, in EPSG:4326 CRS is used in the example below.
The raster data in the GeoTIFF format is also in EPSG:4326 CRS.
See :ref:`crs` for more information.

.. doctest::
:skipif: gpd is None

>>> wn = wntr.network.WaterNetworkModel('networks/Net1.inp') # doctest: +SKIP
>>> wn_gis = wntr.network.to_gis(wn, crs='EPSG:4326')

Sample elevations at junctions
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Elevation is an essential attribute for accurate simulation of pressure in a water network and is
commonly provided in GeoTIFF (.tif) files. The following example shows how such files can be sampled
and assigned to the junctions and tanks of a network. Note that elevation data generally needs
to be adjusted to account for buried pipes.

.. doctest::
:skipif: gpd is None or rasterio is None

>>> elevation_data_path = 'data/Net1_elevation_data.tif' # doctest: +SKIP
>>> junctions = wn_gis.junctions
>>> junction_elevations = wntr.gis.sample_raster(junctions, elevation_data_path)
>>> print(junction_elevations)
name
10 1400.0
11 2100.0
12 3500.0
13 4900.0
21 1200.0
22 2000.0
23 2800.0
31 300.0
32 500.0
dtype: float64

.. doctest::
:skipif: gpd is None or rasterio is None

>>> tanks = wn_gis.tanks
>>> tank_elevations = wntr.gis.sample_raster(tanks, elevation_data_path)
>>> print(tank_elevations)
name
2 4500.0
dtype: float64

To use these elevations for hydraulic simulations,
they need to be added to the water network object.

.. doctest::
:skipif: gpd is None or rasterio is None

>>> for junction_name in wn.junction_name_list:
... junction = wn.get_node(junction_name)
... junction.elevation = junction_elevations[junction_name]

.. doctest::
:skipif: gpd is None or rasterio is None

>>> for tank_name in wn.tank_name_list:
... tank = wn.get_node(tank_name)
... tank.elevation = tank_elevations[tank_name]

The sampled elevations can be plotted as follows. The
resulting :numref:`fig-sample-elevations` illustrates Net1 with the elevations
sampled from the raster file.

.. doctest::
:skipif: gpd is None or rasterio is None

>>> ax = wntr.graphics.plot_network(wn, node_attribute="elevation", link_width=1.5,
... node_size=40, node_colorbar_label='Raster Elevation')

.. doctest::
:skipif: gpd is None or rasterio is None
:hide:

>>> bounds = ax.axis('equal')
>>> plt.tight_layout()
>>> plt.savefig('sample_elevations.png', dpi=300)
>>> plt.close()

.. _fig-sample-elevations:
.. figure:: figures/sample_elevations.png
:width: 640
:alt: Net1 with elevations sampled from raster.

Net1 with elevations sampled from raster.
2 changes: 2 additions & 0 deletions documentation/installation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,8 @@ The following Python packages are optional:
https://pypi.org/project/utm/
* geopandas :cite:p:`jvfm21`: used to work with geospatial data,
https://geopandas.org/
* rasterio :cite:p:`rasterio`: used to work with raster data,
https://rasterio.readthedocs.io/
* rtree :cite:p:`rtree`: used for overlay operations in geopandas,
https://rtree.readthedocs.io/
* openpyxl :cite:p:`gacl18`: used to read/write to Microsoft® Excel® spreadsheets,
Expand Down
8 changes: 8 additions & 0 deletions documentation/references.bib
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,14 @@ @misc{jvfm21
year = "2021"
}

@misc{rasterio,
author = {Sean Gillies and others},
organization = {Mapbox},
title = {{Rasterio: geospatial raster I/O for {Python} programmers}},
year = {2013--},
url = {"https://github.com/rasterio/rasterio"}
}

@article{jcmg11,
author = "Joyner, David and \v{C}ert\'{i}k, Ond\v{r}ej and Meurer, Aaron and Granger, Brian E.",
address = "New York, NY, USA",
Expand Down
Binary file added examples/data/Net1_elevation_data.tif
Binary file not shown.
2 changes: 2 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ folium
utm
openpyxl
geopandas<1.0
fiona<1.10
rasterio
rtree

# Documentation
Expand Down
2 changes: 1 addition & 1 deletion wntr/gis/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
and GIS formatted data and geospatial functions to snap data and find intersections.
"""
from wntr.gis.network import WaterNetworkGIS
from wntr.gis.geospatial import snap, intersect
from wntr.gis.geospatial import snap, intersect, sample_raster

Loading

0 comments on commit f0c32d4

Please sign in to comment.