Skip to content
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 changes: 2 additions & 0 deletions docs/api/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ Fixed
a layer in the model discretization, which would cause these cells to be
dropped when distributing conductances later.
- Fixed :func:`imod.prepare.spatial.polygonize` for polygons with holes.
- :func:`imod.formats.prj.open_projectfile_data` now drops empty wells from the
dataset, and logs a warning about it.

Changed
~~~~~~~
Expand Down
9 changes: 9 additions & 0 deletions imod/formats/prj/prj.py
Original file line number Diff line number Diff line change
Expand Up @@ -915,6 +915,15 @@ def _read_package_ipf(
# Ensure the columns are identifiable.
path = Path(entry["path"])
ipf_df, indexcol, ext = _try_read_with_func(imod.ipf._read_ipf, path)
nrow = ipf_df.shape[0]
if nrow == 0:
log_message = f"IPF file {path} contains no data. Skipping."
imod.logging.logger.log(
loglevel=LogLevel.WARNING,
message=log_message,
additional_depth=0,
)
continue
if indexcol == 0:
# No associated files
has_associated = False
Expand Down
1 change: 1 addition & 0 deletions imod/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
)
from .fixtures.imod5_well_data import (
well_duplication_import_prj,
well_empty_ipfs,
well_mixed_ipfs,
well_out_of_bounds_ipfs,
well_regular_import_prj,
Expand Down
41 changes: 41 additions & 0 deletions imod/tests/fixtures/imod5_well_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,36 @@ def out_of_bounds_timeseries_string():
)


def ipf_simple_empty():
"""
Empty ipf file with only the header and zero rows. iMOD5 can generate these
files after clipping an existing database.
"""
ipf_simple_header_copy = "0" + ipf_simple_header[ipf_simple_header.find("\n") :]

return textwrap.dedent(
f"""\
{ipf_simple_header_copy}
"""
)


def ipf_associated_empty():
"""
Empty associated ipf file with only the header and zero rows. iMOD5 can generate these
files after clipping an existing database.
"""
ipf_associated_header_copy = (
"0" + ipf_associated_header[ipf_associated_header.find("\n") :]
)

return textwrap.dedent(
f"""\
{ipf_associated_header_copy}
"""
)


def write_ipf_and_maybe_assoc_files(
tmp_path,
projectfile_str,
Expand Down Expand Up @@ -337,3 +367,14 @@ def well_out_of_bounds_ipfs():
other_timeseries_well_str,
tmp_path,
)


@pytest.fixture(scope="session")
def well_empty_ipfs():
tmp_path = imod.util.temporary_directory()
os.makedirs(tmp_path)

ipf1_str = ipf_simple_empty()
ipf_associated_str = ipf_associated_empty()

return write_ipf_mixed_files(ipf_associated_str, ipf1_str, "", "", tmp_path)
48 changes: 47 additions & 1 deletion imod/tests/test_formats/test_prj_wel.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import sys
from datetime import datetime
from shutil import copyfile
from textwrap import dedent
Expand All @@ -13,7 +14,8 @@
parametrize_with_cases,
)

from imod.formats.prj import open_projectfile_data
from imod.formats.prj import open_projectfile_data, read_projectfile
from imod.logging import LoggerType, LogLevel, configure
from imod.mf6 import LayeredWell, Well


Expand Down Expand Up @@ -946,3 +948,47 @@ def test_from_imod5_data_wells__wells_out_of_bounds(
expected_last_rate = data[wellname]["dataframe"][0]["rate"].iloc[-2]
actual_last_rate = well.dataset["rate"].isel(index=1, time=-1).item()
assert actual_last_rate == expected_last_rate


@pytest.mark.unittest_jit
@parametrize("wel_case", argvalues=PRJ_ARGS)
@parametrize("wel_cls", argvalues=[LayeredWell, Well])
def test_from_imod5_data_wells__empty_wells(
wel_cls: Union[LayeredWell, Well],
wel_case,
well_empty_ipfs,
tmp_path,
request,
):
# Arrange
# Replace layer number to zero if non-layered well.
if wel_cls == Well:
wel_case = wel_case.replace("1,2, 001", "1,2, 000")
# Write prj and copy ipfs to right folder.
case_name = get_case_name(request)
wel_file = tmp_path / f"{case_name}.prj"
setup_test_files(wel_case, wel_file, well_empty_ipfs, tmp_path)

projectfile_contents = read_projectfile(wel_file)

# Act
logfile_path = tmp_path / "logfile.txt"
with open(logfile_path, "w") as sys.stdout:
configure(
LoggerType.LOGURU,
log_level=LogLevel.WARNING,
add_default_file_handler=False,
add_default_stream_handler=True,
)
data, _ = open_projectfile_data(wel_file)

with open(logfile_path, "r") as f:
log = f.read()

# Assert
# Projectfile only contains empty wells, so expect empty data.
assert len(data) == 0
# Expect warning about empty wells.
for ipf_contents in projectfile_contents["(wel)"]["ipf"]:
ipf_path = ipf_contents["path"]
assert f"IPF file {ipf_path} contains no data. Skipping." in log
Loading