Skip to content

Commit c22c238

Browse files
mjrenomjreno
authored andcommitted
mfpackage and mfmodel netcdf info
1 parent 278bc24 commit c22c238

File tree

6 files changed

+980
-3
lines changed

6 files changed

+980
-3
lines changed

.docs/Notebooks/netcdf01_tutorial.py

Lines changed: 344 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,344 @@
1+
import sys
2+
from pathlib import Path
3+
from pprint import pformat
4+
from tempfile import TemporaryDirectory
5+
6+
import numpy as np
7+
import xarray as xr
8+
9+
import flopy
10+
11+
print(sys.version)
12+
print(f"flopy version: {flopy.__version__}")
13+
14+
DNODATA = 3.0e30
15+
16+
17+
def create_sim(ws):
18+
name = "uzf01"
19+
perlen = [500.0]
20+
nper = len(perlen)
21+
nstp = [10]
22+
tsmult = nper * [1.0]
23+
crs = "EPSG:26916"
24+
nlay, nrow, ncol = 100, 1, 1
25+
delr = 1.0
26+
delc = 1.0
27+
delv = 1.0
28+
top = 100.0
29+
botm = [top - (k + 1) * delv for k in range(nlay)]
30+
strt = 0.5
31+
hk = 1.0
32+
laytyp = 1
33+
ss = 0.0
34+
sy = 0.1
35+
36+
tdis_rc = []
37+
for i in range(nper):
38+
tdis_rc.append((perlen[i], nstp[i], tsmult[i]))
39+
40+
# build MODFLOW 6 files
41+
sim = flopy.mf6.MFSimulation(
42+
sim_name=name, version="mf6", exe_name="mf6", sim_ws=ws
43+
)
44+
45+
# create tdis package
46+
tdis = flopy.mf6.ModflowTdis(sim, time_units="DAYS", nper=nper, perioddata=tdis_rc)
47+
48+
# create iterative model solution and register the gwf model with it
49+
nouter, ninner = 100, 10
50+
hclose, rclose, relax = 1.5e-6, 1e-6, 0.97
51+
imsgwf = flopy.mf6.ModflowIms(
52+
sim,
53+
print_option="SUMMARY",
54+
outer_dvclose=hclose,
55+
outer_maximum=nouter,
56+
under_relaxation="DBD",
57+
under_relaxation_theta=0.7,
58+
inner_maximum=ninner,
59+
inner_dvclose=hclose,
60+
rcloserecord=rclose,
61+
linear_acceleration="BICGSTAB",
62+
scaling_method="NONE",
63+
reordering_method="NONE",
64+
relaxation_factor=relax,
65+
)
66+
67+
# create gwf model
68+
newtonoptions = "NEWTON UNDER_RELAXATION"
69+
gwf = flopy.mf6.ModflowGwf(
70+
sim,
71+
modelname=name,
72+
newtonoptions=newtonoptions,
73+
save_flows=True,
74+
)
75+
76+
dis = flopy.mf6.ModflowGwfdis(
77+
gwf,
78+
crs=crs,
79+
nlay=nlay,
80+
nrow=nrow,
81+
ncol=ncol,
82+
delr=delr,
83+
delc=delc,
84+
top=top,
85+
botm=botm,
86+
idomain=np.ones((nlay, nrow, ncol), dtype=int),
87+
)
88+
89+
# initial conditions
90+
ic = flopy.mf6.ModflowGwfic(gwf, strt=strt)
91+
92+
# node property flow
93+
npf = flopy.mf6.ModflowGwfnpf(gwf, save_flows=False, icelltype=laytyp, k=hk)
94+
# storage
95+
sto = flopy.mf6.ModflowGwfsto(
96+
gwf,
97+
save_flows=False,
98+
iconvert=laytyp,
99+
ss=ss,
100+
sy=sy,
101+
steady_state={0: False},
102+
transient={0: True},
103+
)
104+
105+
# ghbg
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+
bhead=bhead,
116+
cond=cond,
117+
save_flows=False,
118+
)
119+
120+
ghb.obs.initialize(
121+
filename=f"{name}.ghb.obs",
122+
digits=20,
123+
print_input=True,
124+
continuous=ghb_obs,
125+
)
126+
127+
# note: for specifying lake number, use fortran indexing!
128+
uzf_obs = {
129+
f"{name}.uzf.obs.csv": [
130+
("wc 02", "water-content", 2, 0.5),
131+
("wc 50", "water-content", 50, 0.5),
132+
("wcbn 02", "water-content", "uzf 002", 0.5),
133+
("wcbn 50", "water-content", "UZF 050", 0.5),
134+
("rch 02", "uzf-gwrch", "uzf 002"),
135+
("rch 50", "uzf-gwrch", "uzf 050"),
136+
]
137+
}
138+
139+
sd = 0.1
140+
vks = hk
141+
thtr = 0.05
142+
thti = thtr
143+
thts = sy
144+
eps = 4
145+
uzf_pkdat = [[0, (0, 0, 0), 1, 1, sd, vks, thtr, thts, thti, eps, "uzf 001"]] + [
146+
[k, (k, 0, 0), 0, k + 1, sd, vks, thtr, thts, thti, eps, f"uzf {k + 1:03d}"]
147+
for k in range(1, nlay - 1)
148+
]
149+
uzf_pkdat[-1][3] = -1
150+
infiltration = 2.01
151+
uzf_spd = {0: [[0, infiltration, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]]}
152+
uzf = flopy.mf6.ModflowGwfuzf(
153+
gwf,
154+
print_input=True,
155+
print_flows=True,
156+
save_flows=True,
157+
boundnames=True,
158+
ntrailwaves=15,
159+
nwavesets=40,
160+
nuzfcells=len(uzf_pkdat),
161+
packagedata=uzf_pkdat,
162+
perioddata=uzf_spd,
163+
budget_filerecord=f"{name}.uzf.bud",
164+
budgetcsv_filerecord=f"{name}.uzf.bud.csv",
165+
observations=uzf_obs,
166+
filename=f"{name}.uzf",
167+
)
168+
169+
# output control
170+
oc = flopy.mf6.ModflowGwfoc(
171+
gwf,
172+
budget_filerecord=f"{name}.bud",
173+
head_filerecord=f"{name}.hds",
174+
headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")],
175+
saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")],
176+
printrecord=[("HEAD", "LAST"), ("BUDGET", "ALL")],
177+
)
178+
179+
obs_lst = []
180+
obs_lst.append(["obs1", "head", (0, 0, 0)])
181+
obs_lst.append(["obs2", "head", (1, 0, 0)])
182+
obs_dict = {f"{name}.obs.csv": obs_lst}
183+
obs = flopy.mf6.ModflowUtlobs(gwf, pname="head_obs", digits=20, continuous=obs_dict)
184+
185+
return sim
186+
187+
188+
def add_netcdf_vars(dataset, nc_info, dimmap):
189+
def _data_shape(shape):
190+
dims_l = []
191+
for d in shape:
192+
dims_l.append(dimmap[d])
193+
194+
return dims_l
195+
196+
for v in nc_info:
197+
varname = nc_info[v]["varname"]
198+
data = np.full(
199+
_data_shape(nc_info[v]["nc_shape"]),
200+
nc_info[v]["attrs"]["_FillValue"],
201+
dtype=nc_info[v]["nc_type"],
202+
)
203+
var_d = {varname: (nc_info[v]["nc_shape"], data)}
204+
dataset = dataset.assign(var_d)
205+
for a in nc_info[v]["attrs"]:
206+
dataset[varname].attrs[a] = nc_info[v]["attrs"][a]
207+
208+
return dataset
209+
210+
211+
temp_dir = TemporaryDirectory()
212+
workspace = Path(temp_dir.name)
213+
214+
# run the non-netcdf simulation
215+
sim = create_sim(ws=workspace)
216+
sim.write_simulation()
217+
success, buff = sim.run_simulation(silent=True, report=True)
218+
assert success, pformat(buff)
219+
220+
# create directory for netcdf sim
221+
sim.set_sim_path(workspace / "netcdf")
222+
gwf = sim.get_model("uzf01")
223+
gwf.name_file.nc_filerecord = "uzf01.structured.nc"
224+
sim.write_simulation()
225+
226+
# create the netcdf dataset
227+
ds = xr.Dataset()
228+
229+
# get model netcdf info
230+
nc_info = gwf.netcdf_info()
231+
232+
# update dataset with required attributes
233+
for a in nc_info["attrs"]:
234+
ds.attrs[a] = nc_info["attrs"][a]
235+
236+
# set dimensional info
237+
dis = gwf.modelgrid
238+
xoff = dis.xoffset
239+
yoff = dis.yoffset
240+
x = xoff + dis.xycenters[0]
241+
y = yoff + dis.xycenters[1]
242+
z = [float(x) for x in range(1, dis.nlay + 1)]
243+
nstp = sum(gwf.modeltime.nstp)
244+
time = gwf.modeltime.tslen
245+
nlay = dis.nlay
246+
nrow = dis.nrow
247+
ncol = dis.ncol
248+
dimmap = {"time": nstp, "z": nlay, "y": nrow, "x": ncol}
249+
250+
# create coordinate vars
251+
var_d = {"time": (["time"], time), "z": (["z"], z), "y": (["y"], y), "x": (["x"], x)}
252+
ds = ds.assign(var_d)
253+
254+
# dis
255+
dis = gwf.get_package("dis")
256+
nc_info = dis.netcdf_info()
257+
258+
# create dis dataset variables
259+
ds = add_netcdf_vars(ds, nc_info, dimmap)
260+
261+
# update data
262+
ds["dis_delr"].values = dis.delr.get_data()
263+
ds["dis_delc"].values = dis.delc.get_data()
264+
ds["dis_top"].values = dis.top.get_data()
265+
ds["dis_botm"].values = dis.botm.get_data()
266+
ds["dis_idomain"].values = dis.idomain.get_data()
267+
268+
# update dis to read from netcdf
269+
with open(workspace / "netcdf" / "uzf01.dis", "w") as f:
270+
f.write("BEGIN options\n")
271+
f.write(" crs EPSG:26916\n")
272+
f.write("END options\n\n")
273+
f.write("BEGIN dimensions\n")
274+
f.write(" NLAY 100\n")
275+
f.write(" NROW 1\n")
276+
f.write(" NCOL 1\n")
277+
f.write("END dimensions\n\n")
278+
f.write("BEGIN griddata\n")
279+
f.write(" delr NETCDF\n")
280+
f.write(" delc NETCDF\n")
281+
f.write(" top NETCDF\n")
282+
f.write(" botm NETCDF\n")
283+
f.write(" idomain NETCDF\n")
284+
f.write("END griddata\n")
285+
286+
# npf
287+
npf = gwf.get_package("npf")
288+
nc_info = npf.netcdf_info()
289+
290+
# create npf dataset variables
291+
ds = add_netcdf_vars(ds, nc_info, dimmap)
292+
293+
# update data
294+
ds["npf_icelltype"].values = npf.icelltype.get_data()
295+
ds["npf_k"].values = npf.k.get_data()
296+
297+
# update npf to read from netcdf
298+
with open(workspace / "netcdf" / "uzf01.npf", "w") as f:
299+
f.write("BEGIN options\n")
300+
f.write("END options\n\n")
301+
f.write("BEGIN griddata\n")
302+
f.write(" icelltype NETCDF\n")
303+
f.write(" k NETCDF\n")
304+
f.write("END griddata\n")
305+
306+
# get ghbg package netcdf info
307+
ghbg = gwf.get_package("ghbg_0")
308+
nc_info = ghbg.netcdf_info()
309+
310+
# create ghbg dataset variables
311+
ds = add_netcdf_vars(ds, nc_info, dimmap)
312+
313+
# update bhead netcdf array from flopy perioddata
314+
for p in ghbg.bhead.get_data():
315+
istp = sum(gwf.modeltime.nstp[0:p])
316+
ds["ghbg_0_bhead"].values[istp] = ghbg.bhead.get_data()[p]
317+
318+
# update cond netcdf array from flopy perioddata
319+
for p in ghbg.cond.get_data():
320+
istp = sum(gwf.modeltime.nstp[0:p])
321+
ds["ghbg_0_cond"].values[istp] = ghbg.cond.get_data()[p]
322+
323+
# write the netcdf
324+
ds.to_netcdf(
325+
workspace / "netcdf/uzf01.structured.nc", format="NETCDF4", engine="netcdf4"
326+
)
327+
328+
# update ghbg to read from netcdf
329+
with open(workspace / "netcdf/uzf01.ghbg", "w") as f:
330+
f.write("BEGIN options\n")
331+
f.write(" READARRAYGRID\n")
332+
f.write(" PRINT_INPUT\n")
333+
f.write(" PRINT_FLOWS\n")
334+
f.write(" OBS6 FILEIN uzf01.ghb.obs\n")
335+
f.write("END options\n\n")
336+
f.write("BEGIN period 1\n")
337+
f.write(" bhead NETCDF\n")
338+
f.write(" cond NETCDF\n")
339+
f.write("END period 1\n")
340+
341+
# TODO need extended modflow 6 to run this simulation
342+
# run the netcdf sim
343+
# success, buff = sim.run_simulation(silent=True, report=True)
344+
# assert success, pformat(buff)

0 commit comments

Comments
 (0)