Skip to content

Commit fe887bf

Browse files
mjrenomjreno
andauthored
feat(gwf): add ghbg package (#2247)
* add ghba package * add ghba dfn * cleanup unused variables * nodelist contains nodesuser nodes * add structured netcdf grid write support * add netcdf read and write support * rebuild makefiles * rebuild makefiles * store dynamic netcdf input as timeseries * add tests * mark gridded array input packages as dev feature * netcdf timeseries export array uses dis length units * review updates * add developmode marker to ghba tests * apply maxbound to nodelist * consolidate ghb package code * update makefile * rebuild makefiles * rebuild makefiles * restore makedefaults * add mesh global attribute * modflow_input attr should contain tag name --------- Co-authored-by: mjreno <mjreno@IGSAAA071L01144.gs.doi.net>
1 parent 2176305 commit fe887bf

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+4246
-1819
lines changed

autotest/test_gwf_disv_uzf.py

Lines changed: 46 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
import numpy as np
1515
import pytest
1616
from flopy.utils.gridutil import get_disv_kwargs
17-
from framework import TestFramework
17+
from framework import DNODATA, TestFramework
1818

1919
cases = ["disv_with_uzf"]
2020
nlay = 5
@@ -109,20 +109,21 @@
109109
uzf_spd.update({t: spd})
110110

111111

112-
# Work up the GHB boundary
112+
# Work up the GHB / GHBG boundary
113113
ghb_ids = [(ncol - 1) + i * ncol for i in range(nrow)]
114114
ghb_spd = []
115+
abhead = np.full((nlay, ncpl), DNODATA, dtype=float)
116+
acond = np.full((nlay, ncpl), DNODATA, dtype=float)
115117
cond = 1e4
116118
for k in np.arange(3, 5, 1):
117119
for i in ghb_ids:
118120
ghb_spd.append([(k, i), 14.0, cond])
121+
abhead[k, i] = 14.0
122+
acond[k, i] = cond
119123

120124

121-
def build_models(idx, test):
122-
name = cases[idx]
123-
125+
def get_model(ws, name, array_input=False):
124126
# build MODFLOW 6 files
125-
ws = test.workspace
126127
sim = flopy.mf6.MFSimulation(
127128
sim_name=name, version="mf6", exe_name="mf6", sim_ws=ws
128129
)
@@ -171,7 +172,12 @@ def build_models(idx, test):
171172
sto = flopy.mf6.ModflowGwfsto(gwf, iconvert=1, ss=1e-5, sy=0.2, transient=True)
172173

173174
# general-head boundary
174-
ghb = flopy.mf6.ModflowGwfghb(gwf, print_flows=True, stress_period_data=ghb_spd)
175+
if array_input:
176+
ghb = flopy.mf6.ModflowGwfghbg(
177+
gwf, print_flows=True, maxbound=20, bhead=abhead, cond=acond
178+
)
179+
else:
180+
ghb = flopy.mf6.ModflowGwfghb(gwf, print_flows=True, stress_period_data=ghb_spd)
175181

176182
# unsaturated-zone flow
177183
etobs = []
@@ -220,18 +226,18 @@ def build_models(idx, test):
220226
obs_dict = {f"{name}.obs.csv": obs_lst}
221227
obs = flopy.mf6.ModflowUtlobs(gwf, pname="head_obs", digits=20, continuous=obs_dict)
222228

223-
return sim, None
229+
return sim
224230

225231

226-
def check_output(idx, test):
232+
def check_output(ws, name):
227233
# Next, get the binary printed heads
228-
fpth = os.path.join(test.workspace, test.name + ".hds")
234+
fpth = os.path.join(ws, name + ".hds")
229235
hobj = flopy.utils.HeadFile(fpth, precision="double")
230236
hds = hobj.get_alldata()
231237
hds = hds.reshape((np.sum(nstp), 5, 10, 10))
232238

233239
# Get the MF6 cell-by-cell fluxes
234-
bpth = os.path.join(test.workspace, test.name + ".cbc")
240+
bpth = os.path.join(ws, name + ".cbc")
235241
bobj = flopy.utils.CellBudgetFile(bpth, precision="double")
236242
bobj.get_unique_record_names()
237243
# ' STO-SS'
@@ -249,7 +255,7 @@ def check_output(idx, test):
249255
gwet = gwetv.reshape((np.sum(nstp), 5, 10, 10))
250256

251257
# Also retrieve the binary UZET output
252-
uzpth = os.path.join(test.workspace, test.name + ".uzf.bud")
258+
uzpth = os.path.join(ws, name + ".uzf.bud")
253259
uzobj = flopy.utils.CellBudgetFile(uzpth, precision="double")
254260
uzobj.get_unique_record_names()
255261
# b' FLOW-JA-FACE',
@@ -353,14 +359,41 @@ def check_output(idx, test):
353359
print("Finished running checks")
354360

355361

362+
def build_models(idx, test):
363+
# build MODFLOW 6 files
364+
ws = test.workspace
365+
name = cases[idx]
366+
sim = get_model(ws, name)
367+
368+
# build comparison array_input model
369+
ws = os.path.join(test.workspace, "mf6")
370+
mc = get_model(ws, name, array_input=True)
371+
372+
return sim, mc
373+
374+
375+
def check_outputs(idx, test):
376+
name = cases[idx]
377+
378+
# check output MODFLOW 6 files
379+
ws = test.workspace
380+
check_output(ws, name)
381+
382+
# check output comparison array_input model
383+
ws = os.path.join(test.workspace, "mf6")
384+
check_output(ws, name)
385+
386+
356387
@pytest.mark.slow
388+
@pytest.mark.developmode
357389
@pytest.mark.parametrize("idx, name", enumerate(cases))
358390
def test_mf6model(idx, name, function_tmpdir, targets):
359391
test = TestFramework(
360392
name=name,
361393
workspace=function_tmpdir,
362394
targets=targets,
363395
build=lambda t: build_models(idx, t),
364-
check=lambda t: check_output(idx, t),
396+
check=lambda t: check_outputs(idx, t),
397+
compare="mf6",
365398
)
366399
test.run()

autotest/test_gwf_sfr_inactive02.py

Lines changed: 44 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,19 @@
11
# Test evap in SFR reaches (no interaction with gwf)
22

3+
import os
34

45
import flopy
56
import numpy as np
67
import pytest
7-
from framework import TestFramework
8+
from framework import DNODATA, TestFramework
89

910
HDRY, HNOFLO = -1e30, 1e30
1011

1112
cases = ["sfr-inactive02"]
1213

1314

14-
def build_models(idx, test):
15+
def get_model(ws, name, array_input=False):
1516
# Base simulation and model name and workspace
16-
ws = test.workspace
17-
name = cases[idx]
1817

1918
length_units = "m"
2019
time_units = "sec"
@@ -66,7 +65,15 @@ def build_models(idx, test):
6665
icelltype=1, # >0 means saturated thickness varies with computed head
6766
)
6867
flopy.mf6.ModflowGwfic(gwf, strt=1.0)
69-
flopy.mf6.ModflowGwfghb(gwf, stress_period_data=[((0, 0, 0), 1.0, 1e6)])
68+
if array_input:
69+
# if False:
70+
bhead = np.full(nlay * nrow * ncol, DNODATA, dtype=float)
71+
cond = np.full(nlay * nrow * ncol, DNODATA, dtype=float)
72+
bhead[0] = 1.0
73+
cond[0] = 1e6
74+
flopy.mf6.ModflowGwfghbg(gwf, maxbound=1, bhead=bhead, cond=cond)
75+
else:
76+
flopy.mf6.ModflowGwfghb(gwf, stress_period_data=[((0, 0, 0), 1.0, 1e6)])
7077

7178
# sfr data
7279
nreaches = 4
@@ -116,7 +123,7 @@ def build_models(idx, test):
116123
print_stage=True,
117124
print_flows=True,
118125
print_input=True,
119-
stage_filerecord=f"{name}.sfr.hds",
126+
stage_filerecord=f"{name}.sfr.stg",
120127
budget_filerecord=f"{name}.sfr.cbc",
121128
length_conversion=1.0,
122129
time_conversion=1.0,
@@ -150,11 +157,11 @@ def build_models(idx, test):
150157
saverecord=[("head", "all"), ("budget", "all")],
151158
)
152159

153-
return sim, None
160+
return sim
154161

155162

156-
def check_output(idx, test):
157-
sim = flopy.mf6.MFSimulation.load(sim_ws=test.workspace)
163+
def check_output(ws, name):
164+
sim = flopy.mf6.MFSimulation.load(sim_ws=ws)
158165
gwf = sim.get_model()
159166
sfr = gwf.get_package("SFR-1")
160167
stage = sfr.output.stage().get_alldata().squeeze()
@@ -214,13 +221,40 @@ def check_output(idx, test):
214221
)
215222

216223

224+
def build_models(idx, test):
225+
# build MODFLOW 6 files
226+
ws = test.workspace
227+
name = cases[idx]
228+
sim = get_model(ws, name)
229+
230+
# build comparison array_input model
231+
ws = os.path.join(test.workspace, "mf6")
232+
mc = get_model(ws, name, array_input=True)
233+
234+
return sim, mc
235+
236+
237+
def check_outputs(idx, test):
238+
name = cases[idx]
239+
240+
# check output MODFLOW 6 files
241+
ws = test.workspace
242+
check_output(ws, name)
243+
244+
# check output comparison array_input model
245+
ws = os.path.join(test.workspace, "mf6")
246+
check_output(ws, name)
247+
248+
249+
@pytest.mark.developmode
217250
@pytest.mark.parametrize("idx, name", enumerate(cases))
218251
def test_mf6model(idx, name, function_tmpdir, targets):
219252
test = TestFramework(
220253
name=name,
221254
workspace=function_tmpdir,
222255
targets=targets,
223256
build=lambda t: build_models(idx, t),
224-
check=lambda t: check_output(idx, t),
257+
check=lambda t: check_outputs(idx, t),
258+
compare="mf6",
225259
)
226260
test.run()

autotest/test_gwf_uzf01.py

Lines changed: 65 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,15 @@
88
import flopy
99
import numpy as np
1010
import pytest
11-
from framework import TestFramework
11+
from framework import DNODATA, TestFramework
1212

1313
cases = ["gwf_uzf01a"]
1414
nlay, nrow, ncol = 100, 1, 1
1515

1616
crs = "EPSG:26916"
1717

1818

19-
def build_models(idx, test):
20-
name = cases[idx]
21-
19+
def get_model(ws, name, array_input=False):
2220
perlen = [500.0]
2321
nper = len(perlen)
2422
nstp = [10]
@@ -39,7 +37,6 @@ def build_models(idx, test):
3937
tdis_rc.append((perlen[i], nstp[i], tsmult[i]))
4038

4139
# build MODFLOW 6 files
42-
ws = test.workspace
4340
sim = flopy.mf6.MFSimulation(
4441
sim_name=name, version="mf6", exe_name="mf6", sim_ws=ws
4542
)
@@ -104,16 +101,40 @@ def build_models(idx, test):
104101
transient={0: True},
105102
)
106103

107-
# ghb
108-
ghbspdict = {
109-
0: [[(nlay - 1, 0, 0), 1.5, 1.0]],
110-
}
111-
ghb = flopy.mf6.ModflowGwfghb(
112-
gwf,
104+
# ghb / ghbg
105+
if array_input:
106+
ghb_obs = {f"{name}.ghb.obs.csv": [("100_1_1", "GHB", (99, 0, 0))]}
107+
bhead = np.full(nlay * nrow * ncol, DNODATA, dtype=float)
108+
cond = np.full(nlay * nrow * ncol, DNODATA, dtype=float)
109+
bhead[nlay - 1] = 1.5
110+
cond[nlay - 1] = 1.0
111+
ghb = flopy.mf6.ModflowGwfghbg(
112+
gwf,
113+
print_input=True,
114+
print_flows=True,
115+
maxbound=1,
116+
bhead=bhead,
117+
cond=cond,
118+
save_flows=False,
119+
)
120+
else:
121+
ghb_obs = {f"{name}.ghb.obs.csv": [("100_1_1", "GHB", (99, 0, 0))]}
122+
ghbspdict = {
123+
0: [[(nlay - 1, 0, 0), 1.5, 1.0]],
124+
}
125+
ghb = flopy.mf6.ModflowGwfghb(
126+
gwf,
127+
print_input=True,
128+
print_flows=True,
129+
stress_period_data=ghbspdict,
130+
save_flows=False,
131+
)
132+
133+
ghb.obs.initialize(
134+
filename=f"{name}.ghb.obs",
135+
digits=20,
113136
print_input=True,
114-
print_flows=True,
115-
stress_period_data=ghbspdict,
116-
save_flows=False,
137+
continuous=ghb_obs,
117138
)
118139

119140
# note: for specifying lake number, use fortran indexing!
@@ -174,13 +195,10 @@ def build_models(idx, test):
174195
obs_dict = {f"{name}.obs.csv": obs_lst}
175196
obs = flopy.mf6.ModflowUtlobs(gwf, pname="head_obs", digits=20, continuous=obs_dict)
176197

177-
return sim, None
198+
return sim
178199

179200

180-
def check_output(idx, test):
181-
name = test.name
182-
ws = test.workspace
183-
201+
def check_output(ws, name):
184202
# check binary grid file
185203
fname = os.path.join(ws, name + ".dis.grb")
186204
grbobj = flopy.mf6.utils.MfGrdFile(fname)
@@ -228,13 +246,40 @@ def check_output(idx, test):
228246
)
229247

230248

249+
def build_models(idx, test):
250+
# build MODFLOW 6 files
251+
ws = test.workspace
252+
name = cases[idx]
253+
sim = get_model(ws, name)
254+
255+
# build comparison array_input model
256+
ws = os.path.join(test.workspace, "mf6")
257+
mc = get_model(ws, name, array_input=True)
258+
259+
return sim, mc
260+
261+
262+
def check_outputs(idx, test):
263+
name = cases[idx]
264+
265+
# check output MODFLOW 6 files
266+
ws = test.workspace
267+
check_output(ws, name)
268+
269+
# check output comparison array_input model
270+
ws = os.path.join(test.workspace, "mf6")
271+
check_output(ws, name)
272+
273+
274+
@pytest.mark.developmode
231275
@pytest.mark.parametrize("idx, name", enumerate(cases))
232276
def test_mf6model(idx, name, function_tmpdir, targets):
233277
test = TestFramework(
234278
name=name,
235279
workspace=function_tmpdir,
236280
build=lambda t: build_models(idx, t),
237-
check=lambda t: check_output(idx, t),
281+
check=lambda t: check_outputs(idx, t),
238282
targets=targets,
283+
compare="mf6",
239284
)
240285
test.run()

0 commit comments

Comments
 (0)