Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue #344 part1 imod refactor primod update #346

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2,980 changes: 2,403 additions & 577 deletions pixi.lock

Large diffs are not rendered by default.

8 changes: 7 additions & 1 deletion pixi.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ build-imod-coupler = "rm -rf dist && pyinstaller imod_coupler/__main__.py --name
netCDF4 = "*"
loguru = "*"
numpy = "<2.0"
imod = "*"
pip = "*"
pydantic = "2.*"
pyinstaller = "*"
Expand All @@ -29,6 +28,11 @@ scipy = "*"
tomli = "*"
tomli-w = "*"
xmipy = "*"
filelock = "*"
geopandas = "*"
pandamesh = "*"
rioxarray = "*"
xugrid = ">=0.11.0"

#[pypi-dependencies]
#ribasim = {git = "https://github.com/Deltares/Ribasim.git/#subdirectory=python/ribasim"}
Expand All @@ -39,10 +43,12 @@ install-ribasim-python = "pip install git+https://github.com/Deltares/Ribasim.gi
install-ribasim-testmodels = "pip install git+https://github.com/Deltares/Ribasim.git/#subdirectory=python/ribasim_testmodels"
install-primod = "pip install --no-deps --editable pre-processing"
install-metaswap-testmodels = "svn checkout https://repos.deltares.nl/repos/DSCTestbench/trunk/cases/e150_metaswap/f00_common/c00_common/LHM2016_v01vrz .imod_collector/e150_metaswap"
install-imod = "pip install git+https://github.com/Deltares/imod-python.git@msw_refactoring_feature_branch"
install-imod-collector = "python scripts/download_imod_collector.py"
install-imod-collector-regression = "python scripts/download_imod_collector.py regression"
generate-env-file = "python scripts/generate_env_file.py"
install = { depends_on = [
"install-imod",
"install-minimal",
"install-ribasim-testmodels",
"install-primod",
Expand Down
2 changes: 2 additions & 0 deletions pre-processing/primod/driver_coupling/ribameta.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ def derive_mapping(
self.ribasim_basin_definition,
like=svat.isel(subunit=0, drop=True),
column="node_id",
fill=-1,
)
svat_basin_mapping = SvatBasinMapping(
name="msw_ponding",
Expand All @@ -81,6 +82,7 @@ def derive_mapping(
self.ribasim_user_demand_definition,
like=svat.isel(subunit=0, drop=True),
column="node_id",
fill=-1,
)
# sprinkling surface water for subsection of svats determined in 'sprinkling'
swspr_grid_data = copy.deepcopy(msw_model[grid_data_key])
Expand Down
1 change: 1 addition & 0 deletions pre-processing/primod/driver_coupling/ribamod.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ def write_exchanges(
basin_definition,
like=dis["idomain"].isel(layer=0, drop=True),
column="node_id",
fill=-1,
)

# Collect which Ribasim basins are coupled, so that we can set their
Expand Down
18 changes: 10 additions & 8 deletions pre-processing/primod/mapping/wel_svat_mapping.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import numpy as np
import pandas as pd
import xarray as xr
from imod import mf6
from imod.mf6.mf6_wel_adapter import Mf6Wel
from imod.msw.fixed_format import VariableMetaData
from numpy.typing import NDArray

Expand Down Expand Up @@ -38,9 +38,7 @@ class WellSvatMapping(MetaModMapping):
_with_subunit = ("wel_id", "svat", "layer")
_to_fill = ("free",)

def __init__(
self, svat: xr.DataArray, well: mf6.WellDisStructured, index: NDArray[Int]
):
def __init__(self, svat: xr.DataArray, well: Mf6Wel, index: NDArray[Int]):
super().__init__()
self.index = index
self.well = well
Expand All @@ -55,10 +53,14 @@ def _create_well_id(
"""
Get modflow indices, svats, and layer number for the wells
"""
well_cellid = self.well["cellid"]
if len(well_cellid.coords["dim_cellid"]) != 3:
raise TypeError("Coupling to unstructured grids is not supported.")

# Convert to Python's 0-based index
well_row = self.well["row"] - 1
well_column = self.well["column"] - 1
well_layer = self.well["layer"]
well_layer = well_cellid.sel(dim_cellid="layer").data
well_row = well_cellid.sel(dim_cellid="row").data - 1
well_column = well_cellid.sel(dim_cellid="column").data - 1

n_subunit = svat["subunit"].size

Expand All @@ -71,7 +73,7 @@ def _create_well_id(
layer = np.tile(well_layer, (n_subunit, 1))
layer_1d = layer[well_active]

well_id = self.well.dataset.coords["index"] + 1
well_id = well_cellid.coords["ncellid"] + 1
well_id_1d = np.tile(well_id, (n_subunit, 1))[well_active]

return (well_id_1d, well_svat_1d, layer_1d)
Expand Down
16 changes: 9 additions & 7 deletions tests/fixtures/common.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import numpy as np
import pandas as pd
import xarray as xr
from imod import mf6
from imod.mf6.mf6_wel_adapter import Mf6Wel, cellid_from_arrays__structured
from numpy import float64, int_
from numpy.typing import NDArray

Expand Down Expand Up @@ -34,7 +34,7 @@ def get_times() -> pd.DatetimeIndex:

def create_wells(
nrow: int, ncol: int, idomain: xr.DataArray, wel_layer: int | None = None
) -> mf6.WellDisStructured:
) -> Mf6Wel:
"""
Create wells, deactivate inactive cells. This function wouldn't be necessary
if iMOD Python had a package to specify wells based on grids.
Expand All @@ -59,15 +59,17 @@ def create_wells(

rate = np.zeros(ix_active.shape)
layer = np.full_like(ix_active, wel_layer)
index = np.arange(ncol * nrow)[~to_deactivate]

return mf6.WellDisStructured(
layer=layer, row=iy_active, column=ix_active, rate=rate
cellid = cellid_from_arrays__structured(
layer=layer, row=iy_active, column=ix_active
)
rate_da = xr.DataArray(rate, coords={"index": index}, dims=("index",))

return Mf6Wel(cellid=cellid, rate=rate_da)

def create_wells_max_layer(
nrow: int, ncol: int, idomain: xr.DataArray
) -> mf6.WellDisStructured:

def create_wells_max_layer(nrow: int, ncol: int, idomain: xr.DataArray) -> Mf6Wel:
"""
Create wells in deepest layer of MODFLOW 6 model
"""
Expand Down
3 changes: 2 additions & 1 deletion tests/fixtures/fixture_metaswap.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import pytest_cases
import xarray as xr
from imod import mf6, msw
from imod.mf6.mf6_wel_adapter import Mf6Wel
from numpy import nan

from .common import create_wells, get_times, grid_sizes
Expand All @@ -14,7 +15,7 @@ def metaswap_model(
times: list[pd.date_range],
area: xr.DataArray,
active: xr.DataArray,
well: mf6.WellDisStructured,
well: Mf6Wel,
dis: mf6.StructuredDiscretization,
unsaturated_database: str,
) -> msw.MetaSwapModel:
Expand Down
2 changes: 1 addition & 1 deletion tests/fixtures/fixture_ribametamod.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def make_msw_model(

idomain = gwf["GWF_1"]["dis"]["idomain"]
if "layer" in idomain.dims:
idomain_layer1 = idomain.sel(layer=1)
idomain_layer1 = idomain.sel(layer=1, drop=True)
if nsubunits is None:
nsubunits = xr.ones_like(idomain)

Expand Down
1 change: 1 addition & 0 deletions tests/test_imod_coupler/test_metamod.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ def test_metamod_regression(
subprocess.run(
[imod_coupler_exec_regression, tmp_path_reg / metamod_model._toml_name],
check=True,
capture_output=True,
)

# Read Modflow 6 output
Expand Down
44 changes: 19 additions & 25 deletions tests/test_primod/test_wel_svat_mapping.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

import numpy as np
import xarray as xr
from imod import mf6
from imod.mf6.mf6_wel_adapter import Mf6Wel, cellid_from_arrays__structured
from numpy.testing import assert_equal
from primod.mapping.wel_svat_mapping import WellSvatMapping

Expand Down Expand Up @@ -34,14 +34,12 @@ def test_simple_model(fixed_format_parser):
index = (svat != 0).to_numpy().ravel()

# Well
well_layer = [3, 2, 1]
well_row = [1, 2, 3]
well_column = [2, 2, 2]
well_rate = [-5.0] * 3
well = mf6.WellDisStructured(
layer=well_layer,
row=well_row,
column=well_column,
cellid = cellid_from_arrays__structured(
layer=[3, 2, 1], row=[1, 2, 3], column=[2, 2, 2]
)
well_rate = xr.DataArray([-5.0] * 3, coords={"index": [0, 1, 2]}, dims=("index",))
well = Mf6Wel(
cellid=cellid,
rate=well_rate,
)

Expand Down Expand Up @@ -83,14 +81,10 @@ def test_simple_model_1_subunit(fixed_format_parser):
index = (svat != 0).to_numpy().ravel()

# Well
well_layer = [3, 2]
well_row = [1, 3]
well_column = [2, 2]
well_rate = [-5.0] * 2
well = mf6.WellDisStructured(
layer=well_layer,
row=well_row,
column=well_column,
cellid = cellid_from_arrays__structured(layer=[3, 2], row=[1, 3], column=[2, 2])
well_rate = xr.DataArray([-5.0] * 2, coords={"index": [0, 1]}, dims=("index",))
well = Mf6Wel(
cellid=cellid,
rate=well_rate,
)

Expand Down Expand Up @@ -141,14 +135,14 @@ def test_simple_model_inactive(fixed_format_parser):
index = (svat != 0).to_numpy().ravel()

# Well
well_layer = [1, 3, 2, 1]
well_row = [1, 1, 2, 3]
well_column = [1, 2, 2, 2]
well_rate = [-5.0] * 4
well = mf6.WellDisStructured(
layer=well_layer,
row=well_row,
column=well_column,
cellid = cellid_from_arrays__structured(
layer=[1, 3, 2, 1], row=[1, 1, 2, 3], column=[1, 2, 2, 2]
)
well_rate = xr.DataArray(
[-5.0] * 4, coords={"index": [0, 1, 2, 3]}, dims=("index",)
)
well = Mf6Wel(
cellid=cellid,
rate=well_rate,
)

Expand Down