Skip to content

Commit 9fe0e50

Browse files
authored
Merge pull request #360 from gwmod/dev
Release v0.8
2 parents 008e6e8 + 39c83a5 commit 9fe0e50

95 files changed

Lines changed: 3524 additions & 1512 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/ci.yml

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,13 @@ jobs:
1717
runs-on: ubuntu-latest
1818
strategy:
1919
matrix:
20-
python-version: [3.9]
20+
python-version: [3.11]
2121

2222
steps:
23-
- uses: actions/checkout@v3
23+
- uses: actions/checkout@v4
2424

2525
- name: Set up Python ${{ matrix.python-version }}
26-
uses: actions/setup-python@v4
26+
uses: actions/setup-python@v5
2727
with:
2828
python-version: ${{ matrix.python-version }}
2929

@@ -32,25 +32,15 @@ jobs:
3232
python -m pip install --upgrade pip
3333
pip install -e .[ci]
3434
35-
- name: Lint with flake8
36-
run: |
37-
# stop the build if there are Python syntax errors or undefined names
38-
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
39-
# exit-zero treats all errors as warnings.
40-
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=80 --statistics
41-
4235
- name: Download executables needed for tests
4336
shell: bash -l {0}
4437
run: |
4538
python -c "import nlmod; nlmod.util.download_mfbinaries()"
4639
47-
- name: Run notebooks
48-
if: ${{ github.event_name == 'push' }}
49-
run: |
50-
py.test ./tests -m "not notebooks"
51-
5240
- name: Run tests only
53-
if: ${{ github.event_name == 'pull_request' }}
41+
env:
42+
NHI_GWO_USERNAME: ${{ secrets.NHI_GWO_USERNAME}}
43+
NHI_GWO_PASSWORD: ${{ secrets.NHI_GWO_PASSWORD}}
5444
run: |
5545
py.test ./tests -m "not notebooks"
5646

.github/workflows/python-publish.yml

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,22 +9,24 @@ on:
99

1010
jobs:
1111
deploy:
12-
1312
runs-on: ubuntu-latest
14-
1513
steps:
16-
- uses: actions/checkout@v3
14+
- uses: actions/checkout@v4
15+
1716
- name: Set up Python
18-
uses: actions/setup-python@v4
17+
uses: actions/setup-python@v5
1918
with:
20-
python-version: '3.9'
19+
python-version: '3.11'
20+
2121
- name: Install dependencies
2222
run: |
2323
python -m pip install --upgrade pip
2424
pip install build setuptools wheel
25+
2526
- name: build binary wheel and a source tarball
2627
run: |
2728
python -m build --sdist --wheel --outdir dist/
29+
2830
- name: Publish a Python distribution to PyPI
2931
uses: pypa/gh-action-pypi-publish@release/v1
3032
with:

.prospector.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ pylint:
2929
- too-many-branches
3030
- too-many-statements
3131
- logging-fstring-interpolation
32+
- import-outside-toplevel
33+
- implicit-str-concat
3234

3335
mccabe:
3436
disable:

README.md

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,13 @@ groundwater models, makes models more reproducible and transparent.
1818

1919
The functions in `nlmod` have four main objectives:
2020

21-
1. Create and adapt the temporal and spatial discretization of a MODFLOW model using an xarray Dataset (`nlmod.dims`).
22-
2. Download and read data from external sources, project this data on the modelgrid and add this data to an xarray Dataset (`nlmod.read`).
23-
3. Use data in an xarray Dataset to build modflow packages for both groundwater flow and transport models using FloPy (`nlmod.sim`, `nlmod.gwf` and `nlmod.gwt` for Modflow 6 and `nlmod.modpath` for Modpath).
21+
1. Create and adapt the temporal and spatial discretization of a MODFLOW model using an
22+
xarray Dataset (`nlmod.dims`).
23+
2. Download and read data from external sources, project this data on the modelgrid and
24+
add this data to an xarray Dataset (`nlmod.read`).
25+
3. Use data in an xarray Dataset to build modflow packages for both groundwater flow
26+
and transport models using FloPy (`nlmod.sim`, `nlmod.gwf` and `nlmod.gwt` for
27+
Modflow 6 and `nlmod.modpath` for Modpath).
2428
4. Visualise modeldata in Python (`nlmod.plot`) or GIS software (`nlmod.gis`).
2529

2630
More information can be found on the documentation-website:
@@ -50,9 +54,10 @@ Install the module with pip:
5054
* `dask`
5155
* `colorama`
5256
* `joblib`
57+
* `bottleneck`
5358

5459
There are some optional dependecies, only needed (and imported) in a single method.
55-
Examples of this are `bottleneck` (used in calculate_gxg), `geocube` (used in
60+
Examples of this are `geocube` (used in
5661
add_min_ahn_to_gdf), `h5netcdf` (used for hdf5 files backend in xarray), `scikit-image`
5762
(used in calculate_sea_coverage). To install `nlmod` with the optional dependencies use:
5863

@@ -65,11 +70,4 @@ notoriously hard to install on certain platforms. Please see the
6570

6671
## Getting started
6772

68-
If you are using `nlmod` for the first time you need to download the MODFLOW
69-
executables. You can easily download these executables by running this Python code:
70-
71-
import nlmod
72-
nlmod.download_mfbinaries()
73-
74-
After you've downloaded the executables you can run the Jupyter Notebooks in the
75-
examples folder. These notebooks illustrate how to use the `nlmod` package.
73+
Start with the Jupyter Notebooks in the examples folder. These notebooks illustrate how to use the `nlmod` package.

docs/conf.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,11 @@
1010
# add these directories to sys.path here. If the directory is relative to the
1111
# documentation root, use os.path.abspath to make it absolute, like shown here.
1212
#
13-
from nlmod import __version__
1413
import os
1514
import sys
1615

16+
from nlmod import __version__
17+
1718
sys.path.insert(0, os.path.abspath("."))
1819

1920

docs/examples/00_model_from_scratch.ipynb

Lines changed: 5 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -20,28 +20,9 @@
2020
"outputs": [],
2121
"source": [
2222
"import flopy as fp\n",
23-
"import matplotlib.pyplot as plt\n",
24-
"import nlmod\n",
25-
"import numpy as np\n",
26-
"import pandas as pd"
27-
]
28-
},
29-
{
30-
"cell_type": "code",
31-
"execution_count": null,
32-
"metadata": {},
33-
"outputs": [],
34-
"source": [
35-
"nlmod.util.get_color_logger(\"INFO\");"
36-
]
37-
},
38-
{
39-
"attachments": {},
40-
"cell_type": "markdown",
41-
"metadata": {},
42-
"source": [
43-
"## Download MODFLOW-binaries\n",
44-
"To run MODFLOW, we need to download the MODFLOW-excecutables. We do this with the following code:"
23+
"import pandas as pd\n",
24+
"\n",
25+
"import nlmod"
4526
]
4627
},
4728
{
@@ -50,8 +31,8 @@
5031
"metadata": {},
5132
"outputs": [],
5233
"source": [
53-
"if not nlmod.util.check_presence_mfbinaries():\n",
54-
" nlmod.download_mfbinaries()"
34+
"nlmod.util.get_color_logger(\"INFO\")\n",
35+
"nlmod.show_versions()"
5536
]
5637
},
5738
{

docs/examples/01_basic_model.ipynb

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,6 @@
1818
"metadata": {},
1919
"outputs": [],
2020
"source": [
21-
"import logging\n",
22-
"import os\n",
23-
"\n",
24-
"import flopy\n",
25-
"import geopandas as gpd\n",
26-
"import matplotlib.pyplot as plt\n",
2721
"import nlmod"
2822
]
2923
},
@@ -33,9 +27,8 @@
3327
"metadata": {},
3428
"outputs": [],
3529
"source": [
36-
"print(f\"nlmod version: {nlmod.__version__}\")\n",
37-
"\n",
38-
"nlmod.util.get_color_logger(\"INFO\")"
30+
"nlmod.util.get_color_logger(\"INFO\")\n",
31+
"nlmod.show_versions()"
3932
]
4033
},
4134
{
@@ -44,19 +37,20 @@
4437
"source": [
4538
"## Create model\n",
4639
"\n",
47-
"With the code below we create a modflow model with the name 'IJmuiden'. This model has the following properties :\n",
40+
"With the code below we create a modflow model with the name 'IJmuiden'. This model has the following properties:\n",
41+
"\n",
4842
"- an extent that covers part of the Northsea, Noordzeekanaal and the small port city IJmuiden.\n",
49-
"- a structured grid based on the subsurface models [Regis](https://www.dinoloket.nl/regis-ii-het-hydrogeologische-model) and [Geotop](https://www.dinoloket.nl/detaillering-van-de-bovenste-lagen-met-geotop). The Regis layers that are not present within the extent are removed. In this case we use 'MSz1' as the bottom layer of the model. Use `nlmod.read.regis.get_layer_names()` to get all the layer names of Regis. All Regis layers below this layer are not used in the model. Geotop is used to replace the holoceen layer in Regis because there is no kh or kv defined for the holoceen in Regis. Part of the model is in the North sea. Regis and Geotop have no data there. Therefore the Regis and Geotop layers are extrapolated from the shore and the seabed is added using bathymetry data from [Jarkus](https://www.openearth.nl/rws-bathymetry/2018.html).\n",
43+
"- a structured grid based on the subsurface models [Regis](https://www.dinoloket.nl/regis-ii-het-hydrogeologische-model) and [Geotop](https://www.dinoloket.nl/detaillering-van-de-bovenste-lagen-met-geotop). The Regis layers that are not present within the extent are removed. In this case we use 'MSz1' as the bottom layer of the model. Use `nlmod.read.regis.get_layer_names()` to get all the layer names of Regis. All Regis layers below this layer are not used in the model. Geotop is used to replace the Holocene layer in Regis because there is no kh or kv defined for the Holocene in Regis. Part of the model is in the North sea. Regis and Geotop have no data there. Therefore the Regis and Geotop layers are extrapolated from the shore and the seabed is added using bathymetry data from [Jarkus](https://www.openearth.nl/rws-bathymetry/2018.html).\n",
5044
"- starting heads of 1 in every cell.\n",
51-
"- the model is a steady state model of a single time step.\n",
45+
"- the model is a steady state model with a single time step.\n",
5246
"- big surface water bodies (Northsea, IJsselmeer, Markermeer, Noordzeekanaal) within the extent are added as a general head boundary. The surface water bodies are obtained from a [shapefile](..\\data\\shapes\\opp_water.shp).\n",
53-
"- surface drainage is added using [ahn](https://www.ahn.nl) data and a default conductance of $1000 m^2/d$\n",
54-
"- recharge is added using data from the [knmi](https://www.knmi.nl/nederland-nu/klimatologie/daggegevens) using the following steps:~~\n",
55-
" 1. Check for each cell which KNMI weather and/or rainfall station is closest.\n",
56-
" 2. Download the data for the stations found in 1. for the model period. For a steady state stress period the average precipitation and evaporation of 8 years before the stress period time is used.\n",
57-
" 3. Combine precipitation and evaporation data from step 2 to create a recharge time series for each cell\n",
58-
" 4. Add the timeseries to the model dataset and create the recharge package.\n",
59-
"- constant head boundaries are added to the model edges in every layer. The starting head is used as constant head."
47+
"- surface drainage is added using the Dutch DEM ([ahn](https://www.ahn.nl)) and a default conductance of $1000 m^2/d$\n",
48+
"- recharge is added using data from [knmi](https://www.knmi.nl/nederland-nu/klimatologie/daggegevens) using the following steps:\n",
49+
" 1. Check for each cell which KNMI weather and/or rainfall station is closest.\n",
50+
" 2. Download the data for the stations found in 1. for the model period. For a steady state stress period the average precipitation and evaporation of 8 years before the stress period time is used.\n",
51+
" 3. Combine precipitation and evaporation data from step 2 to create a recharge time series for each cell,\n",
52+
" 4. Add the timeseries to the model dataset and create the recharge package.\n",
53+
"- constant head boundaries are added to the model edges in every layer. The starting head is used as the specified head."
6054
]
6155
},
6256
{
@@ -215,6 +209,7 @@
215209
"source": [
216210
"## Write and Run\n",
217211
"Now that we've created all the modflow packages we need to write them to modflow files. You always have to write the modflow data to the model workspace before you can run the model. You can write the model files and run the model using the function `nlmod.sim.write_and_run)` as shown below. This function has two additional options:\n",
212+
"\n",
218213
"1. Write the model dataset to the disk if `write_ds` is `True`. This makes it easier and faster to load model data if you ever need it. \n",
219214
"2. Write a copy of this Jupyter Notebook to the same directory as the modflow files if `nb_path` is the name of this Jupyter Notebook. It can be useful to have a copy of the script that created the modflow files, together with the files. "
220215
]
@@ -250,7 +245,7 @@
250245
"cell_type": "markdown",
251246
"metadata": {},
252247
"source": [
253-
"Data from a model with a structured grid can be easily visualised using the model dataset. Below some examples"
248+
"Data from a model with a structured grid can be easily visualised using the model dataset. Below are some examples:"
254249
]
255250
},
256251
{

docs/examples/02_surface_water.ipynb

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
"\n",
1313
"This example notebook shows some how to add surface water defined in a GeoDataFrame to a MODFLOW model using the `nlmod` package.\n",
1414
"\n",
15-
"There are three water boards in the model area, of which we download seasonal data about the stage of the surface water. In this notebook we perform a steady-state run, in which the stage of the surface water is the mean of the summer and winter stage. For locations without a stage from the water board, we delineate information from a Digital Terrain Model, to set a stage. We assign a stage of 0.0 m NAP to the river Lek. to The surface water bodies in each cell are aggregated using an area-weighted method and added to the model as a river-package."
15+
"There are three water boards in the model area, and we download seasonal data about the stage of the surface water for each. In this notebook we perform a steady-state run, in which the stage of the surface water is the mean of the summer and winter stage. For locations without a stage from the water board, we obtain information from a Digital Terrain Model near the surface water features, to estimate a stage. We assign a stage of 0.0 m NAP to the river Lek. The surface water bodies in each cell are aggregated using an area-weighted method and added to the model with the river-package."
1616
]
1717
},
1818
{
@@ -25,12 +25,10 @@
2525
"import os\n",
2626
"\n",
2727
"import flopy\n",
28-
"import rioxarray\n",
2928
"import matplotlib.pyplot as plt\n",
30-
"import nlmod\n",
31-
"from geocube.api.core import make_geocube\n",
32-
"from functools import partial\n",
33-
"from geocube.rasterize import rasterize_image"
29+
"import rioxarray\n",
30+
"\n",
31+
"import nlmod"
3432
]
3533
},
3634
{
@@ -40,9 +38,8 @@
4038
"metadata": {},
4139
"outputs": [],
4240
"source": [
43-
"print(f\"nlmod version: {nlmod.__version__}\")\n",
44-
"\n",
45-
"nlmod.util.get_color_logger(\"INFO\")"
41+
"nlmod.util.get_color_logger(\"INFO\")\n",
42+
"nlmod.show_versions()"
4643
]
4744
},
4845
{
@@ -94,7 +91,7 @@
9491
"if not os.path.isfile(fname_ahn):\n",
9592
" ahn = nlmod.read.ahn.get_ahn4(extent, identifier=\"AHN4_DTM_5m\")\n",
9693
" ahn.rio.to_raster(fname_ahn)\n",
97-
"ahn = rioxarray.open_rasterio(fname_ahn, mask_and_scale=True)"
94+
"ahn = rioxarray.open_rasterio(fname_ahn, mask_and_scale=True)[0]"
9895
]
9996
},
10097
{
@@ -103,7 +100,7 @@
103100
"metadata": {},
104101
"source": [
105102
"### Layer 'waterdeel' from bgt\n",
106-
"As the source of the location of the surface water bodies we use the 'waterdeel' layer of the Basisregistratie Grootschalige Topografie (BGT). This data consists of detailed polygons, maintained by dutch government agencies (water boards, municipalities and Rijkswatrstaat)."
103+
"As the source of the location of the surface water bodies we use the 'waterdeel' layer of the Basisregistratie Grootschalige Topografie (BGT). This data consists of detailed polygons, maintained by dutch government agencies (water boards, municipalities and Rijkswaterstaat)."
107104
]
108105
},
109106
{
@@ -223,7 +220,7 @@
223220
"metadata": {},
224221
"source": [
225222
"#### Save the data to use in other notebooks as well\n",
226-
"We save the bgt-data to a GeoPackage file, so we can use the data in other notebooks with surface water as well"
223+
"We save the bgt-data to a GeoPackage file, so we can use the data in other notebooks with surface water as well."
227224
]
228225
},
229226
{
@@ -275,7 +272,13 @@
275272
"\n",
276273
"The `stage` and the `botm` columns are present in our dataset. The bottom resistance `c0` is rarely known, and is usually estimated when building the model. We will add our estimate later on.\n",
277274
"\n",
278-
"*__Note__: the NaN's in the dataset indicate that not all parameters are known for each feature. This is not necessarily a problem but this will mean some features will not be converted to model input.*"
275+
"<div class=\"alert alert-info\">\n",
276+
" \n",
277+
"<b>Note:</b>\n",
278+
"\n",
279+
"The NaN's in the dataset indicate that not all parameters are known for each feature. This is not necessarily a problem but this will mean some features will not be converted to model input.\n",
280+
" \n",
281+
"</div>"
279282
]
280283
},
281284
{
@@ -493,7 +496,7 @@
493496
"xlim = ax.get_xlim()\n",
494497
"ylim = ax.get_ylim()\n",
495498
"gwf.modelgrid.plot(ax=ax)\n",
496-
"ax.set_xlim(xlim[0], xlim[0] + ds.delr * 1.1)\n",
499+
"ax.set_xlim(xlim[0], xlim[0] + nlmod.grid.get_delr(ds)[-1] * 1.1)\n",
497500
"ax.set_ylim(ylim)\n",
498501
"ax.set_title(f\"Surface water shapes in cell: {cid}\")"
499502
]

0 commit comments

Comments
 (0)