Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
66800d9
Boyscouting: Get rid of calls to .values
JoerivanEngelen Jul 8, 2026
0473920
Pass id on to Mf6Wel
JoerivanEngelen Jul 9, 2026
7040e13
Support IPF wells for LayeredWell.from_imod5_cap_data
JoerivanEngelen Jul 13, 2026
aa1ab08
Temp add scratch script to try out data reworking
JoerivanEngelen Jul 15, 2026
6405be4
Change order of merging to first merge tables, then to grid and deal …
JoerivanEngelen Jul 16, 2026
fe251dd
Make script work for both subunits
JoerivanEngelen Jul 16, 2026
42948e5
Prototype SprinklingPoints class
JoerivanEngelen Jul 22, 2026
87a5e02
Format
JoerivanEngelen Jul 22, 2026
f088ad2
Fix mypy errors
JoerivanEngelen Aug 12, 2026
eb8a9e2
Convert to set literal
JoerivanEngelen Aug 12, 2026
308b157
Clearer varname for inside_df
JoerivanEngelen Aug 12, 2026
99dba8f
Add comment
JoerivanEngelen Aug 12, 2026
157e91d
Add SprinklingPoints to msw namespace
JoerivanEngelen Aug 12, 2026
ab4815d
Put columns in right order
JoerivanEngelen Aug 12, 2026
e5af555
Start adding unittest
JoerivanEngelen Aug 12, 2026
01f4a5e
Start refactoring test_module: Separate cases from tests
JoerivanEngelen Aug 12, 2026
67058da
Refactor into test for one subunit
JoerivanEngelen Aug 13, 2026
cb7458a
Add SprinklingPoints to the public API
JoerivanEngelen Aug 13, 2026
a7b1d6d
Migrate from_imod5_ipf logic into designated function, update docstri…
JoerivanEngelen Aug 13, 2026
2326477
Format and fix mypy issues by adding some specific typeddicts
JoerivanEngelen Aug 13, 2026
709038c
Finalize renaming to "capacity_p", deal with extra edge case if svat_…
JoerivanEngelen Aug 13, 2026
900de95
Slightly better name
JoerivanEngelen Aug 13, 2026
ab665d2
Add test to write from_imod5_data
JoerivanEngelen Aug 13, 2026
b7fce78
Separate expected case data into separate dataclass
JoerivanEngelen Aug 17, 2026
4f39a69
Start adding unittest for SprinklingPoints with a bunch of test cases…
JoerivanEngelen Aug 17, 2026
4188560
Simplify case where the art grid has a mapping id in an inactive svat
JoerivanEngelen Aug 18, 2026
a5f01ac
Fix edge case that wasn't working and reduce code a lot
JoerivanEngelen Aug 18, 2026
06f40fc
Finish unittest cases and format
JoerivanEngelen Aug 18, 2026
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
6 changes: 6 additions & 0 deletions docs/api/msw.rst
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@ Grid packages
Sprinkling.from_imod5_data
Sprinkling.get_regrid_methods
Sprinkling.write
SprinklingPoints
SprinklingPoints.regrid_like
SprinklingPoints.clip_box
SprinklingPoints.from_imod5_data
SprinklingPoints.get_regrid_methods
SprinklingPoints.write

Initial conditions
==================
Expand Down
4 changes: 3 additions & 1 deletion imod/mf6/mf6_wel_adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ def __init__(
self,
cellid,
rate,
id,
concentration=None,
concentration_boundary_type="aux",
save_flows: Optional[bool] = None,
Expand All @@ -153,6 +154,7 @@ def __init__(
dict_dataset = {
"cellid": cellid,
"rate": rate,
"id": id,
"concentration": concentration,
"concentration_boundary_type": concentration_boundary_type,
"save_flows": save_flows,
Expand All @@ -169,7 +171,7 @@ def _ds_to_arrdict(self, ds):
arrdict: Dict[str, Any] = {}

arrdict["data_vars"] = [
var_name for var_name in ds.data_vars if var_name != "cellid"
var_name for var_name in ds.data_vars if var_name not in ("cellid", "id")
]

dsvar = {}
Expand Down
20 changes: 16 additions & 4 deletions imod/mf6/utilities/imod5_converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,16 @@ def fill_missing_layers(


def _well_from_imod5_cap_point_data(cap_data: GridDataDict) -> dict[str, np.ndarray]:
raise NotImplementedError(
"Assigning sprinkling wells with an IPF file is not supported, please specify them as IDF."
)
df_points = cap_data["artificial_recharge_layer"]
data = {}
# Order of columns is x, y, layer, the other columns are irrelevant here.
data["x"] = df_points.iloc[:, 0].to_numpy().astype(float)
data["y"] = df_points.iloc[:, 1].to_numpy().astype(float)
data["layer"] = df_points.iloc[:, 2].to_numpy().astype(int)
data["rate"] = np.zeros_like(data["x"], dtype=float)
data["id"] = df_points.index.to_numpy()

return data


def _well_from_imod5_cap_grid_data(cap_data: GridDataDict) -> dict[str, np.ndarray]:
Expand All @@ -85,7 +92,7 @@ def _well_from_imod5_cap_grid_data(cap_data: GridDataDict) -> dict[str, np.ndarr

def well_from_imod5_cap_data(
imod5_data: Imod5DataDict,
target_dis: IRegridPackage,
target_dis: Optional[IRegridPackage],
regridder_types: DataclassType,
regrid_cache: RegridderWeightsCache,
) -> dict[str, np.ndarray]:
Expand Down Expand Up @@ -121,6 +128,11 @@ def well_from_imod5_cap_data(
if has_ipf_well:
return _well_from_imod5_cap_point_data(cap_data)
else:
if target_dis is None:
raise ValueError(
"target_dis must be provided when converting iMOD5 cap data "
"from grids (IDF)"
)
cap_data_regridded = regrid_imod5_cap_data(
imod5_data, target_dis, regridder_types, regrid_cache
)["cap"]
Expand Down
37 changes: 24 additions & 13 deletions imod/mf6/wel.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,11 @@ def _assign_dims(arg: Any) -> tuple[Any, ...] | xr.DataArray:
if arg.dims[0] != "time":
arg = arg.transpose()
da = xr.DataArray(
data=arg.values, coords={"time": arg["time"]}, dims=["time", "index"]
data=arg.to_numpy(), coords={"time": arg["time"]}, dims=["time", "index"]
)
return da
elif is_da:
return "index", arg.values
return "index", arg.to_numpy()
else:
return "index", arg

Expand Down Expand Up @@ -347,11 +347,11 @@ class GridAgnosticWell(BoundaryCondition, IPointDataPackage, abc.ABC):

@property
def x(self) -> npt.NDArray[np.float64]:
return self.dataset["x"].values
return self.dataset["x"].to_numpy()

@property
def y(self) -> npt.NDArray[np.float64]:
return self.dataset["y"].values
return self.dataset["y"].to_numpy()

@classmethod
def _is_grid_agnostic_package(cls) -> bool:
Expand Down Expand Up @@ -394,7 +394,9 @@ def _create_dataset_vars(
# Carefully rename the dimension and set coordinates
d_rename = {"index": "ncellid"}
ds_vars = ds_vars.rename_dims(**d_rename).rename_vars(**d_rename)
ds_vars = ds_vars.assign_coords(**{"ncellid": cellid.coords["ncellid"].values})
ds_vars = ds_vars.assign_coords(
**{"ncellid": cellid.coords["ncellid"].to_numpy()}
)

return ds_vars

Expand Down Expand Up @@ -525,9 +527,9 @@ def _to_mf6_pkg(
ds = ds.assign(**data_vars_dict) # type: ignore[arg-type]

ds = remove_inactive(ds, idomain)
ds["save_flows"] = self["save_flows"].values[()]
ds["print_flows"] = self["print_flows"].values[()]
ds["print_input"] = self["print_input"].values[()]
ds["save_flows"] = enforce_scalar(self["save_flows"])
ds["print_flows"] = enforce_scalar(self["print_flows"])
ds["print_input"] = enforce_scalar(self["print_input"])

filtered_final_well_ids = self._gather_filtered_well_ids(ds, wells_df)
if len(filtered_final_well_ids) > 0:
Expand All @@ -537,8 +539,6 @@ def _to_mf6_pkg(
)
logger.log(loglevel=LogLevel.WARNING, message=message_end)

ds = ds.drop_vars("id")

data_vars_dict = {str(k): v for k, v in ds.data_vars.items()}
return Mf6Wel(**data_vars_dict) # type: ignore[arg-type]

Expand Down Expand Up @@ -1060,8 +1060,8 @@ def _find_well_value_at_layer(
if (value is not None) and is_spatial_grid(value):
value = imod.select.points_values(
value,
x=well_dataset["x"].values,
y=well_dataset["y"].values,
x=well_dataset["x"].to_numpy(),
y=well_dataset["y"].to_numpy(),
out_of_bounds="ignore",
)
in_bounds = np.full(well_dataset.sizes["index"], False)
Expand Down Expand Up @@ -1449,7 +1449,7 @@ def _validate_imod5_depth_information(
def from_imod5_cap_data(
cls,
imod5_data: Imod5DataDict,
target_dis: StructuredDiscretization,
target_dis: Optional[StructuredDiscretization] = None,
regridder_types: CapDataWellRegridMethod = CapDataWellRegridMethod(),
regrid_cache: RegridderWeightsCache = RegridderWeightsCache(),
):
Expand Down Expand Up @@ -1489,6 +1489,17 @@ def from_imod5_cap_data(
xarray datasets, under the key of the package type to which it
belongs, as returned by
:func:`imod.formats.prj.open_projectfile_data`.
target_dis: Optional[StructuredDiscretization]
The target discretization to which the data should be regridded.
Only necessary when "artificial_recharge_layer" is an IDF grid,
otherwise ignored.
regridder_types: CapDataWellRegridMethod
The regridder type to use for the regridding of the "artificial_recharge_layer"
and "artificial_recharge_capacity" grids. Only necessary when
"artificial_recharge_layer" is an IDF grid, otherwise ignored.
regrid_cache: RegridderWeightsCache
Cache for storing intermediate regridding results. Only necessary when
"artificial_recharge_layer" is an IDF grid, otherwise ignored.
"""
data = well_from_imod5_cap_data(
imod5_data, target_dis, regridder_types, regrid_cache
Expand Down
2 changes: 1 addition & 1 deletion imod/msw/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,5 @@
from imod.msw.output_control import TimeOutputControl, VariableOutputControl
from imod.msw.ponding import Ponding
from imod.msw.scaling_factors import ScalingFactors
from imod.msw.sprinkling import Sprinkling
from imod.msw.sprinkling import Sprinkling, SprinklingPoints
from imod.msw.vegetation import AnnualCropFactors
22 changes: 22 additions & 0 deletions imod/msw/regrid/regrid_schemes.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,28 @@ class SprinklingRegridMethod(DataclassType):
max_abstraction_surfacewater: RegridVarType = (RegridderType.OVERLAP, "mean")


@dataclass(config=_CONFIG)
class SprinklingPointsRegridMethod(DataclassType):
"""
Object containing regridder methods for the
:class:`imod.msw.Sprinkling` package. This can be provided to the
``regrid_like`` method to regrid with custom settings.

Parameters
----------
art_grid: tuple, default (RegridderType.OVERLAP, "mode")

Examples
--------
Regrid with custom settings:

>>> regrid_method = SprinklingPointsRegridMethod(art_grid=(RegridderType.OVERLAP,"min"))
>>> sprinking.regrid_like(target_grid, RegridderWeightsCache(), regrid_method)
"""

art_grid: RegridVarType = (RegridderType.OVERLAP, "mode")


@dataclass(config=_CONFIG)
class MeteoGridRegridMethod(DataclassType):
"""
Expand Down
Loading
Loading