Skip to content

Commit

Permalink
refactor(datafile): ignore "text" parameter, add attributes from file
Browse files Browse the repository at this point in the history
  • Loading branch information
mwtoews committed Jun 14, 2024
1 parent e2a85a3 commit 2f1d78e
Show file tree
Hide file tree
Showing 7 changed files with 142 additions and 55 deletions.
82 changes: 81 additions & 1 deletion autotest/test_binaryfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
See also test_cellbudgetfile.py for similar tests.
"""

import warnings
from itertools import repeat

import numpy as np
Expand Down Expand Up @@ -104,6 +105,8 @@ def test_headfile_build_index(example_data_path):
assert hds.ncol == 20
assert hds.nlay == 3
assert not hasattr(hds, "nper")
assert hds.text == "head"
assert hds.text_bytes == b"HEAD".rjust(16)
assert hds.totalbytes == 10_676_004
assert len(hds.recordarray) == 3291
assert type(hds.recordarray) == np.ndarray
Expand Down Expand Up @@ -150,7 +153,80 @@ def test_headfile_build_index(example_data_path):
)


def test_concentration_build_index(example_data_path):
@pytest.mark.parametrize(
"pth, expected",
[
pytest.param(
"mf6-freyberg/freyberg.hds",
{
"precision": "double",
"nlay, nrow, ncol": (1, 40, 20),
"text": "head",
"text_bytes": b"HEAD".ljust(16),
"len(obj)": 1,
},
id="freyberg.hds",
),
pytest.param(
"mf6/create_tests/test_transport/expected_output/gwt_mst03.ucn",
{
"precision": "double",
"nlay, nrow, ncol": (1, 1, 1),
"text": "concentration",
"text_bytes": b"CONCENTRATION".ljust(16),
"len(obj)": 28,
},
id="gwt_mst03.ucn",
),
pytest.param(
"mfusg_test/03A_conduit_unconfined/output/ex3A.cln.hds",
{
"precision": "single",
"nlay, nrow, ncol": (1, 1, 2),
"text": "cln_heads",
"text_bytes": b"CLN HEADS".rjust(16),
"len(obj)": 1,
},
id="ex3A.cln.hds",
),
pytest.param(
"mfusg_test/03A_conduit_unconfined/output/ex3A.ddn",
{
"precision": "single",
"nlay, nrow, ncol": (2, 100, 100),
"text": "drawdown",
"text_bytes": b"DRAWDOWN".rjust(16),
"len(obj)": 2,
},
id="ex3A.ddn",
),
],
)
def test_headfile_examples(example_data_path, pth, expected):
with HeadFile(example_data_path / pth) as obj:
assert obj.precision == expected["precision"]
assert (obj.nlay, obj.nrow, obj.ncol) == expected["nlay, nrow, ncol"]
assert obj.text == expected["text"]
assert obj.text_bytes == expected["text_bytes"]
assert len(obj) == expected["len(obj)"]


@pytest.mark.parametrize(
"pth",
[
"mt3d_test/mf96mt3d/P01/case1b/MT3D001.UCN",
"unstructured/headu.githds",
],
)
def test_not_headfile(example_data_path, pth):
# These examples pass get_headfile_precision, but are not HeadFiles
with pytest.raises(ValueError, match="cannot read file with HeadFile"):
with warnings.catch_warnings():
warnings.simplefilter("ignore")
HeadFile(example_data_path / pth)


def test_ucnfile_build_index(example_data_path):
# test low-level BinaryLayerFile._build_index() method with UCN file
pth = example_data_path / "mt3d_test/mf2005mt3d/P07/MT3D001.UCN"
with UcnFile(pth) as ucn:
Expand All @@ -159,6 +235,8 @@ def test_concentration_build_index(example_data_path):
assert ucn.ncol == 21
assert ucn.nlay == 8
assert not hasattr(ucn, "nper")
assert ucn.text == "concentration"
assert ucn.text_bytes == b"CONCENTRATION".ljust(16)
assert ucn.totalbytes == 10_432
assert len(ucn.recordarray) == 8
assert type(ucn.recordarray) == np.ndarray
Expand Down Expand Up @@ -296,6 +374,8 @@ def test_headu_file_data(function_tmpdir, example_data_path):
headobj = HeadUFile(fname)
assert isinstance(headobj, HeadUFile)
assert headobj.nlay == 3
assert headobj.text == "headu"
assert headobj.text_bytes == b"HEADU".rjust(16)

# ensure recordarray is has correct data
ra = headobj.recordarray
Expand Down
1 change: 1 addition & 0 deletions autotest/test_formattedfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ def test_headfile_build_index(example_data_path):
assert hds.ncol == 10
assert hds.nlay == 1
assert not hasattr(hds, "nper")
assert hds.text == "head"
assert hds.totalbytes == 1613
assert len(hds.recordarray) == 1
assert type(hds.recordarray) == np.ndarray
Expand Down
12 changes: 6 additions & 6 deletions flopy/export/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ def _add_output_nc_variable(
else:
a = out_obj.get_data(totim=t)
except Exception as e:
nme = var_name + text.decode().strip().lower()
nme = var_name + text
estr = f"error getting data for {nme} at time {t}:{e!s}"
if logger:
logger.warn(estr)
Expand All @@ -191,7 +191,7 @@ def _add_output_nc_variable(
try:
array[i, :, :, :] = a.astype(np.float32)
except Exception as e:
nme = var_name + text.decode().strip().lower()
nme = var_name + text
estr = f"error assigning {nme} data to array for time {t}:{e!s}"
if logger:
logger.warn(estr)
Expand All @@ -209,7 +209,7 @@ def _add_output_nc_variable(

if isinstance(nc, dict):
if text:
var_name = text.decode().strip().lower()
var_name = text
nc[var_name] = array
return nc

Expand All @@ -219,7 +219,7 @@ def _add_output_nc_variable(
precision_str = "f4"

if text:
var_name = text.decode().strip().lower()
var_name = text
attribs = {"long_name": var_name}
attribs["coordinates"] = "time layer latitude longitude"
attribs["min"] = mn
Expand Down Expand Up @@ -434,7 +434,7 @@ def output_helper(
times,
shape3d,
out_obj,
"concentration",
out_obj.text,
logger=logger,
mask_vals=mask_vals,
mask_array3d=mask_array3d,
Expand All @@ -446,7 +446,7 @@ def output_helper(
times,
shape3d,
out_obj,
out_obj.text.decode(),
out_obj.text,
logger=logger,
mask_vals=mask_vals,
mask_array3d=mask_array3d,
Expand Down
4 changes: 1 addition & 3 deletions flopy/export/vtk.py
Original file line number Diff line number Diff line change
Expand Up @@ -1228,14 +1228,12 @@ def add_heads(self, hds, kstpkper=None, masked_values=None):
kstpkpers = hds.get_kstpkper()
self._totim = {ki: time for (ki, time) in zip(kstpkpers, times)}

text = hds.text.decode()

d = dict()
for ki in kstpkper:
d[ki] = hds.get_data(ki)

self.__transient_output_data = False
self.add_transient_array(d, name=text, masked_values=masked_values)
self.add_transient_array(d, name=hds.text, masked_values=masked_values)
self.__transient_output_data = True

def add_cell_budget(
Expand Down
6 changes: 2 additions & 4 deletions flopy/mf6/utils/binaryfile_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ def _get_binary_file_object(self, path, bintype, key):

elif bintype == "DDN":
try:
return bf.HeadFile(path, text="drawdown", precision="double")
return bf.HeadFile(path, precision="double")
except AssertionError:
raise AssertionError(f"{self.dataDict[key]} does not exist")

Expand Down Expand Up @@ -333,9 +333,7 @@ def _setbinarykeys(self, binarypathdict):

elif key[1] == "DDN":
try:
readddn = bf.HeadFile(
path, text="drawdown", precision="double"
)
readddn = bf.HeadFile(path, precision="double")
self.dataDict[(key[0], key[1], "DRAWDOWN")] = path
readddn.close()

Expand Down
83 changes: 44 additions & 39 deletions flopy/utils/binaryfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,10 @@ def _build_index(self):
header = self._get_header()
self.nrow = header["nrow"]
self.ncol = header["ncol"]
self.text_bytes = header["text"]
self.text = (
self.text_bytes.decode("ascii").strip().lower().replace(" ", "_")
)
if header["ilay"] > self.nlay:
self.nlay = header["ilay"]

Expand All @@ -488,8 +492,12 @@ def _build_index(self):
while ipos < self.totalbytes:
header = self._get_header()
self.recordarray.append(header)
if self.text.upper() not in header["text"]:
continue
if header["text"] != self.text_bytes:
warnings.warn(
"inconsistent text headers changing from "
f"{self.text_bytes!r} to {header['text']!r}",
UserWarning,
)
if ipos == 0:
self.times.append(header["totim"])
self.kstpkper.append((header["kstp"], header["kper"]))
Expand All @@ -501,6 +509,8 @@ def _build_index(self):
ipos = self.file.tell()
self.iposarray.append(ipos)
databytes = self.get_databytes(header)
if ipos + databytes > self.totalbytes:
raise EOFError(f"attempting to seek {ipos + databytes}")
self.file.seek(databytes, 1)
ipos = self.file.tell()

Expand Down Expand Up @@ -617,14 +627,13 @@ class HeadFile(BinaryLayerFile):
----------
filename : str or PathLike
Path of the head file.
text : string
Name of the text string in the head file. Default is 'head'.
precision : string
Precision of floating point head data in the value. Accepted
values are 'auto', 'single' or 'double'. Default is 'auto',
which enables automatic detection of precision.
verbose : bool
Toggle logging output. Default is False.
text : str
Ignored.
precision : {'auto', 'single', 'double'}
Precision of floating point head data in the value. Default
'auto' enables automatic detection of precision.
verbose : bool, default False
Toggle logging output.
Examples
--------
Expand All @@ -634,7 +643,7 @@ class HeadFile(BinaryLayerFile):
>>> hdobj.list_records()
>>> rec = hdobj.get_data(kstpkper=(0, 49))
>>> ddnobj = bf.HeadFile('model.ddn', text='drawdown', precision='single')
>>> ddnobj = bf.HeadFile('model.ddn', precision='single')
>>> ddnobj.list_records()
>>> rec = ddnobj.get_data(totim=100.)
Expand All @@ -643,12 +652,11 @@ class HeadFile(BinaryLayerFile):
def __init__(
self,
filename: Union[str, os.PathLike],
text="head",
text="head", # noqa ARG002
precision="auto",
verbose=False,
**kwargs,
):
self.text = text.encode()
if precision == "auto":
precision = get_headfile_precision(filename)
if precision == "unknown":
Expand Down Expand Up @@ -749,14 +757,15 @@ class UcnFile(BinaryLayerFile):
Parameters
----------
filename : string
Name of the concentration file
text : string
Name of the text string in the ucn file. Default is 'CONCENTRATION'
precision : string
'auto', 'single' or 'double'. Default is 'auto'.
verbose : bool
Write information to the screen. Default is False.
filename : str or PathLike
Path of the concentration file.
text : str
Ignored.
precision : {'auto', 'single', 'double'}
Precision of floating point values. Default 'auto' enables automatic
detection of precision.
verbose : bool, default False
Write information to the screen.
Attributes
----------
Expand Down Expand Up @@ -792,12 +801,11 @@ class UcnFile(BinaryLayerFile):
def __init__(
self,
filename,
text="concentration",
text="concentration", # noqa ARG002
precision="auto",
verbose=False,
**kwargs,
):
self.text = text.encode()
if precision == "auto":
precision = get_headfile_precision(filename)
if precision == "unknown":
Expand All @@ -821,14 +829,13 @@ class HeadUFile(BinaryLayerFile):
----------
filename : str or PathLike
Path of the head file
text : string
Name of the text string in the head file. Default is 'headu'.
precision : string
Precision of the floating point head data in the file. Accepted
values are 'auto', 'single' or 'double'. Default is 'auto', which
enables precision to be automatically detected.
verbose : bool
Toggle logging output. Default is False.
text : str
Ignored.
precision : {'auto', 'single', 'double'}
Precision of floating point values. Default 'auto' enables automatic
detection of precision.
verbose : bool, default False
Toggle logging output.
Notes
-----
Expand Down Expand Up @@ -859,15 +866,14 @@ class HeadUFile(BinaryLayerFile):
def __init__(
self,
filename: Union[str, os.PathLike],
text="headu",
text="headu", # noqa ARG002
precision="auto",
verbose=False,
**kwargs,
):
"""
Class constructor
"""
self.text = text.encode()
if precision == "auto":
precision = get_headfile_precision(filename)
if precision == "unknown":
Expand Down Expand Up @@ -990,11 +996,11 @@ class CellBudgetFile:
----------
filename : str or PathLike
Path of the cell budget file.
precision : string
Precision of floating point budget data in the file. Accepted
values are 'single' or 'double'. Default is 'single'.
verbose : bool
Toggle logging output. Default is False.
precision : {'auto', 'single', 'double'}
Precision of floating point values. Default 'auto' enables automatic
detection of precision.
verbose : bool, default False
Toggle logging output.
Examples
--------
Expand Down Expand Up @@ -2217,7 +2223,6 @@ def reverse(self, filename: Optional[os.PathLike] = None):
Parameters
----------
filename : str or PathLike, optional
Path of the new reversed binary cell budget file to create.
"""
Expand Down
Loading

0 comments on commit 2f1d78e

Please sign in to comment.