diff --git a/autotest/test_interface.py b/autotest/test_interface.py index 79a0fcc..0c6a932 100644 --- a/autotest/test_interface.py +++ b/autotest/test_interface.py @@ -1,6 +1,7 @@ import shutil from pathlib import Path from platform import system +from textwrap import dedent import numpy as np import pytest @@ -341,6 +342,157 @@ def callback(sim, step): raise Exception(e) +def test_sfr_input_context_names(function_tmpdir): + def callback(sim, step): + if step != Callbacks.timestep_start or sim.kstp != 0: + return + model = sim.get_model() + sfr = model.get_package("sfr_0") + if sim.kper == 1: + # the write persists into the next time step + np.testing.assert_allclose(sfr.packagedata.values["hk"], written["hk"], err_msg="hk write did not persist") + written["persisted"] = True + return + if f"__INPUT__/{model.name}/SFR_0/BEDK" in sim.mf6.get_input_var_names(): + path = f"__INPUT__/{model.name}/SFR_0" + names = ("BEDK", "MANNING", "UPSTREAM_FRAC") + else: + path = f"{model.name}/SFR_0" + names = ("HK", "ROUGH", "USTRF") + addrs = [f"{path}/{name}" for name in names] + for addr in addrs: + assert addr in sfr._package_var_addrs, f"{addr} not used" + + pd = sfr.packagedata.values + for column, values in expected.items(): + np.testing.assert_allclose(pd[column], values, err_msg=f"{column} does not match the input") + + pd["hk"] *= 10.0 + sfr.packagedata = pd + np.testing.assert_allclose(sim.mf6.get_value(addrs[0]), pd["hk"], err_msg="hk is not being properly set") + written["hk"] = pd["hk"].copy() + + written = {} + + # three reaches in a row of three cells; reach 1 flows to reach 2 and + # diverts to reach 3 + expected = {"hk": [0.1, 0.2, 0.3], "rough": [0.03, 0.035, 0.04], "ustrf": [1.0, 1.0, 0.0]} + packagedata = "\n".join( + f" {i + 1} 1 1 {i + 1} 100.0 {width} 0.001 {rtp} 1.0 {hk} {rough} {ncon} {ustrf} {ndiv}" + for i, (width, rtp, hk, rough, ncon, ustrf, ndiv) in enumerate( + zip( + [10.0, 10.0, 5.0], + [9.0, 8.9, 8.9], + expected["hk"], + expected["rough"], + [2, 1, 1], + expected["ustrf"], + [1, 0, 0], + ) + ) + ) + files = { + "mfsim.nam": """ + BEGIN timing + TDIS6 sim.tdis + END timing + BEGIN models + gwf6 sfr.nam sfr + END models + BEGIN exchanges + END exchanges + BEGIN solutiongroup 1 + ims6 sim.ims sfr + END solutiongroup + """, + "sim.tdis": """ + BEGIN dimensions + NPER 2 + END dimensions + BEGIN perioddata + 1.0 1 1.0 + 1.0 1 1.0 + END perioddata + """, + "sim.ims": "", + "sfr.nam": """ + BEGIN packages + DIS6 sfr.dis dis + NPF6 sfr.npf npf + IC6 sfr.ic ic + CHD6 sfr.chd chd_0 + SFR6 sfr.sfr sfr_0 + END packages + """, + "sfr.dis": """ + BEGIN dimensions + NLAY 1 + NROW 1 + NCOL 3 + END dimensions + BEGIN griddata + delr + CONSTANT 100.0 + delc + CONSTANT 100.0 + top + CONSTANT 10.0 + botm + CONSTANT 0.0 + END griddata + """, + "sfr.npf": """ + BEGIN griddata + icelltype + CONSTANT 0 + k + CONSTANT 10.0 + END griddata + """, + "sfr.ic": """ + BEGIN griddata + strt + CONSTANT 8.0 + END griddata + """, + "sfr.chd": """ + BEGIN dimensions + MAXBOUND 1 + END dimensions + BEGIN period 1 + 1 1 1 8.0 + END period + """, + "sfr.sfr": """ + BEGIN dimensions + NREACHES 3 + END dimensions + BEGIN packagedata + {packagedata} + END packagedata + BEGIN connectiondata + 1 -2 -3 + 2 1 + 3 1 + END connectiondata + BEGIN diversions + 1 1 3 UPTO + END diversions + BEGIN period 1 + 1 INFLOW 10.0 + 1 DIVERSION 1 2.0 + END period + """, + } + test_pth = function_tmpdir / "sfr_model" + test_pth.mkdir() + for name, text in files.items(): + (test_pth / name).write_text(dedent(text).format(packagedata=packagedata)) + + run_simulation(so, test_pth, callback) + assert written.get("persisted"), "hk was not checked in the second stress period" + + def test_rhs_hcof_advanced(function_tmpdir): def callback(sim, step): model = sim.test_model diff --git a/modflowapi/extensions/data.py b/modflowapi/extensions/data.py index c104da2..80aa0bb 100644 --- a/modflowapi/extensions/data.py +++ b/modflowapi/extensions/data.py @@ -110,7 +110,9 @@ def _set_data(self): else: continue - reduced = var_addr.split("/")[-1].lower() + # keep the column name of a variable read from the input context + column_names = getattr(self.parent, "_column_names", {}) + reduced = column_names.get(var_addr, var_addr.split("/")[-1].lower()) if reduced in ("maxbound", "nbound"): setattr(self, f"_{reduced}", values) if not self._spd and reduced == "maxbound": diff --git a/modflowapi/extensions/datamodel.py b/modflowapi/extensions/datamodel.py index 669a0d5..1b1b1e7 100644 --- a/modflowapi/extensions/datamodel.py +++ b/modflowapi/extensions/datamodel.py @@ -275,6 +275,16 @@ "maw": {"packagedata": ["nmawwells", ("ifno:range:nmawwells", "radius", "bot", "strt", "ngwfnodes")]}, } +# advanced package variables read from the input context when libmf6 has them, +# keyed by column name, with the input context name +adv_input_vars = { + "sfr": { + "hk": "BEDK", + "rough": "MANNING", + "ustrf": "UPSTREAM_FRAC", + }, +} + def get_package_type(pkg_type): from .advpaks import LakPackage, MawPackage, SfrPakage, UzfPackage diff --git a/modflowapi/extensions/pakbase.py b/modflowapi/extensions/pakbase.py index 2a48c9b..29e2464 100644 --- a/modflowapi/extensions/pakbase.py +++ b/modflowapi/extensions/pakbase.py @@ -1,7 +1,7 @@ import numpy as np from .data import AdvancedInput, ArrayInput, ListInput, ScalarInput -from .datamodel import adv_pkgvars, pkgvars +from .datamodel import adv_input_vars, adv_pkgvars, pkgvars class PackageBase: @@ -468,6 +468,10 @@ def __init__(self, model, pkg_type, pkg_name, sim_package=False): self._sp_var_addrs = [] self._package_vars = None self._sp_vars = None + self._input_vars = adv_input_vars.get(pkg_type, {}) + self._column_names = {} + if self._input_vars: + self._input_var_names = set(self.model.mf6.get_input_var_names()) if pkg_type in adv_pkgvars: self._adv_var_dict = adv_pkgvars[pkg_type] @@ -550,6 +554,12 @@ def _get_advanced_variable_addr(self, var_str): ------- var_addr : str """ + var = var_str.lower() + if var in self._input_vars: + s = f"__INPUT__/{self.model.name}/{self.pkg_name}/{self._input_vars[var]}" + if s in self._input_var_names: + self._column_names[s] = var + return s s = f"{self.model.name}/{self.pkg_name}/{var_str.upper()}" return s