Skip to content

Commit baf4300

Browse files
authored
fix(csub): fix a few memory issues in csub package (#1935)
* fix z-displacement issue with inactive cells when saving z-displacement data * initialize flag_string * add warning if saving delay bed convergence data and delay beds are not included in a simulation * add a simple csub test that covers the changes (inactive cells, z-displacement output, and csub convergence output w/no delay beds)
1 parent cea7af2 commit baf4300

File tree

4 files changed

+377
-68
lines changed

4 files changed

+377
-68
lines changed

autotest/test_gwf_csub_zdisp02.py

Lines changed: 280 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,280 @@
1+
import pathlib as pl
2+
3+
import flopy
4+
import numpy as np
5+
import pytest
6+
7+
from framework import TestFramework
8+
9+
cases = ["csub_zdisp02"]
10+
htol = [None for _ in range(len(cases))]
11+
dtol = 1e-3
12+
budtol = 1e-2
13+
14+
# static model data
15+
# temporal discretization
16+
nper = 31
17+
perlen = [1.0] + [365.2500000 for _ in range(nper - 1)]
18+
nstp = [1] + [6 for _ in range(nper - 1)]
19+
tsmult = [1.0] + [1.3 for _ in range(nper - 1)]
20+
tdis_rc = []
21+
for i in range(nper):
22+
tdis_rc.append((perlen[i], nstp[i], tsmult[i]))
23+
24+
# spatial discretization data
25+
nlay, nrow, ncol = 3, 6, 6
26+
shape3d = (nlay, nrow, ncol)
27+
size3d = nlay * nrow * ncol
28+
delr, delc = 1000.0, 1000.0
29+
top = 0.0
30+
botm = [-100, -150.0, -350.0]
31+
zthick = [top - botm[0], botm[0] - botm[1], botm[1] - botm[2]]
32+
strt = 0.0
33+
34+
# create idomain and ibound
35+
idomain = np.ones(shape3d, dtype=np.int32)
36+
idomain[0, :, :] = np.array(
37+
[
38+
[0, 0, 0, 1, 1, 1],
39+
[0, 0, 1, 1, 1, 1],
40+
[0, 1, 1, 1, 1, 1],
41+
[1, 1, 1, 1, 1, 0],
42+
[1, 1, 1, 1, 0, 0],
43+
[1, 1, 1, 0, 0, 0],
44+
]
45+
)
46+
idomain[1, :, :] = np.flip(idomain[0], axis=1)
47+
idomain[2] = idomain[0] * idomain[1]
48+
49+
# calculate hk
50+
hk1fact = 1.0 / 50.0
51+
hk1 = 0.5 * hk1fact
52+
hk = [20.0, hk1, 5.0]
53+
54+
# calculate vka
55+
vka = [1e6, 7.5e-5, 1e6]
56+
57+
# layer 1 is convertible
58+
laytyp = [1, 0, 0]
59+
60+
# solver options
61+
nouter, ninner = 500, 300
62+
hclose, rclose, relax = 1e-9, 1e-6, 1.0
63+
newtonoptions = "NEWTON"
64+
imsla = "BICGSTAB"
65+
66+
67+
# pumping well data
68+
spd_wel = [(2, 3, 2, -1400.0)]
69+
maxwel = len(spd_wel)
70+
71+
# storage and compaction data
72+
ss = [0.0, 0.0, 0.0]
73+
void = 0.82
74+
theta = void / (1.0 + void)
75+
76+
# static ibc and sub data
77+
sgm = 0.0
78+
sgs = 0.0
79+
omega = 1.0
80+
81+
# no delay bed data
82+
lnd = [0, 1, 2]
83+
hc = -7.0
84+
thicknd0 = [15.0, 50.0, 30.0]
85+
ccnd0 = [6e-4, 3e-4, 6e-4]
86+
crnd0 = [6e-6, 3e-6, 6e-6]
87+
sfv = []
88+
sfe = []
89+
for k in range(nlay):
90+
sfv.append(ccnd0[k] * thicknd0[k])
91+
sfe.append(crnd0[k] * thicknd0[k])
92+
93+
# no delay bed packagedata entries
94+
sub6 = []
95+
cdelays = "nodelay"
96+
ibcno = 0
97+
for kdx, k in enumerate(lnd):
98+
for i in range(nrow):
99+
for j in range(ncol):
100+
# skip inactive cells
101+
if idomain[k, i, j] == 0:
102+
continue
103+
tag = f"{k + 1:02d}_{i + 1:02d}_{j + 1:02d}"
104+
# create nodelay entry
105+
b = thicknd0[kdx]
106+
d = (
107+
ibcno,
108+
(k, i, j),
109+
cdelays,
110+
hc,
111+
b,
112+
1.0,
113+
ccnd0[kdx],
114+
crnd0[kdx],
115+
theta,
116+
999.0,
117+
-999.0,
118+
tag,
119+
)
120+
sub6.append(d)
121+
ibcno += 1
122+
123+
# create coarse-grained material storage
124+
ske_scaled = []
125+
for k in range(nlay):
126+
sst = (zthick[k] - thicknd0[k]) * ss[k] / zthick[k]
127+
ske_scaled.append(sst)
128+
129+
130+
def build_models(idx, test):
131+
name = cases[idx]
132+
133+
# build MODFLOW 6 files
134+
ws = test.workspace
135+
sim = flopy.mf6.MFSimulation(
136+
sim_name=name, version="mf6", exe_name="mf6", sim_ws=ws
137+
)
138+
139+
flopy.mf6.ModflowTdis(
140+
sim, time_units="DAYS", nper=nper, perioddata=tdis_rc
141+
)
142+
143+
flopy.mf6.ModflowIms(
144+
sim,
145+
print_option="SUMMARY",
146+
outer_dvclose=hclose,
147+
outer_maximum=nouter,
148+
under_relaxation="NONE",
149+
inner_maximum=ninner,
150+
inner_dvclose=hclose,
151+
rcloserecord=rclose,
152+
linear_acceleration=imsla,
153+
scaling_method="NONE",
154+
reordering_method="NONE",
155+
relaxation_factor=relax,
156+
)
157+
158+
# create gwf model
159+
gwf = flopy.mf6.ModflowGwf(
160+
sim, modelname=name, newtonoptions=newtonoptions, save_flows=True
161+
)
162+
163+
flopy.mf6.ModflowGwfdis(
164+
gwf,
165+
nlay=nlay,
166+
nrow=nrow,
167+
ncol=ncol,
168+
delr=delr,
169+
delc=delc,
170+
top=top,
171+
botm=botm,
172+
idomain=idomain,
173+
)
174+
175+
flopy.mf6.ModflowGwfic(gwf, strt=strt, filename=f"{name}.ic")
176+
177+
flopy.mf6.ModflowGwfnpf(
178+
gwf, save_flows=False, icelltype=laytyp, k=hk, k33=vka
179+
)
180+
181+
flopy.mf6.ModflowGwfsto(
182+
gwf,
183+
save_flows=False,
184+
iconvert=laytyp,
185+
ss=0,
186+
sy=0,
187+
storagecoefficient=None,
188+
steady_state={0: True},
189+
transient={1: True},
190+
)
191+
192+
copth = f"{name}.compaction.gridbin"
193+
zopth = f"{name}.zdisplacement.gridbin"
194+
cvgpth = f"{name}.csub.convergence.csv"
195+
flopy.mf6.ModflowGwfcsub(
196+
gwf,
197+
boundnames=True,
198+
head_based=True,
199+
update_material_properties=True,
200+
specified_initial_interbed_state=True,
201+
effective_stress_lag=False,
202+
save_flows=True,
203+
compaction_filerecord=copth,
204+
zdisplacement_filerecord=zopth,
205+
package_convergence_filerecord=cvgpth,
206+
ninterbeds=len(sub6),
207+
beta=0.0,
208+
cg_ske_cr=ss,
209+
packagedata=sub6,
210+
)
211+
212+
flopy.mf6.ModflowGwfwel(
213+
gwf,
214+
print_input=True,
215+
print_flows=True,
216+
maxbound=maxwel,
217+
stress_period_data={1: spd_wel},
218+
)
219+
220+
flopy.mf6.ModflowGwfoc(
221+
gwf,
222+
budget_filerecord=f"{name}.cbc",
223+
head_filerecord=f"{name}.hds",
224+
saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")],
225+
printrecord=[("HEAD", "LAST"), ("BUDGET", "ALL")],
226+
)
227+
228+
return sim, None
229+
230+
231+
def check_output(idx, test):
232+
with open(pl.Path(test.workspace) / "mfsim.lst", "r") as f:
233+
lines = f.readlines()
234+
tag = (
235+
"1. Package convergence data is requested but delay interbeds are not"
236+
)
237+
found = False
238+
for line in lines[::-1]:
239+
if tag in line:
240+
found = True
241+
break
242+
assert found, f"WARNING: '{tag}' not found in mfsim.lst"
243+
244+
sim = flopy.mf6.MFSimulation.load(sim_ws=test.workspace)
245+
gwf = sim.get_model()
246+
idomain = gwf.dis.idomain.array
247+
248+
times = gwf.csub.output.compaction().get_times()
249+
totim = times[-1]
250+
251+
compaction = gwf.csub.output.compaction().get_data(totim=totim)
252+
compaction[compaction == 1e30] = 0.0
253+
zdis_calc = np.zeros(compaction.shape, dtype=float)
254+
zdis_calc[2] = compaction[2]
255+
for k in (1, 0):
256+
zdis_calc[k] = zdis_calc[k + 1] + compaction[k]
257+
zdis_calc[idomain < 1] = 0.0
258+
259+
zpth = pl.Path(test.workspace) / "csub_zdisp02.zdisplacement.gridbin"
260+
zobj = flopy.utils.HeadFile(zpth, text="CSUB-ZDISPLACE")
261+
zdis = zobj.get_data(totim=totim)
262+
zdis[zdis == 1e30] = 0.0
263+
264+
assert np.allclose(
265+
zdis, zdis_calc
266+
), "Calculated z-displacement is not equal to simulated z-displacement"
267+
268+
269+
@pytest.mark.slow
270+
@pytest.mark.parametrize("idx, name", enumerate(cases))
271+
def test_mf6model(idx, name, function_tmpdir, targets):
272+
test = TestFramework(
273+
name=name,
274+
workspace=function_tmpdir,
275+
targets=targets,
276+
build=lambda t: build_models(idx, t),
277+
check=lambda t: check_output(idx, t),
278+
htol=htol[idx],
279+
)
280+
test.run()

doc/ReleaseNotes/develop.tex

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@
2929
\item The PRT model's cell face flows were improperly combined with boundary flows; for cell faces with active neighbors, the face flow replaced any boundary flows (likely a rare situation because IFLOWFACE is typically applied to faces on the boundary of the active domain). The face flow calculation has been corrected.
3030
\item A bad pointer reference has been fixed in the PRT model. Depending on the combination of platform and compiler used to build the program, this could result in crashes (e.g. divide by zero errors) or in silent failures to properly pass particles downward between vertically adjacent cells, leading to early termination. The latter could occur as a consequence of undefined behavior which prevented detection of situations when a particle should exit a cell through its bottom face.
3131
\item For a UZF setup with multiple UZF objects in a cell, the auxmultname option would cause the program to issue an unnecessary error. The program was corrected to remove the unnecessary error. The revised program was tested to ensure that the assignment of multiple UZF objects per cell works when it should and fails when the cumulative area of the UZF objects within a cell exceed the total area for the cell.
32+
\item An array out of bounds error for Z-displacement output in inactive cells has been fixed in the CSUB package. Depending on the combination of platform and compiler used to build the program, this could result in crashes.
33+
\item Initialize a few uninitialized variables in the CSUB package. Depending on the combination of platform and compiler used to build the program, this could result in different program behaviour.
34+
\item Add a warning if saving convergence data for the CSUB package when delay beds are not included in a simulation. Also modified the convergence output data so that it is clear that DVMAX and DSTORAGEMAX data and locations are not calculated in this case (by writing `-\,-' to the output file).
35+
3236
% \item xxx
3337
\end{itemize}
3438

doc/mf6io/mf6ivar/dfn/gwf-csub.dfn

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -413,7 +413,7 @@ reader urword
413413
tagged true
414414
optional false
415415
longname package_convergence keyword
416-
description keyword to specify that record corresponds to the package convergence comma spaced values file.
416+
description keyword to specify that record corresponds to the package convergence comma spaced values file. Package convergence data is for delay interbeds. A warning message will be issued if package convergence data is requested but delay interbeds are not included in the package.
417417

418418
block options
419419
name package_convergence_filename

0 commit comments

Comments
 (0)