Skip to content

Commit 54940d4

Browse files
Issue #1799 Skip empty wells and throw warning (#1800)
Fixes #1799 # Description Fix edge case where imod.formats.prj.open_projectfile_data could not handle empty well ipfs, which can be generated by iMOD5. # Checklist <!--- Before requesting review, please go through this checklist: --> - [x] Links to correct issue - [x] Update changelog, if changes affect users - [x] PR title starts with ``Issue #nr``, e.g. ``Issue #737`` - [x] Unit tests were added - [ ] **If feature added**: Added/extended example - [ ] **If feature added**: Added feature to API documentation - [ ] **If pixi.lock was changed**: Ran `pixi run generate-sbom` and committed changes
1 parent 9a9f9db commit 54940d4

5 files changed

Lines changed: 100 additions & 1 deletion

File tree

docs/api/changelog.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ Fixed
5656
a layer in the model discretization, which would cause these cells to be
5757
dropped when distributing conductances later.
5858
- Fixed :func:`imod.prepare.spatial.polygonize` for polygons with holes.
59+
- :func:`imod.formats.prj.open_projectfile_data` now drops empty wells from the
60+
dataset, and logs a warning about it.
5961

6062
Changed
6163
~~~~~~~

imod/formats/prj/prj.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -915,6 +915,15 @@ def _read_package_ipf(
915915
# Ensure the columns are identifiable.
916916
path = Path(entry["path"])
917917
ipf_df, indexcol, ext = _try_read_with_func(imod.ipf._read_ipf, path)
918+
nrow = ipf_df.shape[0]
919+
if nrow == 0:
920+
log_message = f"IPF file {path} contains no data. Skipping."
921+
imod.logging.logger.log(
922+
loglevel=LogLevel.WARNING,
923+
message=log_message,
924+
additional_depth=0,
925+
)
926+
continue
918927
if indexcol == 0:
919928
# No associated files
920929
has_associated = False

imod/tests/conftest.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
)
3030
from .fixtures.imod5_well_data import (
3131
well_duplication_import_prj,
32+
well_empty_ipfs,
3233
well_mixed_ipfs,
3334
well_out_of_bounds_ipfs,
3435
well_regular_import_prj,

imod/tests/fixtures/imod5_well_data.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,36 @@ def out_of_bounds_timeseries_string():
188188
)
189189

190190

191+
def ipf_simple_empty():
192+
"""
193+
Empty ipf file with only the header and zero rows. iMOD5 can generate these
194+
files after clipping an existing database.
195+
"""
196+
ipf_simple_header_copy = "0" + ipf_simple_header[ipf_simple_header.find("\n") :]
197+
198+
return textwrap.dedent(
199+
f"""\
200+
{ipf_simple_header_copy}
201+
"""
202+
)
203+
204+
205+
def ipf_associated_empty():
206+
"""
207+
Empty associated ipf file with only the header and zero rows. iMOD5 can generate these
208+
files after clipping an existing database.
209+
"""
210+
ipf_associated_header_copy = (
211+
"0" + ipf_associated_header[ipf_associated_header.find("\n") :]
212+
)
213+
214+
return textwrap.dedent(
215+
f"""\
216+
{ipf_associated_header_copy}
217+
"""
218+
)
219+
220+
191221
def write_ipf_and_maybe_assoc_files(
192222
tmp_path,
193223
projectfile_str,
@@ -337,3 +367,14 @@ def well_out_of_bounds_ipfs():
337367
other_timeseries_well_str,
338368
tmp_path,
339369
)
370+
371+
372+
@pytest.fixture(scope="session")
373+
def well_empty_ipfs():
374+
tmp_path = imod.util.temporary_directory()
375+
os.makedirs(tmp_path)
376+
377+
ipf1_str = ipf_simple_empty()
378+
ipf_associated_str = ipf_associated_empty()
379+
380+
return write_ipf_mixed_files(ipf_associated_str, ipf1_str, "", "", tmp_path)

imod/tests/test_formats/test_prj_wel.py

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import sys
12
from datetime import datetime
23
from shutil import copyfile
34
from textwrap import dedent
@@ -13,7 +14,8 @@
1314
parametrize_with_cases,
1415
)
1516

16-
from imod.formats.prj import open_projectfile_data
17+
from imod.formats.prj import open_projectfile_data, read_projectfile
18+
from imod.logging import LoggerType, LogLevel, configure
1719
from imod.mf6 import LayeredWell, Well
1820

1921

@@ -946,3 +948,47 @@ def test_from_imod5_data_wells__wells_out_of_bounds(
946948
expected_last_rate = data[wellname]["dataframe"][0]["rate"].iloc[-2]
947949
actual_last_rate = well.dataset["rate"].isel(index=1, time=-1).item()
948950
assert actual_last_rate == expected_last_rate
951+
952+
953+
@pytest.mark.unittest_jit
954+
@parametrize("wel_case", argvalues=PRJ_ARGS)
955+
@parametrize("wel_cls", argvalues=[LayeredWell, Well])
956+
def test_from_imod5_data_wells__empty_wells(
957+
wel_cls: Union[LayeredWell, Well],
958+
wel_case,
959+
well_empty_ipfs,
960+
tmp_path,
961+
request,
962+
):
963+
# Arrange
964+
# Replace layer number to zero if non-layered well.
965+
if wel_cls == Well:
966+
wel_case = wel_case.replace("1,2, 001", "1,2, 000")
967+
# Write prj and copy ipfs to right folder.
968+
case_name = get_case_name(request)
969+
wel_file = tmp_path / f"{case_name}.prj"
970+
setup_test_files(wel_case, wel_file, well_empty_ipfs, tmp_path)
971+
972+
projectfile_contents = read_projectfile(wel_file)
973+
974+
# Act
975+
logfile_path = tmp_path / "logfile.txt"
976+
with open(logfile_path, "w") as sys.stdout:
977+
configure(
978+
LoggerType.LOGURU,
979+
log_level=LogLevel.WARNING,
980+
add_default_file_handler=False,
981+
add_default_stream_handler=True,
982+
)
983+
data, _ = open_projectfile_data(wel_file)
984+
985+
with open(logfile_path, "r") as f:
986+
log = f.read()
987+
988+
# Assert
989+
# Projectfile only contains empty wells, so expect empty data.
990+
assert len(data) == 0
991+
# Expect warning about empty wells.
992+
for ipf_contents in projectfile_contents["(wel)"]["ipf"]:
993+
ipf_path = ipf_contents["path"]
994+
assert f"IPF file {ipf_path} contains no data. Skipping." in log

0 commit comments

Comments
 (0)