Skip to content

Commit ed928bb

Browse files
mjrenomjreno
authored andcommitted
baseline twri example
1 parent 41e28a3 commit ed928bb

File tree

9 files changed

+61
-152
lines changed

9 files changed

+61
-152
lines changed

docs/examples/image/qs.png

-54 KB
Binary file not shown.

docs/examples/image/qsprj.png

-33 KB
Binary file not shown.

docs/examples/image/quickstart.png

-29.8 KB
Loading

docs/examples/qsplot.py

Lines changed: 0 additions & 111 deletions
This file was deleted.

docs/examples/quickstart.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
name = "quickstart"
1313
workspace = Path(__file__).parent / name
14+
workspace.mkdir(exist_ok=True)
1415
time = Time(perlen=[1.0], nstp=[1])
1516
grid = StructuredGrid(
1617
nlay=1,
@@ -65,5 +66,5 @@
6566
ax.grid(which="both", color="white")
6667
head.plot.imshow(ax=ax)
6768
head.plot.contour(ax=ax, levels=[0.2, 0.4, 0.6, 0.8], linewidths=3.0)
68-
budget.plot.quiver(x="x", y="y", u="npf-qx", v="npf-qy", ax=ax, color="white")
69+
# budget.plot.quiver(x="x", y="y", u="npf-qx", v="npf-qy", ax=ax, color="white")
6970
fig.savefig(workspace / ".." / "image" / "quickstart.png")

docs/examples/twri.py

Lines changed: 32 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
from pathlib import Path
66

77
import numpy as np
8-
import xarray as xr
98

109
import flopy4
1110

@@ -16,7 +15,7 @@
1615
nper = time.nper
1716

1817
# Grid
19-
nlay = 5
18+
nlay = 3
2019
nrow = 15
2120
ncol = 15
2221
shape = (nlay, nrow, ncol)
@@ -25,18 +24,19 @@
2524
delc = np.ones((nrow,)) * 5000.0
2625
idomain = np.ones(shape, dtype=int)
2726
top = np.ones((nrow, ncol), dtype=float) * 200.0
28-
bottom = np.stack([np.full((nrow, ncol), val) for val in [-150.0, -200.0, -300.0, -350.0, -450.0]])
27+
bottom = np.stack([np.full((nrow, ncol), val) for val in [-200.0, -300.0, -450.0]])
2928
grid = flopy4.mf6.utils.grid.StructuredGrid(
3029
nlay=nlay, nrow=nrow, ncol=ncol, top=top, botm=bottom, delr=delr, delc=delc, idomain=idomain
3130
)
3231
dims = {"nper": nper, **dict(grid.dataset.sizes)} # TODO: temporary
3332

3433
# Grid discretization
34+
# TODO: xorigin, yorigin
3535
dis = flopy4.mf6.gwf.Dis.from_grid(grid=grid)
3636

3737
# Constant head boundary on the left
3838
chd = flopy4.mf6.gwf.Chd(
39-
head={"*": {(k, i, 0): 0.0 for k in range(nlay) for i in range(nrow)}},
39+
head={"*": {(k, i, 0): 0.0 for k in range(nlay - 1) for i in range(nrow)}},
4040
print_input=True,
4141
print_flows=True,
4242
save_flows=True,
@@ -47,8 +47,8 @@
4747
elevation = [0.0, 0.0, 10.0, 20.0, 30.0, 50.0, 70.0, 90.0, 100.0]
4848
conductance = 1.0
4949
drn = flopy4.mf6.gwf.Drn(
50-
elev={"*": {(0, 7, j): elevation[j] for j in range(9)}},
51-
cond={"*": {(0, 7, j): conductance for j in range(9)}},
50+
elev={"*": {(0, 7, j + 1): elevation[j] for j in range(9)}},
51+
cond={"*": {(0, 7, j + 1): conductance for j in range(9)}},
5252
print_input=True,
5353
print_flows=True,
5454
save_flows=True,
@@ -59,15 +59,15 @@
5959
ic = flopy4.mf6.gwf.Ic(strt=0.0, dims=dims)
6060

6161
# Node properties
62-
icelltype = np.stack([np.full((nrow, ncol), val) for val in [1, 0, 0, 0, 0]])
63-
k = np.stack([np.full((nrow, ncol), val) for val in [1.0e-3, 1.0e-8, 1.0e-4, 5.0e-7, 2.0e-4]])
64-
k33 = np.stack([np.full((nrow, ncol), val) for val in [1.0e-3, 1.0e-8, 1.0e-4, 5.0e-7, 2.0e-4]])
62+
icelltype = np.stack([np.full((nrow, ncol), val) for val in [1, 0, 0]])
63+
k = np.stack([np.full((nrow, ncol), val) for val in [1.0e-3, 1.0e-4, 2.0e-4]])
64+
k33 = np.stack([np.full((nrow, ncol), val) for val in [2.0e-8, 2.0e-8, 2.0e-8]])
6565
npf = flopy4.mf6.gwf.Npf(
6666
# TODO: no need for reshaping once array structuring converter is done
6767
icelltype=icelltype.reshape((nodes,)),
6868
k=k.reshape((nodes,)),
6969
k33=k33.reshape((nodes,)),
70-
cvoptions=flopy4.mf6.gwf.Npf.CvOptions(variablecv=True, dewatered=True),
70+
cvoptions=flopy4.mf6.gwf.Npf.CvOptions(dewatered=True),
7171
perched=True,
7272
save_flows=True,
7373
dims=dims,
@@ -78,26 +78,34 @@
7878
storagecoefficient=False,
7979
ss=1.0e-5,
8080
sy=0.15,
81-
transient={"*": False},
81+
steady_state=[True, False, False],
8282
iconvert=0,
8383
dims=dims,
8484
)
8585

8686
# Uniform recharge on the top layer
87-
rch_rate = xr.full_like(grid.idomain.sel(k=1), 3.0e-8, dtype=float)
88-
rch = flopy4.mf6.gwf.Rch(recharge=rch_rate, dims=dims)
87+
rch_rate = np.stack(np.full((nlay, nrow, ncol), flopy4.mf6.constants.FILL_DNODATA))
88+
rate = np.repeat(np.expand_dims(rch_rate, axis=0), repeats=nper, axis=0)
89+
rate[0, 0, :] = 3.0e-8
90+
rch = flopy4.mf6.gwf.Rch(recharge=rate.reshape(nper, -1), dims=dims)
8991

9092
# Output control
9193
# TODO: show both ways to set up the Oc package, strings
9294
# and proper record types? and/or with perioddata param?
93-
oc = flopy4.mf6.gwf.Oc(save_head="all", save_budget="all", dims=dims)
95+
oc = flopy4.mf6.gwf.Oc(
96+
budget_file="gwf.bud",
97+
head_file="gwf.hds",
98+
save_head={0: "all"},
99+
save_budget={0: "all"},
100+
dims=dims,
101+
)
94102

95103
# Wells scattered throughout the model
96104
wel_q = -5.0
97105
wel_nodes = [
98-
[3, 4, 10, -5.0],
99-
[2, 3, 5, -5.0],
100-
[2, 5, 11, -5.0],
106+
[2, 4, 10, -5.0],
107+
[1, 3, 5, -5.0],
108+
[1, 5, 11, -5.0],
101109
[0, 8, 7, -5.0],
102110
[0, 8, 9, -5.0],
103111
[0, 8, 11, -5.0],
@@ -119,14 +127,14 @@
119127
# Flow model
120128
gwf = flopy4.mf6.gwf.Gwf(
121129
dis=grid,
122-
chd=chd,
123130
ic=ic,
124131
npf=npf,
125132
sto=sto,
126133
oc=oc,
127-
rch=rch,
128-
wel=wel,
129-
drn=drn,
134+
chd=[chd],
135+
rch=[rch],
136+
wel=[wel],
137+
drn=[drn],
130138
dims=dims,
131139
)
132140

@@ -143,6 +151,7 @@
143151
scaling_method=None,
144152
reordering_method=None,
145153
relaxation_factor=0.97,
154+
models=["gwf"],
146155
)
147156

148157
# TDIS
@@ -166,10 +175,9 @@
166175
sim.run() # assumes the ``mf6`` executable is available on your PATH.
167176

168177
# Load head results
169-
gwf_ws = Path(workspace) / gwf.name
170178
head = flopy4.mf6.utils.open_hds(
171-
gwf_ws / f"{gwf.name}.hds",
172-
gwf_ws / f"{dis.name}.dis.grb",
179+
workspace / f"{gwf.name}.hds",
180+
workspace / f"{gwf.name}.dis.grb",
173181
)
174182

175183
# Plot head results

flopy4/mf6/codec/writer/filters.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ def array2string(value: NDArray) -> str:
107107
format = (
108108
"%d"
109109
if np.issubdtype(value.dtype, np.integer)
110-
else "%f"
110+
else "%.9f"
111111
if np.issubdtype(value.dtype, np.floating)
112112
else "%s"
113113
)

flopy4/mf6/converter/unstructure.py

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -112,12 +112,18 @@ def oc_setting_data(rec):
112112
match value.dtype:
113113
case np.bool:
114114
# supports boolean dataarrays, e.g. STO steady_state and transient
115-
dat = {kper: "" for kper in range(value.sizes["nper"]) if value.values[kper]} # type: ignore
116-
data[name] = dat
115+
# e.g. steady_state to steady-state, why is't this the dfn name?
116+
fname = name.replace("_", "-") # type: ignore
117+
dat = {kper: "" for kper in range(value.sizes["nper"]) if value.values[kper]}
118+
data[fname] = dat
117119
case np.dtypes.StringDType():
118120
# supports string dataarrays, e.g. OC save_budget, save_head
119121
fname = name.replace("_", " ")
120-
dat = {kper: value.values[kper] for kper in range(value.sizes["nper"])}
122+
dat = {
123+
kper: value.values[kper]
124+
for kper in range(value.sizes["nper"])
125+
if value.values[kper].lower() in ["first", "last", "steps", "all"]
126+
}
121127
data[fname] = dat
122128
case object():
123129
# supports object dataararys, e.g. OC PrintSaveSetting
@@ -139,6 +145,8 @@ def oc_setting_data(rec):
139145

140146

141147
def unstructure_component(value: Component) -> dict[str, Any]:
148+
from flopy4.mf6.constants import FILL_DNODATA
149+
142150
blockspec = dict(sorted(value.dfn.blocks.items(), key=block_sort_key)) # type: ignore
143151
blocks: dict[str, dict[str, Any]] = {}
144152
xatspec = xattree.get_xatspec(type(value))
@@ -236,18 +244,21 @@ def unstructure_component(value: Component) -> dict[str, Any]:
236244

237245
# setup indexed period blocks, combine arrays into datasets
238246
for kper, block in period_blocks.items():
239-
blocks[f"period {kper + 1}"] = {}
247+
key = f"period {kper + 1}"
240248
for arr_name, val in block.items():
241-
match block[arr_name]:
242-
case str():
243-
# non data period parameters have their period
244-
# write key set in the _hack_period_non_numeric
245-
# routine
246-
blocks[f"period {kper + 1}"][arr_name] = val
247-
case xr.DataArray():
248-
blocks[f"period {kper + 1}"]["period"] = xr.Dataset(
249-
block, coords=block[arr_name].coords
250-
)
249+
if np.any(val != FILL_DNODATA):
250+
if key not in blocks:
251+
blocks[key] = {}
252+
match block[arr_name]:
253+
case str():
254+
# non data period parameters have their period
255+
# write key set in the _hack_period_non_numeric
256+
# routine
257+
blocks[f"period {kper + 1}"][arr_name] = val
258+
case xr.DataArray():
259+
blocks[f"period {kper + 1}"]["period"] = xr.Dataset(
260+
block, coords=block[arr_name].coords
261+
)
251262

252263
# combine "perioddata" block arrays (tdis, ats) into datasets
253264
# so they render as lists. temp hack TODO do this generically

test/test_mf6_codec.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ def test_dumps_sto():
7373
print("STO dump:")
7474
print(dumped)
7575
assert "BEGIN PERIOD 1\n TRANSIENT" in dumped
76-
assert "BEGIN PERIOD 2\n STEADY_STATE" in dumped
76+
assert "BEGIN PERIOD 2\n STEADY-STATE" in dumped
7777
assert "BEGIN PERIOD 3\n TRANSIENT" in dumped
7878
assert dumped
7979

0 commit comments

Comments
 (0)