Skip to content

Commit 818fbdf

Browse files
committed
fix(cellbudgetfile): fix get_ts support for aux vars
1 parent 75b34a0 commit 818fbdf

File tree

2 files changed

+327
-127
lines changed

2 files changed

+327
-127
lines changed

autotest/test_cellbudgetfile.py

Lines changed: 222 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from autotest.conftest import get_example_data_path
88
from flopy.mf6.modflow.mfsimulation import MFSimulation
99
from flopy.utils.binaryfile import CellBudgetFile
10+
from flopy.utils.gridutil import get_disu_kwargs, get_disv_kwargs
1011

1112
# test low-level CellBudgetFile._build_index() method
1213

@@ -658,34 +659,36 @@ def test_read_mf6_budgetfile(example_data_path):
658659
assert len(rch_zone_3) == 120 * 3 + 1
659660

660661

661-
def test_cellbudgetfile_get_ts_auxiliary_variables(example_data_path):
662+
def test_cellbudgetfile_get_ts_aux_vars_mf2005(example_data_path):
662663
from flopy.discretization import StructuredGrid
663664

664665
mf2005_model_path = example_data_path / "mf2005_test"
665666
cbc_fname = mf2005_model_path / "test1tr.gitcbc"
666667

667-
# modelgrid for test1tr (1 layer, 15 rows, 10 cols)
668-
modelgrid = StructuredGrid(nrow=15, ncol=10, nlay=1)
668+
nlay = 1
669+
nrow = 15
670+
ncol = 10
671+
grid = StructuredGrid(nlay=nlay, nrow=nrow, ncol=ncol)
669672

670-
with CellBudgetFile(cbc_fname, modelgrid=modelgrid) as v:
671-
node = 54 - 1
672-
k = node // (15 * 10)
673-
i = (node % (15 * 10)) // 10
674-
j = node % 10
673+
cbc = CellBudgetFile(cbc_fname, modelgrid=grid)
674+
node = 53
675+
cellid = grid.get_lrc(node)[0]
675676

676-
ts_default = v.get_ts(idx=(k, i, j), text="WELLS")
677-
ts_q_explicit = v.get_ts(idx=(k, i, j), text="WELLS", variable="q")
678-
assert ts_default.shape[1] == 2 # time + 1 data column
679-
np.testing.assert_array_equal(ts_default, ts_q_explicit)
677+
ts_default = cbc.get_ts(idx=cellid, text="WELLS")
678+
ts_q_explicit = cbc.get_ts(idx=cellid, text="WELLS", variable="q")
679+
assert ts_default.shape == ts_q_explicit.shape
680+
assert ts_default.shape[1] == 2 # time + 1 data column
681+
assert np.array_equal(ts_default, ts_q_explicit, equal_nan=True)
680682

681-
ts_iface = v.get_ts(idx=(k, i, j), text="WELLS", variable="IFACE")
682-
assert ts_iface.shape[1] == 2 # time + 1 data column
683-
assert not np.array_equal(ts_default[:, 1], ts_iface[:, 1])
684-
np.testing.assert_array_equal(ts_default[:, 0], ts_iface[:, 0])
683+
ts_iface = cbc.get_ts(idx=cellid, text="WELLS", variable="IFACE")
684+
assert ts_iface.shape[1] == 2 # time + 1 data column
685+
assert ts_default.shape == ts_iface.shape
686+
assert not np.array_equal(ts_default[:, 1], ts_iface[:, 1])
687+
assert np.array_equal(ts_default[:, 0], ts_iface[:, 0], equal_nan=True)
685688

686689

687-
@pytest.mark.requires_exe("mf6")
688-
def test_cellbudgetfile_get_ts_spdis_auxiliary_variables(function_tmpdir):
690+
@pytest.fixture
691+
def dis_sim(function_tmpdir):
689692
from flopy.mf6 import (
690693
MFSimulation,
691694
ModflowGwf,
@@ -698,7 +701,7 @@ def test_cellbudgetfile_get_ts_spdis_auxiliary_variables(function_tmpdir):
698701
ModflowTdis,
699702
)
700703

701-
sim_name = "spdis_test"
704+
sim_name = "test_ts_aux_vars"
702705
sim = MFSimulation(sim_name=sim_name, sim_ws=function_tmpdir, exe_name="mf6")
703706
tdis = ModflowTdis(sim, nper=2, perioddata=[(1.0, 1, 1.0), (1.0, 1, 1.0)])
704707
ims = ModflowIms(sim)
@@ -727,34 +730,211 @@ def test_cellbudgetfile_get_ts_spdis_auxiliary_variables(function_tmpdir):
727730
saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")],
728731
)
729732

733+
return sim
734+
735+
736+
@pytest.mark.requires_exe("mf6")
737+
def test_cellbudgetfile_get_ts_aux_vars_mf6_dis(dis_sim):
738+
sim = dis_sim
730739
sim.write_simulation()
731740
success, _ = sim.run_simulation(silent=True)
741+
assert success
742+
743+
gwf = sim.get_model()
744+
cbc = gwf.output.budget()
745+
spdis = cbc.get_data(text="DATA-SPDIS")
746+
available_fields = list(spdis[0].dtype.names)
747+
expected_fields = ["node", "q", "qx", "qy", "qz"]
748+
for field in expected_fields:
749+
assert field in available_fields
750+
751+
cellid = (0, 2, 2)
752+
nn = gwf.modelgrid.get_node(cellid)[0]
753+
754+
ts_q = cbc.get_ts(idx=cellid, text="DATA-SPDIS", variable="q")
755+
ts_qx = cbc.get_ts(idx=cellid, text="DATA-SPDIS", variable="qx")
756+
ts_qy = cbc.get_ts(idx=cellid, text="DATA-SPDIS", variable="qy")
757+
ts_qz = cbc.get_ts(idx=cellid, text="DATA-SPDIS", variable="qz")
758+
759+
assert ts_q.shape == ts_qx.shape == ts_qy.shape == ts_qz.shape
760+
assert ts_q.shape[1] == 2 # time + 1 data column
761+
assert ts_qx.shape[1] == 2
762+
assert ts_qy.shape[1] == 2
763+
assert ts_qz.shape[1] == 2
764+
765+
assert np.array_equal(ts_q[:, 0], ts_qx[:, 0])
766+
assert np.array_equal(ts_q[:, 0], ts_qy[:, 0])
767+
assert np.array_equal(ts_q[:, 0], ts_qz[:, 0])
768+
769+
# check get_ts() values match get_data() for each time step
770+
for i, rec in enumerate(spdis):
771+
mask = rec["node"] == nn + 1 # 1-based
772+
assert np.allclose(
773+
ts_q[i, 1],
774+
rec["q"][mask][0],
775+
), f"get_ts() q value doesn't match get_data() at time {i}"
776+
assert np.allclose(
777+
ts_qx[i, 1],
778+
rec["qx"][mask][0],
779+
), f"get_ts() qx value doesn't match get_data() at time {i}"
780+
assert np.allclose(
781+
ts_qy[i, 1],
782+
rec["qy"][mask][0],
783+
), f"get_ts() qy value doesn't match get_data() at time {i}"
784+
assert np.allclose(
785+
ts_qz[i, 1],
786+
rec["qz"][mask][0],
787+
), f"get_ts() qz value doesn't match get_data() at time {i}"
788+
789+
assert not np.allclose(ts_qx[:, 1], 0.0), "qx should have non-zero flow"
790+
assert not np.allclose(ts_qy[:, 1], 0.0), "qy should have non-zero flow"
791+
assert np.allclose(ts_q[:, 1], 0.0), "q should be zero for internal cells"
792+
assert np.allclose(ts_qz[:, 1], 0.0), "qz should be zero for single layer"
732793

733-
cbc_file = function_tmpdir / budget_file
734-
with CellBudgetFile(cbc_file, modelgrid=gwf.modelgrid) as cbc:
735-
spdis_data = cbc.get_data(text="DATA-SPDIS")
736-
if len(spdis_data) == 0:
737-
pytest.skip("No DATA-SPDIS records found")
738794

739-
available_fields = list(spdis_data[0].dtype.names)
740-
expected_fields = ["node", "q", "qx", "qy", "qz"]
795+
@pytest.mark.requires_exe("mf6")
796+
def test_cellbudgetfile_get_ts_aux_vars_mf6_disv(dis_sim):
797+
from flopy.mf6 import ModflowGwfchd, ModflowGwfdisv
798+
799+
sim = dis_sim
800+
gwf = sim.get_model()
801+
dis_grid = gwf.modelgrid
802+
disv_kwargs = get_disv_kwargs(
803+
nlay=dis_grid.nlay,
804+
nrow=dis_grid.nrow,
805+
ncol=dis_grid.ncol,
806+
delr=dis_grid.delr,
807+
delc=dis_grid.delc,
808+
tp=dis_grid.top,
809+
botm=dis_grid.botm,
810+
xoff=dis_grid.xoffset,
811+
yoff=dis_grid.yoffset,
812+
)
813+
gwf.remove_package("dis")
814+
gwf.remove_package("chd")
815+
disv = ModflowGwfdisv(gwf, **disv_kwargs)
816+
chd_spd = [[(0, 0), 10.0], [(0, 24), 0.0]]
817+
chd = ModflowGwfchd(gwf, stress_period_data=chd_spd)
741818

742-
for field in ["qx", "qy", "qz"]:
743-
assert field in available_fields, (
744-
f"Expected field '{field}' not found in {available_fields}"
745-
)
819+
sim.write_simulation()
820+
success, _ = sim.run_simulation(silent=False)
821+
assert success
822+
823+
cbc = gwf.output.budget()
824+
spdis = cbc.get_data(text="DATA-SPDIS")
825+
available_fields = list(spdis[0].dtype.names)
826+
expected_fields = ["node", "q", "qx", "qy", "qz"]
827+
for field in expected_fields:
828+
assert field in available_fields
829+
830+
cellid = (0, 4) # cell in center of layer 0
831+
nn = 4
832+
833+
ts_q = cbc.get_ts(idx=cellid, text="DATA-SPDIS", variable="q")
834+
ts_qx = cbc.get_ts(idx=cellid, text="DATA-SPDIS", variable="qx")
835+
ts_qy = cbc.get_ts(idx=cellid, text="DATA-SPDIS", variable="qy")
836+
ts_qz = cbc.get_ts(idx=cellid, text="DATA-SPDIS", variable="qz")
837+
838+
assert ts_q.shape == ts_qx.shape == ts_qy.shape == ts_qz.shape
839+
assert ts_q.shape[1] == 2 # time + 1 data column
840+
assert ts_qx.shape[1] == 2
841+
assert ts_qy.shape[1] == 2
842+
assert ts_qz.shape[1] == 2
843+
844+
# check get_ts() values match get_data() for each time step
845+
for i, rec in enumerate(spdis):
846+
mask = rec["node"] == nn + 1 # 1-based
847+
assert np.allclose(
848+
ts_q[i, 1],
849+
rec["q"][mask][0],
850+
), f"DISV get_ts() q doesn't match get_data() at time {i}"
851+
assert np.allclose(
852+
ts_qx[i, 1],
853+
rec["qx"][mask][0],
854+
), f"DISV get_ts() qx doesn't match get_data() at time {i}"
855+
assert np.allclose(
856+
ts_qy[i, 1],
857+
rec["qy"][mask][0],
858+
), f"DISV get_ts() qy doesn't match get_data() at time {i}"
859+
assert np.allclose(
860+
ts_qz[i, 1],
861+
rec["qz"][mask][0],
862+
), f"DISV get_ts() qz doesn't match get_data() at time {i}"
863+
864+
assert not np.allclose(ts_qx[:, 1], 0.0), "qx should have non-zero flow"
865+
assert not np.allclose(ts_qy[:, 1], 0.0), "qy should have non-zero flow"
866+
assert np.allclose(ts_q[:, 1], 0.0), "q should be zero for internal cells"
867+
assert np.allclose(ts_qz[:, 1], 0.0), "qz should be zero for single layer"
746868

747-
test_cell = (0, 2, 2)
748-
ts_q = cbc.get_ts(idx=test_cell, text="DATA-SPDIS", variable="q")
749-
ts_qx = cbc.get_ts(idx=test_cell, text="DATA-SPDIS", variable="qx")
750-
ts_qy = cbc.get_ts(idx=test_cell, text="DATA-SPDIS", variable="qy")
751-
ts_qz = cbc.get_ts(idx=test_cell, text="DATA-SPDIS", variable="qz")
752869

753-
assert ts_q.shape[1] == 2 # time + 1 data column
754-
assert ts_qx.shape[1] == 2
755-
assert ts_qy.shape[1] == 2
756-
assert ts_qz.shape[1] == 2
870+
@pytest.mark.requires_exe("mf6")
871+
def test_cellbudgetfile_get_ts_aux_vars_mf6_disu(dis_sim):
872+
from flopy.mf6 import ModflowGwfchd, ModflowGwfdisu
873+
874+
sim = dis_sim
875+
gwf = sim.get_model()
876+
dis_grid = gwf.modelgrid
877+
disu_kwargs = get_disu_kwargs(
878+
nlay=dis_grid.nlay,
879+
nrow=dis_grid.nrow,
880+
ncol=dis_grid.ncol,
881+
delr=dis_grid.delr,
882+
delc=dis_grid.delc,
883+
tp=dis_grid.top,
884+
botm=dis_grid.botm,
885+
return_vertices=True,
886+
)
887+
gwf.remove_package("dis")
888+
gwf.remove_package("chd")
889+
disu = ModflowGwfdisu(gwf, **disu_kwargs)
890+
chd_spd = [[0, 10.0], [24, 0.0]]
891+
chd = ModflowGwfchd(gwf, stress_period_data=chd_spd)
757892

758-
np.testing.assert_array_equal(ts_q[:, 0], ts_qx[:, 0])
759-
np.testing.assert_array_equal(ts_q[:, 0], ts_qy[:, 0])
760-
np.testing.assert_array_equal(ts_q[:, 0], ts_qz[:, 0])
893+
sim.write_simulation()
894+
success, _ = sim.run_simulation(silent=False)
895+
assert success
896+
897+
nn = 4
898+
899+
cbc = gwf.output.budget()
900+
spdis = cbc.get_data(text="DATA-SPDIS")
901+
available_fields = list(spdis[0].dtype.names)
902+
expected_fields = ["node", "q", "qx", "qy", "qz"]
903+
for field in expected_fields:
904+
assert field in available_fields
905+
906+
ts_q = cbc.get_ts(idx=nn, text="DATA-SPDIS", variable="q")
907+
ts_qx = cbc.get_ts(idx=nn, text="DATA-SPDIS", variable="qx")
908+
ts_qy = cbc.get_ts(idx=nn, text="DATA-SPDIS", variable="qy")
909+
ts_qz = cbc.get_ts(idx=nn, text="DATA-SPDIS", variable="qz")
910+
911+
assert ts_q.shape == ts_qx.shape == ts_qy.shape == ts_qz.shape
912+
assert ts_q.shape[1] == 2 # time + 1 data column
913+
assert ts_qx.shape[1] == 2
914+
assert ts_qy.shape[1] == 2
915+
assert ts_qz.shape[1] == 2
916+
917+
# check values match get_data()
918+
for i, rec in enumerate(spdis):
919+
mask = rec["node"] == nn + 1 # 1-based
920+
assert np.allclose(
921+
ts_q[i, 1],
922+
rec["q"][mask][0],
923+
), f"DISU get_ts() q doesn't match get_data() at time {i}"
924+
assert np.allclose(
925+
ts_qx[i, 1],
926+
rec["qx"][mask][0],
927+
), f"DISU get_ts() qx doesn't match get_data() at time {i}"
928+
assert np.allclose(
929+
ts_qy[i, 1],
930+
rec["qy"][mask][0],
931+
), f"DISU get_ts() qy doesn't match get_data() at time {i}"
932+
assert np.allclose(
933+
ts_qz[i, 1],
934+
rec["qz"][mask][0],
935+
), f"DISU get_ts() qz doesn't match get_data() at time {i}"
936+
937+
assert not np.allclose(ts_qx[:, 1], 0.0), "qx should have non-zero flow"
938+
assert not np.allclose(ts_qy[:, 1], 0.0), "qy should have non-zero flow"
939+
assert np.allclose(ts_q[:, 1], 0.0), "q should be zero for internal cells"
940+
assert np.allclose(ts_qz[:, 1], 0.0), "qz should be zero for single layer"

0 commit comments

Comments
 (0)