Skip to content

Commit

Permalink
merge upstream/develop into feat_3099
Browse files Browse the repository at this point in the history
  • Loading branch information
jmccreight committed Nov 12, 2024
2 parents 78fc472 + ff674c3 commit 50a45eb
Show file tree
Hide file tree
Showing 49 changed files with 1,422 additions and 751 deletions.
16 changes: 11 additions & 5 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ jobs:
run: |
python -m pip install --upgrade pip
pip install wheel build 'twine<5.0.0' 'importlib_metadata<=7.0.1' 'setuptools<=72.2.0' 'numpy<2.0'
- name: Base installation
run: |
pip --verbose install .
Expand Down Expand Up @@ -124,8 +123,7 @@ jobs:
- name: Set environment variables
run: |
echo "PYTHON_VERSION=${{ matrix.python-version }}" >> $GITHUB_ENV
echo "PYWS_FORTRAN=true" >> $GITHUB_ENV
echo 'SETUPTOOLS_ENABLE_FEATURES="legacy-editable"' >> $GITHUB_ENV
echo "PYWS_FORTRAN=false" >> $GITHUB_ENV
cat .mf6_ci_ref_remote >> $GITHUB_ENV
- name: Enforce MF6 ref and remote merge to main
Expand All @@ -150,8 +148,9 @@ jobs:
run: .github/scripts/symlink_gfortran_mac.sh

- name: Install Dependencies via Micromamba
uses: mamba-org/setup-micromamba@v1
uses: mamba-org/setup-micromamba@v1.9.0
with:
micromamba-version: '1.5.10-0'
log-level: debug
environment-file: environment.yml
cache-environment: true
Expand Down Expand Up @@ -191,7 +190,14 @@ jobs:
- name: domainless - run tests not requiring domain data
working-directory: autotest
run: pytest -m domainless -n=auto -vv
run: pytest
-m domainless
-n=auto
-vv
--durations=0
--cov=pywatershed
--cov-report=xml
--junitxml=pytest_domainless.xml

- name: sagehen_5yr_no_cascades - generate and manage test data domain, run PRMS and convert csv output to NetCDF
working-directory: autotest
Expand Down
20 changes: 19 additions & 1 deletion .github/workflows/ci_examples.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,30 @@ jobs:
echo "SETUPTOOLS_ENABLE_FEATURES=legacy-editable" >> $GITHUB_ENV
- name: Setup micromamba
uses: mamba-org/setup-micromamba@v1
uses: mamba-org/setup-micromamba@v1.9.0
with:
micromamba-version: '1.5.10-0'
environment-file: environment.yml
cache-environment: true
cache-downloads: true

- name: Checkout MODFLOW 6
uses: actions/checkout@v4
with:
repository: MODFLOW-USGS/modflow6
ref: develop
path: modflow6

- name: Update flopy MODFLOW 6 classes
working-directory: modflow6/autotest
run: |
python update_flopy.py
- name: Install mf6 nightly build binaries
uses: modflowpy/install-modflow-action@v1
with:
repo: modflow6-nightly-build

- name: Install error reporter
run: |
pip install pytest-github-actions-annotate-failures
Expand Down
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
[![Anaconda-Server Badge](https://anaconda.org/conda-forge/pywatershed/badges/version.svg)](https://anaconda.org/conda-forge/pywatershed)
[![Anaconda-Server Badge](https://anaconda.org/conda-forge/pywatershed/badges/platforms.svg)](https://anaconda.org/conda-forge/pywatershed)

[![DOI:10.5066/P9AVWA7Z](https://img.shields.io/badge/DOI-10.5066/P9AVWA7Z-b4a9fe.svg)](https://doi.org/10.5066/P9AVWA7Z)

[![WholeTale](https://raw.githubusercontent.com/whole-tale/wt-design-docs/master/badges/wholetale-explore.svg)](https://dashboard.wholetale.org/run/64ae29e8a887f48b9f173678?tab=metadata)


Expand All @@ -24,6 +26,7 @@
- [Installation](#installation)
- [Getting started / Example notebooks](#getting-started--example-notebooks)
- [Community engagement](#community-engagement)
- [How to Cite](#how-to-cite)
- [Disclaimer](#disclaimer)

<!-- END doctoc generated TOC please keep comment here to allow auto update -->
Expand Down Expand Up @@ -149,6 +152,8 @@ guidelines.

Thank you for your interest.

## How to Cite
McCreight, J., Langevin, C. D., & Hughes, J. D. (2023). pywatershed (Version 1.0.0) [Computer software]. [https://doi.org/10.5066/P9AVWA7Z](https://doi.org/10.5066/P9AVWA7Z)

## Disclaimer

Expand Down
61 changes: 36 additions & 25 deletions autotest/test_mmr_to_mf6_dfw.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@
# Getting the gis files causes problems in parallel in CI. See regression test.

# See below to check if these answers are still up-to-date with
# mf6/autotest/test_swf_dfw.py
# mf6/autotest/test_chf_dfw.py
# Note the answers are from the binary FLW files in
# mf6/autotest/test_swf_dfw.py, if you switch to text files, the line should be
# mf6/autotest/test_chf_dfw.py, if you switch to text files, the line should be
# flw_list = [
# (int(binary), 100),
# ] # one-based cell numbers here if binary, zero-based if text

answers_swf_dfw = {
answers_chf_dfw = {
"ia": np.array([0, 2, 5, 7]),
"ja": np.array([0, 1, 1, 0, 2, 2, 1], dtype=np.int32),
"stage": np.array([[[[1.00196123, 1.00003366, 1.0]]]]),
Expand Down Expand Up @@ -52,9 +52,9 @@
@pytest.mark.skipif(mf6_bin_unavailable, reason="mf6 binary not available")
@pytest.mark.domainless
@pytest.mark.parametrize("binary_flw", [True, False])
def test_mmr_to_mf6_swf_dfw(tmp_path, binary_flw):
def test_mmr_to_mf6_chf_dfw(tmp_path, binary_flw):
# The point of this test is to reproduce the
# modflow6/autotest/test_swf_dfw.py
# modflow6/autotest/test_chf_dfw.py

# Here we supply "seg_mid_elevation" in the parameter data and
# "stress_period_data" in chd options. This bypasses the calculation of
Expand All @@ -68,8 +68,8 @@ def test_mmr_to_mf6_swf_dfw(tmp_path, binary_flw):
# stream segments, the other is about the units of volume/flow being in
# cubicfeet.

name = "swf-dfw01"
output_dir = tmp_path / "test_swf_dfw01"
name = "chf-dfw01"
output_dir = tmp_path / "test_chf_dfw01"
save_flows = True
print_flows = True

Expand Down Expand Up @@ -123,16 +123,16 @@ def test_mmr_to_mf6_swf_dfw(tmp_path, binary_flw):
# vertices could also be supplied by shapefiles
vertices = []
vertices = [[j, j * dx, 0.0] for j in range(nreach + 1)]
cell2d = []
cell1d = []
for j in range(nreach):
cell2d.append([j, 0.5, 2, j, j + 1])
nodes = len(cell2d)
cell1d.append([j, 0.5, 2, j, j + 1])
nodes = len(cell1d)
nvert = len(vertices)
disv1d_options = {
"nodes": nodes,
"nvert": nvert,
"vertices": vertices,
"cell2d": cell2d,
"cell1d": cell1d,
}

# dfw
Expand Down Expand Up @@ -191,9 +191,14 @@ def test_mmr_to_mf6_swf_dfw(tmp_path, binary_flw):
else:
flw_vol = 0.0

# <
time_coord_data = np.array([control.start_time]).astype(
"datetime64[ns]"
)

_ = xr.Dataset(
coords=dict(
time=np.array([control.start_time]),
time=time_coord_data,
nsegment=params.parameters["seg_id"],
),
data_vars={
Expand Down Expand Up @@ -246,26 +251,30 @@ def test_mmr_to_mf6_swf_dfw(tmp_path, binary_flw):
# Checks
assert success

# one can verify the answers match the current mf6 results for test_swf_dfw
# by placing the path to its output here
# one can verify the answers match the current mf6 results for test_chf_dfw
# by placing the path to its output here. Run the following lines to
# generate the mf6 results:
# cd modflow6_for_pws_ci/autotest # or your mf6 repo location
# pytest -s -vv test_chf_dfw.py --keep=keepers
# output_dir = pl.Path(
# "../../modflow6/autotest/keepers/test_mf6model[0-swf-dfw01]0"
# "../../modflow6_for_pws_ci/autotest/keepers/"
# "test_mf6model[0-chf-dfw01]0"
# )

# check binary grid file
grb = flopy.mf6.utils.MfGrdFile(output_dir / f"{name}.disv1d.grb")
ia = grb.ia
ja = grb.ja
assert (answers_swf_dfw["ia"] == ia).all()
assert (answers_swf_dfw["ja"] == ja).all()
assert (answers_chf_dfw["ia"] == ia).all()
assert (answers_chf_dfw["ja"] == ja).all()
assert ia.shape[0] == grb.nodes + 1, "ia in grb file is not correct size"

# check stage file
qobj = flopy.utils.HeadFile(
output_dir / f"{name}.stage", precision="double", text="STAGE"
)
stage = qobj.get_alldata()
assert ((answers_swf_dfw["stage"] - stage) < 1.0e-7).all()
assert ((answers_chf_dfw["stage"] - stage) < 1.0e-7).all()

# read the budget file
budobj = flopy.utils.binaryfile.CellBudgetFile(output_dir / f"{name}.bud")
Expand All @@ -275,17 +284,17 @@ def test_mmr_to_mf6_swf_dfw(tmp_path, binary_flw):
qchd = np.array(budobj.get_data(text="CHD")[0].tolist()[0])
qresidual = np.zeros(grb.nodes)[0]

assert (answers_swf_dfw["flowja"] - flowja < 1.0e-7).all()
assert (answers_swf_dfw["qstorage"] - qstorage < 1.0e-7).all()
assert (answers_swf_dfw["qflw"] - qflw < 1.0e-7).all()
assert (answers_swf_dfw["qchd"] - qchd < 1.0e-7).all()
assert (answers_swf_dfw["qresidual"] - qresidual < 1.0e-7).all()
assert (answers_chf_dfw["flowja"] - flowja < 1.0e-7).all()
assert (answers_chf_dfw["qstorage"] - qstorage < 1.0e-7).all()
assert (answers_chf_dfw["qflw"] - qflw < 1.0e-7).all()
assert (answers_chf_dfw["qchd"] - qchd < 1.0e-7).all()
assert (answers_chf_dfw["qresidual"] - qresidual < 1.0e-7).all()


# <
answers_regression_means = {
"stage_all": 1.03667372881148,
"flow_all": 44.685014111989425,
"stage_all": 1.0372047024253908,
"flow_all": 44.70210250910929,
}


Expand Down Expand Up @@ -406,6 +415,7 @@ def test_mmr_to_mf6_dfw_regression(simulation, tmp_path):
inflow_dir=inflow_dir,
)

dfw.write()
success, buff = dfw.run(silent=False, report=True)
assert success

Expand Down Expand Up @@ -468,4 +478,5 @@ def get_outflow(itime):

for kk, vv in answers_regression_means.items():
abs_diff = abs(locals()[kk].mean() - vv)

assert abs_diff < 1e-5, f"results for {kk} are not close"
17 changes: 13 additions & 4 deletions autotest/test_obsin_flow_node.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import numpy as np
import pytest
from pyPRMS import Streamflow as PRMSStreamflowData
from pyPRMS import DataFile as PRMSStreamflowData

from pywatershed import PRMSChannel
from pywatershed.base.adapter import Adapter, AdapterNetcdf, adapter_factory
from pywatershed.base.control import Control
from pywatershed.base.flow_graph import FlowGraph
from pywatershed.base.parameters import Parameters
from pywatershed.constants import nan, zero
from pywatershed.hydrology.obsin_node import ObsInNodeMaker
from pywatershed.hydrology.obsin_flow_node import ObsInFlowNodeMaker
from pywatershed.hydrology.prms_channel_flow_graph import (
HruSegmentFlowAdapter,
PRMSChannelFlowNodeMaker,
Expand Down Expand Up @@ -68,7 +68,13 @@ def test_prms_channel_obsin_compare_prms(
)
control_parameters = PrmsParameters.load(control_param_file)
obsout_seg = control_parameters.parameters["obsout_segment"] - 1
sf_data = PRMSStreamflowData(simulation["dir"] / "sf_data").data
sf_data = PRMSStreamflowData(
simulation["dir"] / "sf_data"
).data_by_variable("runoff")
old_names = sf_data.columns.tolist()
new_names = [cc.split("_")[1] for cc in sf_data.columns.tolist()]
sf_data.rename(columns=dict(zip(old_names, new_names)), inplace=True)

poi_inds = obsout_seg[np.where(obsout_seg >= 0)].tolist()
npoi = len(poi_inds)
poi_ids = discretization_prms.parameters["poi_gage_id"][(poi_inds),]
Expand Down Expand Up @@ -119,13 +125,14 @@ def advance(self) -> None:
"prms_channel": PRMSChannelFlowNodeMaker(
discretization_prms, parameters_prms
),
"obsin": ObsInNodeMaker(obsin_params, obsin_data),
"obsin": ObsInFlowNodeMaker(obsin_params, obsin_data),
}
nnodes = parameters_prms.dims["nsegment"] + npoi
node_maker_name = ["prms_channel"] * nnodes
node_maker_name[-npoi:] = ["obsin"] * npoi
node_maker_index = np.arange(nnodes)
node_maker_index[-npoi:] = np.arange(npoi)
node_maker_id = np.arange(nnodes)
to_graph_index = np.zeros(nnodes, dtype=np.int64)
dis_params = discretization_prms.parameters
to_graph_index[0:-npoi] = dis_params["tosegment"] - 1
Expand Down Expand Up @@ -171,12 +178,14 @@ def advance(self) -> None:
data_vars={
"node_maker_name": node_maker_name,
"node_maker_index": node_maker_index,
"node_maker_id": node_maker_id,
"to_graph_index": to_graph_index,
},
metadata={
"nnodes": {"dims": ["nnodes"]},
"node_maker_name": {"dims": ["nnodes"]},
"node_maker_index": {"dims": ["nnodes"]},
"node_maker_id": {"dims": ["nnodes"]},
"to_graph_index": {"dims": ["nnodes"]},
},
validate=True,
Expand Down
14 changes: 10 additions & 4 deletions autotest/test_pass_through_flow_graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@
from pywatershed.base.model import Model
from pywatershed.base.parameters import Parameters
from pywatershed.constants import nan, zero
from pywatershed.hydrology.pass_through_node import PassThroughNodeMaker
from pywatershed.hydrology.pass_through_flow_node import (
PassThroughFlowNodeMaker,
)
from pywatershed.hydrology.prms_channel_flow_graph import (
HruSegmentFlowAdapter,
PRMSChannelFlowNodeMaker,
Expand Down Expand Up @@ -63,8 +65,10 @@ def parameters_flow_graph(parameters_prms, discretization_prms):
nnodes = parameters_prms.dims["nsegment"] + 1
node_maker_name = ["prms_channel"] * nnodes
node_maker_name[-1] = "pass_throughs"
node_maker_name = np.array(node_maker_name, dtype="U")
node_maker_index = np.arange(nnodes)
node_maker_index[-1] = 0
node_maker_id = np.arange(nnodes)
to_graph_index = np.zeros(nnodes, dtype=np.int64)
dis_params = discretization_prms.parameters
to_graph_index[0:-1] = dis_params["tosegment"] - 1
Expand All @@ -77,11 +81,11 @@ def parameters_flow_graph(parameters_prms, discretization_prms):
)
# have to map to the graph from an index found in prms_channel
wh_intervene_above_graph = np.where(
(np.array(node_maker_name) == "prms_channel")
(node_maker_name == "prms_channel")
& (node_maker_index == wh_intervene_above_nhm[0][0])
)
wh_intervene_below_graph = np.where(
(np.array(node_maker_name) == "prms_channel")
(node_maker_name == "prms_channel")
& np.isin(node_maker_index, wh_intervene_below_nhm)
)

Expand All @@ -98,12 +102,14 @@ def parameters_flow_graph(parameters_prms, discretization_prms):
data_vars={
"node_maker_name": node_maker_name,
"node_maker_index": node_maker_index,
"node_maker_id": node_maker_id,
"to_graph_index": to_graph_index,
},
metadata={
"node_coord": {"dims": ["nnodes"]},
"node_maker_name": {"dims": ["nnodes"]},
"node_maker_index": {"dims": ["nnodes"]},
"node_maker_id": {"dims": ["nnodes"]},
"to_graph_index": {"dims": ["nnodes"]},
},
validate=True,
Expand All @@ -117,7 +123,7 @@ def node_maker_dict(parameters_prms, discretization_prms):
"prms_channel": PRMSChannelFlowNodeMaker(
discretization_prms, parameters_prms
),
"pass_throughs": PassThroughNodeMaker(),
"pass_throughs": PassThroughFlowNodeMaker(),
}


Expand Down
Loading

0 comments on commit 50a45eb

Please sign in to comment.