Skip to content

Commit 94cd19d

Browse files
authored
refactor(utils): move utils from modflow-devtools (#1621)
* add head and budget file writing util fns * add disu creation helper fn * add uniform flow field fn * add head/budget/concentration comparison utility fns * add namefile-reading utility fn * add minimal tests for relocated utils
1 parent 96fc3ad commit 94cd19d

File tree

8 files changed

+2537
-2
lines changed

8 files changed

+2537
-2
lines changed

autotest/test_binaryfile.py

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,12 @@
1515
HeadUFile,
1616
Util2d,
1717
)
18-
from flopy.utils.binaryfile import get_headfile_precision
18+
from flopy.utils.binaryfile import (
19+
get_headfile_precision,
20+
write_budget,
21+
write_head,
22+
)
23+
from flopy.utils.gridutil import uniform_flow_field
1924

2025

2126
@pytest.fixture
@@ -241,3 +246,40 @@ def test_budgetfile_detect_precision_single(path):
241246
def test_budgetfile_detect_precision_double(path):
242247
file = CellBudgetFile(path, precision="auto")
243248
assert file.realtype == np.float64
249+
250+
251+
def test_write_head(function_tmpdir):
252+
file_path = function_tmpdir / "headfile"
253+
head_data = np.random.random((10, 10))
254+
255+
write_head(file_path, head_data)
256+
257+
assert file_path.is_file()
258+
content = np.fromfile(file_path)
259+
assert np.array_equal(head_data.ravel(), content)
260+
261+
# TODO: what else needs to be checked here?
262+
263+
264+
def test_write_budget(function_tmpdir):
265+
file_path = function_tmpdir / "budgetfile"
266+
267+
nlay = 3
268+
nrow = 3
269+
ncol = 3
270+
qx = 1.0
271+
qy = 0.0
272+
qz = 0.0
273+
shape = (nlay, nrow, ncol)
274+
spdis, flowja = uniform_flow_field(qx, qy, qz, shape)
275+
276+
write_budget(file_path, flowja, kstp=0)
277+
assert file_path.is_file()
278+
content1 = np.fromfile(file_path)
279+
280+
write_budget(file_path, flowja, kstp=1, kper=1, text="text")
281+
assert file_path.is_file()
282+
content2 = np.fromfile(file_path)
283+
284+
# TODO: why are these the same?
285+
assert np.array_equal(content1, content2)

autotest/test_compare.py

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import numpy as np
2+
import pytest
3+
4+
from flopy.mf6.utils import MfGrdFile
5+
from flopy.utils.compare import _diffmax, _difftol
6+
7+
8+
def test_diffmax():
9+
a1 = np.array([1, 2, 3])
10+
a2 = np.array([4, 5, 7])
11+
d, indices = _diffmax(a1, a2)
12+
indices = indices[
13+
0
14+
] # return value is a tuple of arrays (1 for each dimension)
15+
assert d == 4
16+
assert list(indices) == [2]
17+
18+
19+
def test_difftol():
20+
a1 = np.array([1, 2, 3])
21+
a2 = np.array([3, 5, 7])
22+
d, indices = _difftol(a1, a2, 2.5)
23+
indices = indices[
24+
0
25+
] # return value is a tuple of arrays (1 for each dimension)
26+
assert d == 4
27+
print(d, indices)
28+
assert list(indices) == [1, 2]
29+
30+
31+
@pytest.mark.skip(reason="todo")
32+
def test_eval_bud_diff(example_data_path):
33+
# get ia from grdfile
34+
mfgrd_test_path = example_data_path / "mfgrd_test"
35+
grb_path = mfgrd_test_path / "nwtp3.dis.grb"
36+
grb = MfGrdFile(str(grb_path), verbose=True)
37+
ia = grb._datadict["IA"] - 1
38+
39+
# TODO: create/run minimal model, then compare budget files
40+
41+
42+
@pytest.mark.skip(reason="todo")
43+
def test_compare_budget():
44+
pass
45+
46+
47+
@pytest.mark.skip(reason="todo")
48+
def test_compare_swrbudget():
49+
pass
50+
51+
52+
@pytest.mark.skip(reason="todo")
53+
def test_compare_heads():
54+
pass
55+
56+
57+
@pytest.mark.skip(reason="todo")
58+
def test_compare_concs():
59+
pass
60+
61+
62+
@pytest.mark.skip(reason="todo")
63+
def test_compare_stages():
64+
pass
65+
66+
67+
@pytest.mark.skip(reason="todo")
68+
def test_compare():
69+
pass

autotest/test_gridutil.py

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import numpy as np
44
import pytest
55

6-
from flopy.utils.gridutil import get_lni
6+
from flopy.utils.gridutil import get_disu_kwargs, get_lni, uniform_flow_field
77

88

99
@pytest.mark.parametrize(
@@ -54,3 +54,77 @@ def test_get_lni_infers_layer_count_when_int_ncpl(ncpl, nodes, expected):
5454
assert isinstance(lni, list)
5555
for i, ln in enumerate(lni):
5656
assert ln == expected[i]
57+
58+
59+
@pytest.mark.parametrize(
60+
"nlay, nrow, ncol, delr, delc, tp, botm",
61+
[
62+
(
63+
1,
64+
61,
65+
61,
66+
np.array(61 * [50]),
67+
np.array(61 * [50]),
68+
np.array([-10]),
69+
np.array([-30.0, -50.0]),
70+
),
71+
(
72+
2,
73+
61,
74+
61,
75+
np.array(61 * [50]),
76+
np.array(61 * [50]),
77+
np.array([-10]),
78+
np.array([-30.0, -50.0]),
79+
),
80+
],
81+
)
82+
def test_get_disu_kwargs(nlay, nrow, ncol, delr, delc, tp, botm):
83+
kwargs = get_disu_kwargs(
84+
nlay=nlay, nrow=nrow, ncol=ncol, delr=delr, delc=delc, tp=tp, botm=botm
85+
)
86+
87+
from pprint import pprint
88+
89+
pprint(kwargs["area"])
90+
91+
assert kwargs["nodes"] == nlay * nrow * ncol
92+
assert kwargs["nvert"] == None
93+
94+
area = np.array([dr * dc for (dr, dc) in product(delr, delc)], dtype=float)
95+
area = np.array(nlay * [area]).flatten()
96+
assert np.array_equal(kwargs["area"], area)
97+
98+
# TODO: test other properties
99+
# print(kwargs["iac"])
100+
# print(kwargs["ihc"])
101+
# print(kwargs["ja"])
102+
# print(kwargs["nja"])
103+
104+
105+
@pytest.mark.parametrize(
106+
"qx, qy, qz, nlay, nrow, ncol",
107+
[
108+
(1, 0, 0, 1, 1, 10),
109+
(0, 1, 0, 1, 1, 10),
110+
(0, 0, 1, 1, 1, 10),
111+
(1, 0, 0, 1, 10, 10),
112+
(1, 0, 0, 2, 10, 10),
113+
(1, 1, 0, 2, 10, 10),
114+
(1, 1, 1, 2, 10, 10),
115+
(2, 1, 1, 2, 10, 10),
116+
],
117+
)
118+
def test_uniform_flow_field(qx, qy, qz, nlay, nrow, ncol):
119+
shape = nlay, nrow, ncol
120+
spdis, flowja = uniform_flow_field(qx, qy, qz, shape)
121+
122+
assert spdis.shape == (nlay * nrow * ncol,)
123+
for i, t in enumerate(spdis.flatten()):
124+
assert t[0] == t[1] == i
125+
assert t[3] == qx
126+
assert t[4] == qy
127+
assert t[5] == qz
128+
129+
# TODO: check flowja
130+
# print(flowja.shape)

autotest/test_mfreadnam.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import pytest
2+
from autotest.conftest import get_example_data_path
3+
4+
from flopy.utils.mfreadnam import get_entries_from_namefile
5+
6+
_example_data_path = get_example_data_path()
7+
8+
9+
@pytest.mark.parametrize(
10+
"path",
11+
[
12+
_example_data_path / "mf6" / "test001a_Tharmonic" / "mfsim.nam",
13+
_example_data_path / "mf6" / "test001e_UZF_3lay" / "mfsim.nam",
14+
_example_data_path / "mf6-freyberg" / "mfsim.nam",
15+
],
16+
)
17+
def test_get_entries_from_namefile_mf6(path):
18+
package = "IMS6"
19+
entries = get_entries_from_namefile(path, ftype=package)
20+
assert len(entries) == 1
21+
22+
entry = entries[0]
23+
assert path.parent.name in entry[0]
24+
assert entry[1] == package
25+
26+
27+
@pytest.mark.skip(reason="only supports mf6 namefiles")
28+
@pytest.mark.parametrize(
29+
"path",
30+
[
31+
_example_data_path / "mf6-freyberg" / "freyberg.nam",
32+
],
33+
)
34+
def test_get_entries_from_namefile_mf2005(path):
35+
package = "IC6"
36+
entries = get_entries_from_namefile(path, ftype=package)
37+
assert len(entries) == 1
38+
39+
entry = entries[0]
40+
assert path.parent.name in entry[0]
41+
assert entry[1] == package

0 commit comments

Comments
 (0)