Skip to content

Commit 39d8d32

Browse files
authored
fix(HeadFile,CellBudgetFile): fix tdis reversal (#2460)
Fix #2459 and expand tests
1 parent ca3adb3 commit 39d8d32

File tree

2 files changed

+48
-41
lines changed

2 files changed

+48
-41
lines changed

autotest/test_binaryfile.py

+30-13
Original file line numberDiff line numberDiff line change
@@ -469,7 +469,7 @@ def test_binaryfile_read_context(freyberg_model_path):
469469
def test_binaryfile_reverse_mf6_dis(function_tmpdir):
470470
name = "reverse_dis"
471471
sim = flopy.mf6.MFSimulation(sim_name=name, sim_ws=function_tmpdir, exe_name="mf6")
472-
tdis_rc = [(1, 1, 1.0), (1, 1, 1.0)]
472+
tdis_rc = [(1, 1, 1.0), (1, 1, 1.0), (1, 1, 1.0)]
473473
nper = len(tdis_rc)
474474
tdis = flopy.mf6.ModflowTdis(sim, nper=nper, perioddata=tdis_rc)
475475
ims = flopy.mf6.ModflowIms(sim)
@@ -503,20 +503,26 @@ def test_binaryfile_reverse_mf6_dis(function_tmpdir):
503503

504504
# reverse head file in place and check reversal
505505
head_file = flopy.utils.HeadFile(function_tmpdir / head_file)
506-
heads = head_file.get_alldata()
507-
assert heads.shape == (nper, 2, 10, 10)
506+
orig_heads = head_file.get_alldata()
507+
orig_kstpkper = head_file.get_kstpkper()
508508
head_file.reverse()
509-
heads_rev = head_file.get_alldata()
510-
assert heads_rev.shape == (nper, 2, 10, 10)
509+
rev_heads = head_file.get_alldata()
510+
rev_kstpkper = head_file.get_kstpkper()
511+
exp_head_shape = (nper, 2, 10, 10)
512+
assert orig_heads.shape == exp_head_shape
513+
assert rev_heads.shape == (nper, 2, 10, 10)
514+
assert orig_kstpkper == rev_kstpkper
511515

512516
# reverse budget and write to separate file
513517
budget_file_rev_path = function_tmpdir / f"{budget_file}_rev"
514518
budget_file = flopy.utils.CellBudgetFile(function_tmpdir / budget_file)
515519
budget_file.reverse(budget_file_rev_path)
516520
budget_file_rev = flopy.utils.CellBudgetFile(budget_file_rev_path)
521+
assert budget_file.get_kstpkper() == orig_kstpkper
522+
assert budget_file_rev.get_kstpkper() == rev_kstpkper
517523

518524
for kper in range(nper):
519-
assert np.allclose(heads[kper], heads_rev[-kper + 1])
525+
assert np.allclose(orig_heads[kper], rev_heads[-(kper + 1)])
520526
budget = budget_file.get_data(text="FLOW-JA-FACE", totim=kper)[0]
521527
budget_rev = budget_file_rev.get_data(text="FLOW-JA-FACE", totim=kper)[0]
522528
assert budget.shape == budget_rev.shape
@@ -527,7 +533,7 @@ def test_binaryfile_reverse_mf6_dis(function_tmpdir):
527533
def test_binaryfile_reverse_mf6_disv(function_tmpdir):
528534
name = "reverse_disv"
529535
sim = flopy.mf6.MFSimulation(sim_name=name, sim_ws=function_tmpdir, exe_name="mf6")
530-
tdis_rc = [(1, 1, 1.0), (1, 1, 1.0)]
536+
tdis_rc = [(1, 1, 1.0), (1, 1, 1.0), (1, 1, 1.0)]
531537
nper = len(tdis_rc)
532538
tdis = flopy.mf6.ModflowTdis(sim, nper=nper, perioddata=tdis_rc)
533539
ims = flopy.mf6.ModflowIms(sim)
@@ -555,20 +561,26 @@ def test_binaryfile_reverse_mf6_disv(function_tmpdir):
555561

556562
# reverse head file in place and check reversal
557563
head_file = flopy.utils.HeadFile(function_tmpdir / head_file)
558-
heads = head_file.get_alldata()
559-
assert heads.shape == (nper, 2, 1, 100)
564+
orig_heads = head_file.get_alldata()
565+
orig_kstpkper = head_file.get_kstpkper()
560566
head_file.reverse()
561-
heads_rev = head_file.get_alldata()
562-
assert heads_rev.shape == (nper, 2, 1, 100)
567+
rev_heads = head_file.get_alldata()
568+
rev_kstpkper = head_file.get_kstpkper()
569+
exp_shape = (nper, 2, 1, 100)
570+
assert orig_heads.shape == exp_shape
571+
assert rev_heads.shape == exp_shape
572+
assert orig_kstpkper == rev_kstpkper
563573

564574
# reverse budget and write to separate file
565575
budget_file_rev_path = function_tmpdir / f"{budget_file}_rev"
566576
budget_file = flopy.utils.CellBudgetFile(function_tmpdir / budget_file)
567577
budget_file.reverse(budget_file_rev_path)
568578
budget_file_rev = flopy.utils.CellBudgetFile(budget_file_rev_path, tdis=tdis)
579+
assert budget_file.get_kstpkper() == orig_kstpkper
580+
assert budget_file_rev.get_kstpkper() == rev_kstpkper
569581

570582
for kper in range(nper):
571-
assert np.allclose(heads[kper], heads_rev[-kper + 1])
583+
assert np.allclose(orig_heads[kper], rev_heads[-(kper + 1)])
572584
budget = budget_file.get_data(text="FLOW-JA-FACE", totim=kper)[0]
573585
budget_rev = budget_file_rev.get_data(text="FLOW-JA-FACE", totim=kper)[0]
574586
assert budget.shape == budget_rev.shape
@@ -581,7 +593,7 @@ def test_binaryfile_reverse_mf6_disu(example_data_path, function_tmpdir):
581593
sim = flopy.mf6.MFSimulation.load(
582594
sim_name=sim_name, sim_ws=example_data_path / "mf6" / sim_name
583595
)
584-
tdis_rc = [(1, 1, 1.0), (1, 1, 1.0)]
596+
tdis_rc = [(1, 1, 1.0), (1, 1, 1.0), (1, 1, 1.0)]
585597
nper = len(tdis_rc)
586598
tdis = flopy.mf6.ModflowTdis(sim, time_units="DAYS", nper=nper, perioddata=tdis_rc)
587599
sim.set_sim_path(function_tmpdir)
@@ -591,11 +603,14 @@ def test_binaryfile_reverse_mf6_disu(example_data_path, function_tmpdir):
591603
# load head file, providing tdis as kwarg
592604
file_path = function_tmpdir / "flow.hds"
593605
head_file = HeadFile(file_path, tdis=tdis)
606+
orig_kstpkper = head_file.get_kstpkper()
594607

595608
# reverse and write to a separate file
596609
head_file_rev_path = function_tmpdir / "flow_rev.hds"
597610
head_file.reverse(filename=head_file_rev_path)
598611
head_file_rev = HeadFile(head_file_rev_path)
612+
rev_kstpkper = head_file_rev.get_kstpkper()
613+
assert orig_kstpkper == rev_kstpkper
599614

600615
# load budget file
601616
file_path = function_tmpdir / "flow.cbc"
@@ -605,6 +620,8 @@ def test_binaryfile_reverse_mf6_disu(example_data_path, function_tmpdir):
605620
budget_file_rev_path = function_tmpdir / "flow_rev.cbc"
606621
budget_file.reverse(filename=budget_file_rev_path)
607622
budget_file_rev = CellBudgetFile(budget_file_rev_path)
623+
assert budget_file.get_kstpkper() == orig_kstpkper
624+
assert budget_file_rev.get_kstpkper() == rev_kstpkper
608625

609626
# check that data from both files have the same shape
610627
assert head_file.get_alldata().shape == (nper, 1, 1, 121)

flopy/utils/binaryfile/__init__.py

+18-28
Original file line numberDiff line numberDiff line change
@@ -577,6 +577,22 @@ def get_ts(self, idx):
577577
return result
578578

579579

580+
def _get_max_kper_kstp_tsim(ra: np.recarray) -> tuple[int, dict[int, int], float]:
581+
header = ra[-1]
582+
max_kper = header["kper"] - 1
583+
max_tsim = header["totim"]
584+
max_kstp = {0: 0}
585+
for i in range(len(ra) - 1, -1, -1):
586+
header = ra[i]
587+
kper = header["kper"] - 1
588+
kstp = header["kstp"] - 1
589+
if kper in max_kstp and kstp > max_kstp[kper]:
590+
max_kstp[kper] += 1
591+
else:
592+
max_kstp[kper] = 0
593+
return max_kper, max_kstp, max_tsim
594+
595+
580596
class HeadFile(BinaryLayerFile):
581597
"""
582598
The HeadFile class provides simple ways to retrieve and manipulate
@@ -650,20 +666,7 @@ def reverse(self, filename: Optional[os.PathLike] = None):
650666
else self.filename
651667
)
652668

653-
def get_max_kper_kstp_tsim():
654-
header = self.recordarray[-1]
655-
kper = header["kper"] - 1
656-
tsim = header["totim"]
657-
kstp = {0: 0}
658-
for i in range(len(self) - 1, -1, -1):
659-
header = self.recordarray[i]
660-
if header["kper"] in kstp and header["kstp"] > kstp[header["kper"]]:
661-
kstp[header["kper"]] += 1
662-
else:
663-
kstp[header["kper"]] = 0
664-
return kper, kstp, tsim
665-
666-
maxkper, maxkstp, maxtsim = get_max_kper_kstp_tsim()
669+
maxkper, maxkstp, maxtsim = _get_max_kper_kstp_tsim(self.recordarray)
667670
prev_kper = None
668671
perlen = None
669672

@@ -2229,20 +2232,7 @@ def reverse(self, filename: Optional[os.PathLike] = None):
22292232
nrecords = len(self)
22302233
target = filename
22312234

2232-
def get_max_kper_kstp_tsim():
2233-
header = self.recordarray[-1]
2234-
kper = header["kper"] - 1
2235-
tsim = header["totim"]
2236-
kstp = {0: 0}
2237-
for i in range(len(self) - 1, -1, -1):
2238-
header = self.recordarray[i]
2239-
if header["kper"] in kstp and header["kstp"] > kstp[header["kper"]]:
2240-
kstp[header["kper"]] += 1
2241-
else:
2242-
kstp[header["kper"]] = 0
2243-
return kper, kstp, tsim
2244-
2245-
maxkper, maxkstp, maxtsim = get_max_kper_kstp_tsim()
2235+
maxkper, maxkstp, maxtsim = _get_max_kper_kstp_tsim(self.recordarray)
22462236
prev_kper = None
22472237
perlen = None
22482238

0 commit comments

Comments
 (0)