Skip to content

Commit 1fd801d

Browse files
mjrenomjreno
andauthored
feat(netcdf): support for a structured export and gridded input arrays (#1934)
* support for a structured export and gridded input arrays * rebuild makefiles * fix msvs build * add netcdf files to make exclude list * additional netcdf input error handling * restore meson build * some cleanup * few additional doxygen comments * add xarray import to tests * run ruff linter * run ruff formatter --------- Co-authored-by: mjreno <[email protected]>
1 parent c0f0b8e commit 1fd801d

Some content is hidden

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

44 files changed

+5051
-826
lines changed

autotest/test_netcdf_gwe_cnd.py

Lines changed: 128 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
# Imports
88

99
import os
10+
import subprocess
1011

1112
import numpy as np
1213
import pytest
@@ -20,31 +21,116 @@
2021
raise Exception(msg)
2122

2223
try:
24+
import xarray as xa
2325
import xugrid as xu
2426
except ImportError:
25-
pytest.skip("xuarray not found", allow_module_level=True)
27+
pytest.skip("xarray and xugrid not found", allow_module_level=True)
2628

2729
from framework import TestFramework
30+
from test_gwe_cnd import cases
2831

29-
cases = ["cnd01"]
3032

31-
32-
def build_models(idx, test):
33+
def build_models(idx, test, export, gridded_input):
3334
from test_gwe_cnd import build_models as build
3435

3536
sim, dummy = build(idx, test)
3637
sim.tdis.start_date_time = "2041-01-01T00:00:00-05:00"
3738
gwe = sim.gwe[0]
38-
gwe.name_file.export_netcdf = "ugrid"
39+
gwe.name_file.export_netcdf = export
3940
gwe.dis.export_array_netcdf = True
4041
gwe.ic.export_array_netcdf = True
4142
gwe.cnd.export_array_netcdf = True
43+
44+
name = "gwe-" + cases[idx]
45+
46+
# netcdf config
47+
ncf = flopy.mf6.ModflowUtlncf(
48+
gwe.dis,
49+
filename=f"{name}.dis.ncf",
50+
)
51+
4252
return sim, dummy
4353

4454

45-
def check_output(idx, test):
55+
def check_output(idx, test, export, gridded_input):
4656
from test_gwe_cnd import check_output as check
4757

58+
name = "gwe-" + test.name
59+
60+
if gridded_input == "netcdf":
61+
# re-run the simulation with model netcdf input
62+
input_fname = f"{name}.nc"
63+
nc_fname = f"{name}.{export}.nc"
64+
subprocess.run(
65+
["mv", test.workspace / input_fname, test.workspace / nc_fname]
66+
)
67+
68+
with open(test.workspace / f"{name}.nam", "w") as f:
69+
f.write("BEGIN options\n")
70+
f.write(" SAVE_FLOWS\n")
71+
f.write(f" EXPORT_NETCDF {export}\n")
72+
f.write(f" NETCDF FILEIN {name}.{export}.nc\n")
73+
f.write("END options\n\n")
74+
f.write("BEGIN packages\n")
75+
f.write(f" DIS6 {name}.dis dis\n")
76+
f.write(f" IC6 {name}.ic ic\n")
77+
f.write(f" ADV6 {name}.adv adv\n")
78+
f.write(f" CND6 {name}.cnd cnd\n")
79+
f.write(f" EST6 {name}.est est\n")
80+
f.write(f" CTP6 {name}.ctp ctp-1\n")
81+
f.write(f" SSM6 {name}.ssm ssm\n")
82+
f.write(f" OC6 {name}.oc oc\n")
83+
f.write("END packages\n")
84+
85+
with open(test.workspace / f"{name}.dis", "w") as f:
86+
f.write("BEGIN options\n")
87+
f.write(" NOGRB\n")
88+
f.write(" EXPORT_ARRAY_NETCDF\n")
89+
f.write(f" NCF6 FILEIN {name}.dis.ncf\n")
90+
f.write("END options\n\n")
91+
f.write("BEGIN dimensions\n")
92+
f.write(" NLAY 1\n")
93+
f.write(" NROW 1\n")
94+
f.write(" NCOL 101\n")
95+
f.write("END dimensions\n\n")
96+
f.write("BEGIN griddata\n")
97+
f.write(" delr NETCDF\n")
98+
f.write(" delc NETCDF\n")
99+
f.write(" top NETCDF\n")
100+
f.write(" botm NETCDF\n")
101+
f.write(" idomain NETCDF\n")
102+
f.write("END griddata\n\n")
103+
104+
with open(test.workspace / f"{name}.ic", "w") as f:
105+
f.write("BEGIN options\n")
106+
f.write(" EXPORT_ARRAY_NETCDF\n")
107+
f.write("END options\n\n")
108+
f.write("BEGIN griddata\n")
109+
f.write(" strt NETCDF\n")
110+
f.write("END griddata\n")
111+
112+
with open(test.workspace / f"{name}.cnd", "w") as f:
113+
f.write("BEGIN options\n")
114+
f.write(" XT3D_OFF\n")
115+
f.write(" EXPORT_ARRAY_NETCDF\n")
116+
f.write("END options\n\n")
117+
f.write("BEGIN griddata\n")
118+
f.write(" alh NETCDF\n")
119+
f.write(" ath1 NETCDF\n")
120+
f.write(" ktw NETCDF\n")
121+
f.write(" kts NETCDF\n")
122+
f.write("END griddata\n")
123+
124+
success, buff = flopy.run_model(
125+
test.targets["mf6"],
126+
test.workspace / "mfsim.nam",
127+
model_ws=test.workspace,
128+
report=True,
129+
)
130+
131+
assert success
132+
test.success = success
133+
48134
check(idx, test)
49135

50136
# read transport results from GWE model
@@ -63,8 +149,11 @@ def check_output(idx, test):
63149

64150
# Check NetCDF output
65151
nc_fpth = os.path.join(test.workspace, f"{gwename}.nc")
66-
ds = xu.open_dataset(nc_fpth)
67-
xds = ds.ugrid.to_dataset()
152+
if export == "ugrid":
153+
ds = xu.open_dataset(nc_fpth)
154+
xds = ds.ugrid.to_dataset()
155+
elif export == "structured":
156+
xds = xa.open_dataset(nc_fpth)
68157

69158
# Compare NetCDF head arrays with binary headfile temperatures
70159
gwe = test.sims[0].gwe[0]
@@ -78,12 +167,20 @@ def check_output(idx, test):
78167
for i in range(nper):
79168
for j in range(int(pd[i][1])):
80169
rec = cobj.get_data(kstpkper=(j, i))
81-
for l in range(nlay):
170+
if export == "ugrid":
171+
for l in range(nlay):
172+
assert np.allclose(
173+
np.array(rec[l]).flatten(),
174+
xds[f"temperature_l{l+1}"][timestep, :].data,
175+
), f"NetCDF-temperature comparison failure in timestep {timestep+1}"
176+
timestep += 1
177+
elif export == "structured":
82178
assert np.allclose(
83-
np.array(rec[l]).flatten(),
84-
xds[f"temperature_l{l+1}"][timestep, :].data,
179+
# np.array(rec).flatten(),
180+
np.array(rec),
181+
xds["temperature"][timestep, :].data,
85182
), f"NetCDF-temperature comparison failure in timestep {timestep+1}"
86-
timestep += 1
183+
timestep += 1
87184

88185
vlist = [
89186
"dis_delr",
@@ -97,15 +194,6 @@ def check_output(idx, test):
97194
"cnd_ktw_l",
98195
"cnd_kts_l",
99196
]
100-
layer_vlist = [
101-
"dis_botm_l",
102-
"dis_idomain_l",
103-
"ic_strt_l",
104-
"cnd_alh_l",
105-
"cnd_ath1_l",
106-
"cnd_ktw_l",
107-
"cnd_kts_l",
108-
]
109197

110198
# Compare NetCDF package input arrays with FloPy arrays
111199
gwe = test.sims[0].gwe[0]
@@ -115,14 +203,22 @@ def check_output(idx, test):
115203
array_name = tokens[1].split("_")[0]
116204
package = getattr(gwe, package_name)
117205
b = getattr(package, array_name).array
118-
if var in layer_vlist:
119-
for l in range(nlay):
206+
if export == "ugrid":
207+
if var.endswith("_l"):
208+
for l in range(nlay):
209+
assert np.allclose(
210+
np.array(b[l]).flatten(), xds[f"{var}{l+1}"].data
211+
), f"NetCDF input array comparison failure, variable={var}{l+1}"
212+
else:
120213
assert np.allclose(
121-
np.array(b[l]).flatten(), xds[f"{var}{l+1}"].data
122-
), f"NetCDF input array comparison failure, variable={var}{l+1}"
123-
else:
214+
np.array(b).flatten(), xds[var].data
215+
), f"NetCDF input array comparison failure, variable={var}"
216+
elif export == "structured":
217+
var = var.replace("_l", "")
124218
assert np.allclose(
125-
np.array(b).flatten(), xds[var].data
219+
# np.array(b).flatten(), xds[var].data
220+
np.array(b),
221+
xds[var].data,
126222
), f"NetCDF input array comparison failure, variable={var}"
127223

128224

@@ -131,12 +227,14 @@ def check_output(idx, test):
131227
"idx, name",
132228
list(enumerate(cases)),
133229
)
134-
def test_mf6model(idx, name, function_tmpdir, targets):
230+
@pytest.mark.parametrize("export", ["ugrid", "structured"])
231+
@pytest.mark.parametrize("gridded_input", ["ascii", "netcdf"])
232+
def test_mf6model(idx, name, function_tmpdir, targets, export, gridded_input):
135233
test = TestFramework(
136234
name=name,
137235
workspace=function_tmpdir,
138-
build=lambda t: build_models(idx, t),
139-
check=lambda t: check_output(idx, t),
236+
build=lambda t: build_models(idx, t, export, gridded_input),
237+
check=lambda t: check_output(idx, t, export, gridded_input),
140238
targets=targets,
141239
)
142240
test.run()

0 commit comments

Comments
 (0)