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 #1122 review comments #1128

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
a07e8e5
Start moving some logic to an abstract base class
JoerivanEngelen Jul 25, 2024
4e0b8c6
Make methods semi-private
JoerivanEngelen Jul 26, 2024
75fcde6
Move more methods to abstract well class
JoerivanEngelen Jul 26, 2024
58512fc
Format code a bit to avoid long line format string
JoerivanEngelen Jul 26, 2024
f037f58
First version of finished LayeredWell
JoerivanEngelen Jul 26, 2024
a188d48
Refactor code into separate cases and add layered well cases and tests.
JoerivanEngelen Jul 26, 2024
aec7051
Better naming for method
JoerivanEngelen Jul 26, 2024
cb1ff38
Update changelog
JoerivanEngelen Jul 26, 2024
52c6c14
Fix example in docstring
JoerivanEngelen Jul 26, 2024
a66f540
format
JoerivanEngelen Jul 26, 2024
b42fcd6
Move grouping logic to prepare well rates to separate helper function.
JoerivanEngelen Jul 26, 2024
846faaa
If layer not 0, make LayeredWell
JoerivanEngelen Jul 26, 2024
46309f1
format
JoerivanEngelen Jul 26, 2024
88158f7
Better variable naming
JoerivanEngelen Jul 29, 2024
efd930c
isinstance GridAgnosticWell instead of Well
JoerivanEngelen Jul 29, 2024
e40f91e
Add layer to dataframe
JoerivanEngelen Jul 29, 2024
58286ab
Parametrize test with LayeredWell case as well.
JoerivanEngelen Jul 29, 2024
b5b261c
Add test to verify the right classes are instantiated.
JoerivanEngelen Jul 29, 2024
30bd4ea
Test if subclass explicitly
JoerivanEngelen Jul 29, 2024
88f934c
Remove code reduncancy where index was retrieved from other df.
JoerivanEngelen Jul 29, 2024
d5ff265
Specify return type
JoerivanEngelen Jul 29, 2024
42c85d7
Add return types
JoerivanEngelen Jul 29, 2024
77f6a24
Expand log message with info that imod.mf6.LayeredWell should be used.
JoerivanEngelen Jul 29, 2024
16b4798
Add LayeredWell class to package sanity
JoerivanEngelen Jul 29, 2024
5477bef
Update docstring, scalars not supported in docstring.
JoerivanEngelen Jul 29, 2024
d924408
Merge branch 'imod5_converter_feature_branch' into issue_#1122_Layere…
JoerivanEngelen Jul 29, 2024
fb112bf
Merge branch 'imod5_converter_feature_branch' into issue_#1122_Layere…
JoerivanEngelen Jul 29, 2024
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
4 changes: 2 additions & 2 deletions imod/mf6/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ def write(
mf6_hfb_ls: List[HorizontalFlowBarrierBase] = []
for pkg_name, pkg in self.items():
try:
if isinstance(pkg, GridAgnosticWell):
if issubclass(type(pkg), GridAgnosticWell):
top, bottom, idomain = self.__get_domain_geometry()
k = self.__get_k()
mf6_well_pkg = pkg.to_mf6_pkg(
Expand All @@ -284,7 +284,7 @@ def write(
globaltimes=globaltimes,
write_context=pkg_write_context,
)
elif isinstance(pkg, imod.mf6.HorizontalFlowBarrierBase):
elif issubclass(type(pkg), imod.mf6.HorizontalFlowBarrierBase):
mf6_hfb_ls.append(pkg)
else:
pkg.write(
Expand Down
58 changes: 32 additions & 26 deletions imod/mf6/wel.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,9 @@ def y(self) -> npt.NDArray[np.float64]:
def is_grid_agnostic_package(cls) -> bool:
return True

def _create_cellid(self, wells_assigned: pd.DataFrame, active: xr.DataArray):
def _create_cellid(
self, wells_assigned: pd.DataFrame, active: xr.DataArray
) -> GridDataArray:
like = ones_like(active)

# Groupby index and select first, to unset any duplicate records
Expand All @@ -123,7 +125,7 @@ def _create_cellid(self, wells_assigned: pd.DataFrame, active: xr.DataArray):
return self._derive_cellid_from_points(like, **d_for_cellid)

def _create_dataset_vars(
self, wells_assigned: pd.DataFrame, wells_df: pd.DataFrame, cellid: xr.DataArray
self, wells_assigned: pd.DataFrame, cellid: xr.DataArray
) -> xr.Dataset:
"""
Create dataset with all variables (rate, concentration), with a similar shape as the cellids.
Expand All @@ -136,7 +138,7 @@ def _create_dataset_vars(
# "rate" variable in conversion from multi-indexed DataFrame to xarray
# DataArray results in duplicated values for "rate" along dimension
# "species". Select first species to reduce this again.
index_names = wells_df.index.names
index_names = wells_assigned.index.names
if "species" in index_names:
ds_vars["rate"] = ds_vars["rate"].isel(species=0)

Expand Down Expand Up @@ -321,7 +323,7 @@ def to_mf6_pkg(
ds = xr.Dataset()
ds["cellid"] = self._create_cellid(wells_assigned, active)

ds_vars = self._create_dataset_vars(wells_assigned, wells_df, ds["cellid"])
ds_vars = self._create_dataset_vars(wells_assigned, ds["cellid"])
ds = ds.assign(**ds_vars.data_vars)

ds = remove_inactive(ds, active)
Expand All @@ -340,7 +342,7 @@ def to_mf6_pkg(

return Mf6Wel(**ds.data_vars)

def to_mf6_package_information(self, filtered_wells):
def to_mf6_package_information(self, filtered_wells: pd.DataFrame) -> str:
message = textwrap.dedent(
"""Some wells were not placed in the MF6 well package. This
can be due to inactive cells or permeability/thickness constraints.\n"""
Expand All @@ -357,7 +359,7 @@ def to_mf6_package_information(self, filtered_wells):
message += f" id = {ids} x = {x} y = {y} \n"
return message

def _create_wells_df(self):
def _create_wells_df(self) -> pd.DataFrame:
raise NotImplementedError("Method in abstract base class called")

def _assign_wells_to_layers(
Expand All @@ -367,7 +369,7 @@ def _assign_wells_to_layers(
top: GridDataArray,
bottom: GridDataArray,
k: GridDataArray,
):
) -> pd.DataFrame:
raise NotImplementedError("Method in abstract base class called")


Expand All @@ -382,15 +384,15 @@ class Well(GridAgnosticWell):
Parameters
----------

y: float or list of floats or np.array of floats
y: list of floats or np.array of floats
is the y location of the well.
x: float or list of floats or np.array of floats
x: list of floats or np.array of floats
is the x location of the well.
screen_top: float or list of floats or np.array of floats
screen_top: list of floats or np.array of floats
is the top of the well screen.
screen_bottom: float or list of floats or np.array of floats
screen_bottom: list of floats or np.array of floats
is the bottom of the well screen.
rate: float, list of floats or xr.DataArray
rate: list of floats or xr.DataArray
is the volumetric well rate. A positive value indicates well
(injection) and a negative value indicates discharge (extraction) (q).
If provided as DataArray, an ``"index"`` dimension is required and an
Expand Down Expand Up @@ -661,7 +663,7 @@ def _assign_wells_to_layers(
top: GridDataArray,
bottom: GridDataArray,
k: GridDataArray,
):
) -> pd.DataFrame:
# Ensure top, bottom & k
# are broadcasted to 3d grid
like = ones_like(active)
Expand Down Expand Up @@ -701,10 +703,11 @@ def from_imod5_data(
if "layer" in pkg_data.keys() and (pkg_data["layer"] != 0):
log_msg = textwrap.dedent(
f"""
In well {key} a layer was assigned, but this is not
supported. Assignment will be done based on filter_top and
filter_bottom, and the chosen layer ({pkg_data["layer"]})
will be ignored."""
In well {key} a layer was assigned, but this is not supported.
Assignment will be done based on filter_top and filter_bottom,
and the chosen layer ({pkg_data["layer"]}) will be ignored. To
specify by layer, use imod.mf6.LayeredWell.
"""
)
logger.log(loglevel=LogLevel.WARNING, message=log_msg, additional_depth=2)

Expand All @@ -713,8 +716,10 @@ def from_imod5_data(
if "filt_top" not in df.columns or "filt_bot" not in df.columns:
log_msg = textwrap.dedent(
f"""
In well {key} the filt_top and filt_bot columns were not both found;
this is not supported for import."""
In well {key} the filt_top and filt_bot columns were not both
found; this is not supported for import. To specify by layer,
use imod.mf6.LayeredWell.
"""
)
logger.log(loglevel=LogLevel.ERROR, message=log_msg, additional_depth=2)
raise ValueError(log_msg)
Expand Down Expand Up @@ -742,20 +747,21 @@ class LayeredWell(GridAgnosticWell):
"""
Agnostic WEL package, which accepts x, y and layers.

This package can be written to any provided model grid.
Any number of WEL Packages can be specified for a single groundwater flow model.
This package can be written to any provided model grid, given that it has
enough layers. Any number of WEL Packages can be specified for a single
groundwater flow model.
https://water.usgs.gov/water-resources/software/MODFLOW-6/mf6io_6.0.4.pdf#page=63

Parameters
----------

y: float or list of floats or np.array of floats
y: list of floats or np.array of floats
is the y location of the well.
x: float or list of floats or np.array of floats
x: list of floats or np.array of floats
is the x location of the well.
layer: int or list of ints or np.array of ints
layer: list of ints or np.array of ints
is the layer of the well.
rate: float, list of floats or xr.DataArray
rate: list of floats or xr.DataArray
is the volumetric well rate. A positive value indicates well
(injection) and a negative value indicates discharge (extraction) (q).
If provided as DataArray, an ``"index"`` dimension is required and an
Expand Down Expand Up @@ -960,7 +966,7 @@ def _assign_wells_to_layers(
top: GridDataArray,
bottom: GridDataArray,
k: GridDataArray,
):
) -> pd.DataFrame:
return wells_df

@classmethod
Expand Down
1 change: 1 addition & 0 deletions imod/tests/test_mf6/test_package_sanity.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
imod.mf6.HorizontalFlowBarrierHydraulicCharacteristic,
imod.mf6.HorizontalFlowBarrierMultiplier,
imod.mf6.HorizontalFlowBarrierResistance,
imod.mf6.LayeredWell,
]


Expand Down