diff --git a/CITATION.cff b/CITATION.cff index f9732fead..b2ba98498 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -3,8 +3,8 @@ message: If you use this software, please cite both the article from preferred-c and the software itself. type: software title: FloPy -version: 3.4.2 -date-released: '2023-08-25' +version: 3.4.3 +date-released: '2023-09-30' doi: 10.5066/F7BK19FH abstract: A Python package to create, run, and post-process MODFLOW-based models. repository-artifact: https://pypi.org/project/flopy diff --git a/README.md b/README.md index 9d297427e..361bff05f 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ flopy3 -### Version 3.4.2 +### Version 3.4.3 [![flopy continuous integration](https://github.com/modflowpy/flopy/actions/workflows/commit.yml/badge.svg?branch=develop)](https://github.com/modflowpy/flopy/actions/workflows/commit.yml) [![Read the Docs](https://github.com/modflowpy/flopy/actions/workflows/rtd.yml/badge.svg?branch=develop)](https://github.com/modflowpy/flopy/actions/workflows/rtd.yml) @@ -142,7 +142,7 @@ How to Cite ##### ***Software/Code citation for FloPy:*** -[Bakker, Mark, Post, Vincent, Hughes, J. D., Langevin, C. D., White, J. T., Leaf, A. T., Paulinski, S. R., Bellino, J. C., Morway, E. D., Toews, M. W., Larsen, J. D., Fienen, M. N., Starn, J. J., Brakenhoff, D. A., and Bonelli, W. P., 2023, FloPy v3.4.2: U.S. Geological Survey Software Release, 25 August 2023, https://doi.org/10.5066/F7BK19FH](https://doi.org/10.5066/F7BK19FH) +[Bakker, Mark, Post, Vincent, Hughes, J. D., Langevin, C. D., White, J. T., Leaf, A. T., Paulinski, S. R., Bellino, J. C., Morway, E. D., Toews, M. W., Larsen, J. D., Fienen, M. N., Starn, J. J., Brakenhoff, D. A., and Bonelli, W. P., 2023, FloPy v3.4.3: U.S. Geological Survey Software Release, 30 September 2023, https://doi.org/10.5066/F7BK19FH](https://doi.org/10.5066/F7BK19FH) Additional FloPy Related Publications diff --git a/autotest/test_binaryfile.py b/autotest/test_binaryfile.py index bb6795b70..c3b6e12a1 100644 --- a/autotest/test_binaryfile.py +++ b/autotest/test_binaryfile.py @@ -1,11 +1,14 @@ import os +from itertools import repeat import numpy as np import pytest from autotest.conftest import get_example_data_path from matplotlib import pyplot as plt from matplotlib.axes import Axes +from modflow_devtools.markers import requires_exe +import flopy from flopy.modflow import Modflow from flopy.utils import ( BinaryHeader, @@ -545,3 +548,170 @@ def test_cellbudgetfile_readrecord_waux(example_data_path): record ) v.close() + + +@pytest.fixture +@pytest.mark.mf6 +@requires_exe("mf6") +def mf6_gwf_2sp_st_tr(function_tmpdir): + """ + A basic flow model with 2 stress periods, + first steady-state, the second transient. + """ + + name = "mf6_gwf_2sp" + sim = flopy.mf6.MFSimulation( + sim_name=name, + version="mf6", + exe_name="mf6", + sim_ws=function_tmpdir, + ) + + tdis = flopy.mf6.ModflowTdis( + simulation=sim, + nper=2, + perioddata=[(0, 1, 1), (10, 10, 1)], + ) + + ims = flopy.mf6.ModflowIms( + simulation=sim, + complexity="SIMPLE", + ) + + gwf = flopy.mf6.ModflowGwf( + simulation=sim, + modelname=name, + save_flows=True, + ) + + dis = flopy.mf6.ModflowGwfdis( + model=gwf, nlay=1, nrow=1, ncol=10, delr=1, delc=10, top=10, botm=0 + ) + + npf = flopy.mf6.ModflowGwfnpf( + model=gwf, + icelltype=[0], + k=10, + ) + + ic = flopy.mf6.ModflowGwfic( + model=gwf, + strt=0, + ) + + wel = flopy.mf6.ModflowGwfwel( + model=gwf, + stress_period_data={0: 0, 1: [[(0, 0, 0), -1]]}, + ) + + sto = flopy.mf6.ModflowGwfsto( + model=gwf, + ss=1e-4, + steady_state={0: True}, + transient={1: True}, + ) + + chd = flopy.mf6.ModflowGwfchd( + model=gwf, + stress_period_data={0: [[(0, 0, 9), 0]]}, + ) + + oc = flopy.mf6.ModflowGwfoc( + model=gwf, + budget_filerecord=f"{name}.cbc", + head_filerecord=f"{name}.hds", + saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], + ) + + return sim + + +def test_read_mf6_2sp(mf6_gwf_2sp_st_tr): + sim = mf6_gwf_2sp_st_tr + gwf = sim.get_model() + sim.write_simulation(silent=False) + success, _ = sim.run_simulation(silent=False) + assert success + + # load heads and flows + hds = gwf.output.head() + cbb = gwf.output.budget() + + # check times + exp_times = [float(t) for t in range(11)] + assert hds.get_times() == exp_times + assert cbb.get_times() == exp_times + + # check stress periods and time steps + exp_kstpkper = [(0, 0)] + [(i, 1) for i in range(10)] + assert hds.get_kstpkper() == exp_kstpkper + assert cbb.get_kstpkper() == exp_kstpkper + + # check head data access by time + exp_hds_data = np.array([[list(repeat(0.0, 10))]]) + hds_data = hds.get_data(totim=0) + assert np.array_equal(hds_data, exp_hds_data) + + # check budget file data by time + cbb_data = cbb.get_data(totim=0) + assert len(cbb_data) > 0 + + # check head data access by kstp and kper + hds_data = hds.get_data(kstpkper=(0, 0)) + assert np.array_equal(hds_data, exp_hds_data) + + # check budget file data by kstp and kper + cbb_data_kstpkper = cbb.get_data(kstpkper=(0, 0)) + assert len(cbb_data) == len(cbb_data_kstpkper) + for i in range(len(cbb_data)): + assert np.array_equal(cbb_data[i], cbb_data_kstpkper[i]) + + +@pytest.mark.parametrize("compact", [True, False]) +def test_read_mf2005_freyberg(example_data_path, function_tmpdir, compact): + m = flopy.modflow.Modflow.load( + example_data_path / "freyberg" / "freyberg.nam", + ) + m.change_model_ws(function_tmpdir) + oc = m.get_package("OC") + oc.compact = compact + + m.write_input() + success, buff = m.run_model(silent=False) + assert success + + # load heads and flows + hds_file = function_tmpdir / "freyberg.hds" + cbb_file = function_tmpdir / "freyberg.cbc" + assert hds_file.is_file() + assert cbb_file.is_file() + hds = HeadFile(hds_file) + cbb = CellBudgetFile(cbb_file, model=m) # failing to specify a model... + + # check times + exp_times = [10.0] + assert hds.get_times() == exp_times + assert cbb.get_times() == exp_times # ...causes get_times() to be empty + + # check stress periods and time steps + exp_kstpkper = [(0, 0)] + assert hds.get_kstpkper() == exp_kstpkper + assert cbb.get_kstpkper() == exp_kstpkper + + # check head data access by time + hds_data_totim = hds.get_data(totim=exp_times[0]) + assert hds_data_totim.shape == (1, 40, 20) + + # check budget file data by time + cbb_data = cbb.get_data(totim=exp_times[0]) + assert len(cbb_data) > 0 + + # check head data access by kstp and kper + hds_data_kstpkper = hds.get_data(kstpkper=(0, 0)) + assert np.array_equal(hds_data_kstpkper, hds_data_totim) + + # check budget file data by kstp and kper + cbb_data_kstpkper = cbb.get_data(kstpkper=(0, 0)) + assert len(cbb_data) == len(cbb_data_kstpkper) + for i in range(len(cbb_data)): + assert np.array_equal(cbb_data[i], cbb_data_kstpkper[i]) diff --git a/autotest/test_export.py b/autotest/test_export.py index 96f3503a2..e0ee5a622 100644 --- a/autotest/test_export.py +++ b/autotest/test_export.py @@ -51,6 +51,10 @@ from flopy.utils.crs import get_authority_crs from flopy.utils.geometry import Polygon +HAS_PYPROJ = has_pkg("pyproj", strict=True) +if HAS_PYPROJ: + import pyproj + def namfiles() -> List[Path]: mf2005_path = get_example_data_path() / "mf2005_test" @@ -677,6 +681,13 @@ def test_export_contourf(function_tmpdir, example_data_path): len(shapes) >= 65 ), "multipolygons were skipped in contourf routine" + # debugging + # for s in shapes: + # x = [i[0] for i in s.points[:]] + # y = [i[1] for i in s.points[:]] + # plt.plot(x, y) + # plt.show() + @pytest.mark.mf6 @requires_pkg("shapefile", "shapely") @@ -706,6 +717,13 @@ def test_export_contours(function_tmpdir, example_data_path): # expect 65 with standard mpl contours (structured grids), 86 with tricontours assert len(shapes) >= 65 + # debugging + # for s in shapes: + # x = [i[0] for i in s.points[:]] + # y = [i[1] for i in s.points[:]] + # plt.plot(x, y) + # plt.show() + @pytest.mark.mf6 @requires_pkg("shapely") diff --git a/autotest/test_generate_classes.py b/autotest/test_generate_classes.py index 06527a56f..a169ec392 100644 --- a/autotest/test_generate_classes.py +++ b/autotest/test_generate_classes.py @@ -3,10 +3,29 @@ from pprint import pprint import pytest +from modflow_devtools.misc import get_current_branch + +branch = get_current_branch() @pytest.mark.mf6 -def test_generate_classes_from_dfn(virtualenv, project_root_path): +@pytest.mark.slow +@pytest.mark.regression +@pytest.mark.skipif( + branch == "master" or branch.startswith("v"), + reason="skip on master and release branches", +) +def test_generate_classes_from_github_refs( + request, virtualenv, project_root_path, ref, worker_id +): + argv = ( + request.config.workerinput["mainargv"] + if hasattr(request.config, "workerinput") + else [] + ) + if worker_id != "master" and "loadfile" not in argv: + pytest.skip("can't run in parallel") + python = virtualenv.python venv = Path(python).parent print(f"Using temp venv at {venv} with python {python}") diff --git a/autotest/test_mbase.py b/autotest/test_mbase.py index 757909f96..8e3ee5d82 100644 --- a/autotest/test_mbase.py +++ b/autotest/test_mbase.py @@ -10,6 +10,8 @@ from flopy.mbase import resolve_exe from flopy.utils.flopy_io import relpath_safe +_system = system() + @pytest.fixture def mf6_model_path(example_data_path): @@ -18,10 +20,7 @@ def mf6_model_path(example_data_path): @requires_exe("mf6") @pytest.mark.parametrize("use_ext", [True, False]) -def test_resolve_exe_by_name(function_tmpdir, use_ext): - if use_ext and system() != "Windows": - pytest.skip(".exe extensions are Windows-only") - +def test_resolve_exe_by_name(use_ext): ext = ".exe" if use_ext else "" expected = which("mf6").lower() actual = resolve_exe(f"mf6{ext}") @@ -31,13 +30,14 @@ def test_resolve_exe_by_name(function_tmpdir, use_ext): @requires_exe("mf6") @pytest.mark.parametrize("use_ext", [True, False]) -def test_resolve_exe_by_abs_path(function_tmpdir, use_ext): - if use_ext and system() != "Windows": - pytest.skip(".exe extensions are Windows-only") - - ext = ".exe" if use_ext else "" +def test_resolve_exe_by_abs_path(use_ext): + abs_path = which("mf6") + if _system == "Windows" and not use_ext: + abs_path = abs_path[:-4] + elif _system != "Windows" and use_ext: + abs_path = f"{abs_path}.exe" expected = which("mf6").lower() - actual = resolve_exe(which(f"mf6{ext}")) + actual = resolve_exe(abs_path) assert actual.lower() == expected assert which(actual) @@ -46,9 +46,6 @@ def test_resolve_exe_by_abs_path(function_tmpdir, use_ext): @pytest.mark.parametrize("use_ext", [True, False]) @pytest.mark.parametrize("forgive", [True, False]) def test_resolve_exe_by_rel_path(function_tmpdir, use_ext, forgive): - if use_ext and system() != "Windows": - pytest.skip(".exe extensions are Windows-only") - ext = ".exe" if use_ext else "" expected = which("mf6").lower() @@ -59,10 +56,11 @@ def test_resolve_exe_by_rel_path(function_tmpdir, use_ext, forgive): with set_dir(inner_dir): # copy exe to relative dir - copy(expected, bin_dir / "mf6") - assert (bin_dir / "mf6").is_file() + new_exe_path = bin_dir / Path(expected).name + copy(expected, new_exe_path) + assert new_exe_path.is_file() - expected = which(str(Path(bin_dir / "mf6").absolute())).lower() + expected = which(str(new_exe_path.absolute())).lower() actual = resolve_exe(f"../bin/mf6{ext}") assert actual.lower() == expected assert which(actual) @@ -77,7 +75,7 @@ def test_resolve_exe_by_rel_path(function_tmpdir, use_ext, forgive): def test_run_model_when_namefile_not_in_model_ws( - mf6_model_path, example_data_path, function_tmpdir + mf6_model_path, function_tmpdir ): # copy input files to temp workspace ws = function_tmpdir / "ws" diff --git a/autotest/test_modflow.py b/autotest/test_modflow.py index 4f165dd11..8e1c8b114 100644 --- a/autotest/test_modflow.py +++ b/autotest/test_modflow.py @@ -207,10 +207,10 @@ def test_exe_selection(example_data_path, function_tmpdir): # no selection defaults to mf2005 exe_name = "mf2005" - assert Path(Modflow().exe_name).name == exe_name - assert Path(Modflow(exe_name=None).exe_name).name == exe_name + assert Path(Modflow().exe_name).stem == exe_name + assert Path(Modflow(exe_name=None).exe_name).stem == exe_name assert ( - Path(Modflow.load(namfile_path, model_ws=model_path).exe_name).name + Path(Modflow.load(namfile_path, model_ws=model_path).exe_name).stem == exe_name ) assert ( @@ -218,20 +218,20 @@ def test_exe_selection(example_data_path, function_tmpdir): Modflow.load( namfile_path, exe_name=None, model_ws=model_path ).exe_name - ).name + ).stem == exe_name ) # user-specified (just for testing - there is no legitimate reason # to use mp7 with Modflow but Modpath7 derives from BaseModel too) exe_name = "mp7" - assert Path(Modflow(exe_name=exe_name).exe_name).name == exe_name + assert Path(Modflow(exe_name=exe_name).exe_name).stem == exe_name assert ( Path( Modflow.load( namfile_path, exe_name=exe_name, model_ws=model_path ).exe_name - ).name + ).stem == exe_name ) diff --git a/autotest/test_mp7.py b/autotest/test_mp7.py index b51edf624..b8b6a4e98 100644 --- a/autotest/test_mp7.py +++ b/autotest/test_mp7.py @@ -899,8 +899,7 @@ def test_pathline_plotting(function_tmpdir): @requires_exe("mf6", "mp7") -@pytest.mark.parametrize("verbose", [True, False]) -def test_mp7sim_replacement(function_tmpdir, capfd, verbose): +def test_mp7sim_replacement(function_tmpdir, capfd): mf6sim = Mp7Cases.mf6(function_tmpdir) mf6sim.write_simulation() mf6sim.run_simulation() @@ -911,7 +910,6 @@ def test_mp7sim_replacement(function_tmpdir, capfd, verbose): flowmodel=mf6sim.get_model(mf6sim.name), exe_name="mp7", model_ws=mf6sim.sim_path, - verbose=verbose, ) defaultiface6 = {"RCH": 6, "EVT": 6} mpbas = Modpath7Bas(mp, porosity=0.1, defaultiface=defaultiface6) @@ -931,27 +929,25 @@ def test_mp7sim_replacement(function_tmpdir, capfd, verbose): zones=Mp7Cases.zones, particlegroups=Mp7Cases.particlegroups, ) - # add a duplicate mp7sim package - mpsim = Modpath7Sim( - mp, - simulationtype="combined", - trackingdirection="forward", - weaksinkoption="pass_through", - weaksourceoption="pass_through", - budgetoutputoption="summary", - budgetcellnumbers=[1049, 1259], - traceparticledata=[1, 1000], - referencetime=[0, 0, 0.0], - stoptimeoption="extend", - timepointdata=[500, 1000.0], - zonedataoption="on", - zones=Mp7Cases.zones, - particlegroups=Mp7Cases.particlegroups, - ) - cap = capfd.readouterr() - msg = "Two packages of the same type" - assert verbose == (msg in cap.out) + # add a duplicate mp7sim package + with pytest.warns(UserWarning, match="Two packages of the same type"): + mpsim = Modpath7Sim( + mp, + simulationtype="combined", + trackingdirection="forward", + weaksinkoption="pass_through", + weaksourceoption="pass_through", + budgetoutputoption="summary", + budgetcellnumbers=[1049, 1259], + traceparticledata=[1, 1000], + referencetime=[0, 0, 0.0], + stoptimeoption="extend", + timepointdata=[500, 1000.0], + zonedataoption="on", + zones=Mp7Cases.zones, + particlegroups=Mp7Cases.particlegroups, + ) mp.write_input() success, buff = mp.run_model() diff --git a/autotest/test_postprocessing.py b/autotest/test_postprocessing.py index 4812ac9c0..fd49f0383 100644 --- a/autotest/test_postprocessing.py +++ b/autotest/test_postprocessing.py @@ -4,6 +4,7 @@ import pytest from modflow_devtools.markers import requires_exe +import flopy from flopy.mf6 import ( MFSimulation, ModflowGwf, @@ -26,51 +27,190 @@ ) -@pytest.fixture(scope="module") +@pytest.fixture +def mf2005_freyberg_path(example_data_path): + return example_data_path / "freyberg" + + +@pytest.fixture def mf6_freyberg_path(example_data_path): return example_data_path / "mf6-freyberg" +@pytest.mark.parametrize( + "nlay, nrow, ncol", + [ + # extended in 1 dimension + [3, 1, 1], + [1, 3, 1], + [1, 1, 3], + # 2D + [3, 3, 1], + [1, 3, 3], + [3, 1, 3], + # 3D + [3, 3, 3], + ], +) @pytest.mark.mf6 @requires_exe("mf6") -def test_faceflows(function_tmpdir, mf6_freyberg_path): +def test_get_structured_faceflows(function_tmpdir, nlay, nrow, ncol): + name = "gsff" + sim = flopy.mf6.MFSimulation( + sim_name=name, exe_name="mf6", version="mf6", sim_ws=function_tmpdir + ) + + # tdis + tdis = flopy.mf6.ModflowTdis( + sim, + nper=1, + perioddata=[(1.0, 1, 1.0)], + ) + + # gwf + gwf = flopy.mf6.ModflowGwf( + sim, + modelname=name, + model_nam_file="{}.nam".format(name), + save_flows=True, + ) + + # dis + botm = ( + np.ones((nlay, nrow, ncol)) + * np.arange(nlay - 1, -1, -1)[:, np.newaxis, np.newaxis] + ) + dis = flopy.mf6.ModflowGwfdis( + gwf, + nlay=nlay, + nrow=nrow, + ncol=ncol, + top=nlay, + botm=botm, + ) + + # initial conditions + h0 = nlay * 2 + start = h0 * np.ones((nlay, nrow, ncol)) + ic = flopy.mf6.ModflowGwfic(gwf, pname="ic", strt=start) + + # constant head + chd_rec = [] + max_dim = max(nlay, nrow, ncol) + h = np.linspace(11, 13, max_dim) + iface = 6 # top + for i in range(0, max_dim): + # ((layer,row,col),head,iface) + cell_id = ( + (0, 0, i) if ncol > 1 else (0, i, 0) if nrow > 1 else (i, 0, 0) + ) + chd_rec.append((cell_id, h[i], iface)) + chd = flopy.mf6.ModflowGwfchd( + gwf, + auxiliary=[("iface",)], + stress_period_data=chd_rec, + print_input=True, + print_flows=True, + save_flows=True, + ) + + # node property flow + npf = flopy.mf6.ModflowGwfnpf(gwf, save_specific_discharge=True) + + # output control + budgetfile = "{}.cbb".format(name) + budget_filerecord = [budgetfile] + saverecord = [("BUDGET", "ALL")] + oc = flopy.mf6.ModflowGwfoc( + gwf, + saverecord=saverecord, + budget_filerecord=budget_filerecord, + ) + + # solver + ims = flopy.mf6.ModflowIms(sim) + + # write and run the model + sim.write_simulation() + sim.check() + success, buff = sim.run_simulation() + assert success + + # load budget output + budget = gwf.output.budget() + flow_ja_face = budget.get_data(text="FLOW-JA-FACE")[0] + frf, fff, flf = get_structured_faceflows( + flow_ja_face, + grb_file=function_tmpdir / f"{gwf.name}.dis.grb", + verbose=True, + ) + + # expect nonzero flows only in extended (>1 cell) dimensions + assert np.any(frf) == (ncol > 1) + assert np.any(fff) == (nrow > 1) + assert np.any(flf) == (nlay > 1) + + +@pytest.mark.mf6 +@requires_exe("mf6") +def test_get_structured_faceflows_freyberg( + function_tmpdir, mf2005_freyberg_path, mf6_freyberg_path +): + # create workspaces + mf6_ws = function_tmpdir / "mf6" + mf2005_ws = function_tmpdir / "mf2005" + + # run freyberg mf6 sim = MFSimulation.load( sim_name="freyberg", exe_name="mf6", sim_ws=mf6_freyberg_path, ) - - # change the simulation workspace - sim.set_sim_path(function_tmpdir) - - # write the model simulation files + sim.set_sim_path(mf6_ws) sim.write_simulation() - - # run the simulation sim.run_simulation() - # get output + # get freyberg mf6 output and compute structured faceflows gwf = sim.get_model("freyberg") - head = gwf.output.head().get_data() - cbc = gwf.output.budget() + mf6_head = gwf.output.head().get_data() + mf6_cbc = gwf.output.budget() + mf6_spdis = mf6_cbc.get_data(text="DATA-SPDIS")[0] + mf6_flowja = mf6_cbc.get_data(text="FLOW-JA-FACE")[0] + mf6_frf, mf6_fff, mf6_flf = get_structured_faceflows( + mf6_flowja, + grb_file=mf6_ws / "freyberg.dis.grb", + ) + assert mf6_frf.shape == mf6_fff.shape == mf6_flf.shape == mf6_head.shape + assert not np.any(mf6_flf) # only 1 layer + + # run freyberg mf2005 + model = Modflow.load("freyberg", model_ws=mf2005_freyberg_path) + model.change_model_ws(mf2005_ws) + model.write_input() + model.run_model() + + # get freyberg mf2005 output + mf2005_cbc = flopy.utils.CellBudgetFile(mf2005_ws / "freyberg.cbc") + mf2005_frf, mf2005_fff = ( + mf2005_cbc.get_data(text="FLOW RIGHT FACE", full3D=True)[0], + mf2005_cbc.get_data(text="FLOW FRONT FACE", full3D=True)[0], + ) - spdis = cbc.get_data(text="DATA-SPDIS")[0] - flowja = cbc.get_data(text="FLOW-JA-FACE")[0] + # compare mf2005 faceflows with converted mf6 faceflows + assert mf2005_frf.shape == mf2005_fff.shape == mf6_head.shape + assert np.allclose(mf6_frf, np.flip(mf2005_frf, 0), atol=1e-3) + assert np.allclose(mf6_fff, np.flip(mf2005_fff, 0), atol=1e-3) - frf, fff, flf = get_structured_faceflows( - flowja, - grb_file=function_tmpdir / "freyberg.dis.grb", - ) Qx, Qy, Qz = get_specific_discharge( - (frf, fff, flf), + (mf6_frf, mf6_fff, mf6_flf), gwf, ) sqx, sqy, sqz = get_specific_discharge( - (frf, fff, flf), + (mf6_frf, mf6_fff, mf6_flf), gwf, - head=head, + head=mf6_head, ) - qx, qy, qz = get_specific_discharge(spdis, gwf) + qx, qy, qz = get_specific_discharge(mf6_spdis, gwf) fig = plt.figure(figsize=(12, 6), constrained_layout=True) ax = fig.add_subplot(1, 3, 1, aspect="equal") @@ -88,6 +228,7 @@ def test_faceflows(function_tmpdir, mf6_freyberg_path): q1 = mm.plot_vector(qx, qy) assert isinstance(q1, matplotlib.quiver.Quiver) + # plt.show() plt.close("all") # uv0 = np.column_stack((q0.U, q0.V)) @@ -96,7 +237,6 @@ def test_faceflows(function_tmpdir, mf6_freyberg_path): # assert ( # np.allclose(uv0, uv1) # ), "get_faceflows quivers are not equal to specific discharge vectors" - return @pytest.mark.mf6 @@ -149,7 +289,7 @@ def test_flowja_residuals(function_tmpdir, mf6_freyberg_path): @pytest.mark.mf6 @requires_exe("mf6") -def test_structured_faceflows_3d(function_tmpdir): +def test_structured_faceflows_3d_shape(function_tmpdir): name = "mymodel" sim = MFSimulation(sim_name=name, sim_ws=function_tmpdir, exe_name="mf6") tdis = ModflowTdis(sim) diff --git a/code.json b/code.json index 0ba0adfdb..b7b4f1605 100644 --- a/code.json +++ b/code.json @@ -29,9 +29,9 @@ "downloadURL": "https://code.usgs.gov/usgs/modflow/flopy/archive/master.zip", "vcs": "git", "laborHours": -1, - "version": "3.4.2", + "version": "3.4.3", "date": { - "metadataLastUpdated": "2023-08-25" + "metadataLastUpdated": "2023-09-30" }, "organization": "U.S. Geological Survey", "permissions": { diff --git a/docs/PyPI_release.md b/docs/PyPI_release.md index 55a9bea16..315be7329 100644 --- a/docs/PyPI_release.md +++ b/docs/PyPI_release.md @@ -30,7 +30,7 @@ How to Cite *Software/Code citation for FloPy:* -[Bakker, Mark, Post, Vincent, Hughes, J. D., Langevin, C. D., White, J. T., Leaf, A. T., Paulinski, S. R., Bellino, J. C., Morway, E. D., Toews, M. W., Larsen, J. D., Fienen, M. N., Starn, J. J., Brakenhoff, D. A., and Bonelli, W. P., 2023, FloPy v3.4.2: U.S. Geological Survey Software Release, 25 August 2023, https://doi.org/10.5066/F7BK19FH](https://doi.org/10.5066/F7BK19FH) +[Bakker, Mark, Post, Vincent, Hughes, J. D., Langevin, C. D., White, J. T., Leaf, A. T., Paulinski, S. R., Bellino, J. C., Morway, E. D., Toews, M. W., Larsen, J. D., Fienen, M. N., Starn, J. J., Brakenhoff, D. A., and Bonelli, W. P., 2023, FloPy v3.4.3: U.S. Geological Survey Software Release, 30 September 2023, https://doi.org/10.5066/F7BK19FH](https://doi.org/10.5066/F7BK19FH) Disclaimer diff --git a/docs/version_changes.md b/docs/version_changes.md index 3126948f8..daa157368 100644 --- a/docs/version_changes.md +++ b/docs/version_changes.md @@ -1,3 +1,13 @@ +### Version 3.4.3 + +#### Bug fixes + +* [fix(export_contours/f)](https://github.com/modflowpy/flopy/commit/30209f2ca2e69289227203e4afd2f33bfceed097): Support matplotlib 3.8+ (#1951). Committed by wpbonelli on 2023-09-19. +* [fix(resolve_exe)](https://github.com/modflowpy/flopy/commit/3522dced8a49dc93fb0140d9ac360a88f31b11bb): Support extensionless abs/rel paths on windows (#1957). Committed by wpbonelli on 2023-09-24. +* [fix(mbase)](https://github.com/modflowpy/flopy/commit/b848f968af4179d8618b811cd4fe6f8de66d09cb): Warn if duplicate pkgs or units (#1964). Committed by wpbonelli on 2023-09-26. +* [fix(get_structured_faceflows)](https://github.com/modflowpy/flopy/commit/92632d26be2ecb21b6d9d56717faadaa13e08369): Cover edge cases, expand tests (#1968). Committed by wpbonelli on 2023-09-29. +* [fix(CellBudgetFile)](https://github.com/modflowpy/flopy/commit/015d6399baa48819f9f0f78bf2f34f60bdd8ef18): Detect compact fmt by negative nlay (#1966). Committed by wpbonelli on 2023-09-30. + ### Version 3.4.2 #### Bug fixes diff --git a/flopy/export/utils.py b/flopy/export/utils.py index 3b94cb10a..c6efd3e16 100644 --- a/flopy/export/utils.py +++ b/flopy/export/utils.py @@ -1,8 +1,10 @@ import os +from itertools import repeat from pathlib import Path -from typing import Optional, Union +from typing import Union import numpy as np +from packaging.version import Version from ..datbase import DataInterface, DataListInterface, DataType from ..mbase import BaseModel, ModelInterface @@ -1693,6 +1695,7 @@ def export_contours( filename: Union[str, os.PathLike], contours, fieldname="level", + verbose=False, **kwargs, ): """ @@ -1706,6 +1709,8 @@ def export_contours( (object returned by matplotlib.pyplot.contour) fieldname : str gis attribute table field name + verbose : bool, optional, default False + whether to show verbose output **kwargs : key-word arguments to flopy.export.shapefile_utils.recarray2shp Returns @@ -1713,26 +1718,76 @@ def export_contours( df : dataframe of shapefile contents """ + from importlib.metadata import version + + from matplotlib.path import Path + from ..utils.geometry import LineString from .shapefile_utils import recarray2shp if not isinstance(contours, list): contours = [contours] + # Export a linestring for each contour component. + # Levels may have multiple disconnected components. geoms = [] level = [] + + # ContourSet.collections was deprecated with + # matplotlib 3.8. ContourSet is a collection + # of Paths, where each Path corresponds to a + # contour level, and may contain one or more + # (possibly disconnected) components. Before + # 3.8, iterating over ContourSet.collections + # and enumerating from get_paths() suffices, + # but post-3.8, we have to walk the segments + # to distinguish disconnected components. + mpl_ver = Version(version("matplotlib")) + for ctr in contours: - levels = ctr.levels - for i, c in enumerate(ctr.collections): - paths = c.get_paths() - geoms += [LineString(p.vertices) for p in paths] - level += list(np.ones(len(paths)) * levels[i]) + if mpl_ver < Version("3.8.0"): + levels = ctr.levels + for i, c in enumerate(ctr.collections): + paths = c.get_paths() + geoms += [LineString(p.vertices) for p in paths] + level += list(np.ones(len(paths)) * levels[i]) + else: + paths = ctr.get_paths() + for pi, path in enumerate(paths): + # skip empty paths + if path.vertices.shape[0] == 0: + continue + + # Each Path may contain multiple components + # so we unpack them as separate geometries. + lines = [] + segs = [] + for seg in path.iter_segments(): + pts, code = seg + if code == Path.MOVETO: + if len(segs) > 0: + lines.append(LineString(segs)) + segs = [] + segs.append(pts) + elif code == Path.LINETO: + segs.append(pts) + elif code == Path.CLOSEPOLY: + segs.append(pts) + segs.append(segs[0]) # add closing segment + lines.append(LineString(segs)) + segs = [] + if len(segs) > 0: + lines.append(LineString(segs)) + + level += list(np.ones(len(lines)) * ctr.levels[pi]) + geoms += lines + + if verbose: + print(f"Writing {len(level)} contour lines") - # convert the dictionary to a recarray ra = np.array(level, dtype=[(fieldname, float)]).view(np.recarray) recarray2shp(ra, geoms, filename, **kwargs) - return def export_contourf( @@ -1769,57 +1824,99 @@ def export_contourf( >>> export_contourf('myfilledcontours.shp', cs) """ + from importlib.metadata import version + + from matplotlib.path import Path + from ..utils.geometry import Polygon, is_clockwise from .shapefile_utils import recarray2shp + if not isinstance(contours, list): + contours = [contours] + + # export a polygon for each filled contour geoms = [] level = [] - if not isinstance(contours, list): - contours = [contours] + # ContourSet.collections was deprecated with + # matplotlib 3.8. ContourSet is a collection + # of Paths, where each Path corresponds to a + # contour level, and may contain one or more + # (possibly disconnected) components. Before + # 3.8, iterating over ContourSet.collections + # and enumerating from get_paths() suffices, + # but post-3.8, we have to walk the segments + # to distinguish disconnected components. + mpl_ver = Version(version("matplotlib")) - for c in contours: - levels = c.levels - for idx, col in enumerate(c.collections): - # Loop through all polygons that have the same intensity level - for contour_path in col.get_paths(): - # Create the polygon(s) for this intensity level - poly = None - for ncp, cp in enumerate(contour_path.to_polygons()): - x = cp[:, 0] - y = cp[:, 1] - verts = [(i[0], i[1]) for i in zip(x, y)] - new_shape = Polygon(verts) - - if ncp == 0: - poly = new_shape - else: - # check if this is a multipolygon by checking vertex - # order. - if is_clockwise(verts): - # Clockwise is a hole, set to interiors - if not poly.interiors: - poly.interiors = [new_shape.exterior] - else: - poly.interiors.append(new_shape.exterior) - else: - geoms.append(poly) - level.append(levels[idx]) + for ctr in contours: + if mpl_ver < Version("3.8.0"): + levels = ctr.levels + for idx, col in enumerate(ctr.collections): + for contour_path in col.get_paths(): + # Create the polygon(s) for this intensity level + poly = None + for ncp, cp in enumerate(contour_path.to_polygons()): + x = cp[:, 0] + y = cp[:, 1] + verts = [(i[0], i[1]) for i in zip(x, y)] + new_shape = Polygon(verts) + + if ncp == 0: poly = new_shape + else: + # check if this is a multipolygon by checking vertex + # order. + if is_clockwise(verts): + # Clockwise is a hole, set to interiors + if not poly.interiors: + poly.interiors = [new_shape.exterior] + else: + poly.interiors.append(new_shape.exterior) + else: + geoms.append(poly) + level.append(levels[idx]) + poly = new_shape - if poly is not None: - # store geometry object - geoms.append(poly) + if poly is not None: + # store geometry object + geoms.append(poly) level.append(levels[idx]) + else: + paths = ctr.get_paths() + for pi, path in enumerate(paths): + # skip empty paths + if path.vertices.shape[0] == 0: + continue + + polys = [] + segs = [] + for seg in path.iter_segments(): + pts, code = seg + if code == Path.MOVETO: + if len(segs) > 0: + polys.append(Polygon(segs)) + segs = [] + segs.append(pts) + elif code == Path.LINETO: + segs.append(pts) + elif code == Path.CLOSEPOLY: + segs.append(pts) + segs.append(segs[0]) # add closing segment + polys.append(Polygon(segs)) + segs = [] + if len(segs) > 0: + polys.append(Polygon(segs)) + + geoms.extend(polys) + level.extend(repeat(ctr.levels[pi], len(polys))) if verbose: print(f"Writing {len(level)} polygons") - # Create recarray ra = np.array(level, dtype=[(fieldname, float)]).view(np.recarray) recarray2shp(ra, geoms, filename, **kwargs) - return def export_array_contours( diff --git a/flopy/mbase.py b/flopy/mbase.py index 846bc6fca..c44dac910 100644 --- a/flopy/mbase.py +++ b/flopy/mbase.py @@ -26,8 +26,10 @@ from .utils import flopy_io from .version import __version__ +on_windows = sys.platform.startswith("win") + # Prepend flopy appdir bin directory to PATH to work with "get-modflow :flopy" -if sys.platform.startswith("win"): +if on_windows: flopy_bin = os.path.expandvars(r"%LOCALAPPDATA%\flopy\bin") else: flopy_bin = os.path.join(os.path.expanduser("~"), ".local/share/flopy/bin") @@ -62,35 +64,46 @@ def resolve_exe( str: absolute path to the executable """ - exe_name = str(exe_name) - exe = which(exe_name) - if exe is not None: - # in case which() returned a relative path, resolve it - exe = which(str(Path(exe).resolve())) - else: - if exe_name.lower().endswith(".exe"): - # try removing .exe suffix - exe = which(exe_name[:-4]) + def _resolve(exe_name): + exe = which(exe_name) if exe is not None: - # in case which() returned a relative path, resolve it + # if which() returned a relative path, resolve it exe = which(str(Path(exe).resolve())) else: - # try tilde-expanded abspath - exe = which(Path(exe_name).expanduser().absolute()) - if exe is None and exe_name.lower().endswith(".exe"): - # try tilde-expanded abspath without .exe suffix - exe = which(Path(exe_name[:-4]).expanduser().absolute()) - if exe is None: + if exe_name.lower().endswith(".exe"): + # try removing .exe suffix + exe = which(exe_name[:-4]) + if exe is not None: + # in case which() returned a relative path, resolve it + exe = which(str(Path(exe).resolve())) + else: + # try tilde-expanded abspath + exe = which(Path(exe_name).expanduser().absolute()) + if exe is None and exe_name.lower().endswith(".exe"): + # try tilde-expanded abspath without .exe suffix + exe = which(Path(exe_name[:-4]).expanduser().absolute()) + return exe + + name = str(exe_name) + exe_path = _resolve(name) + if exe_path is None and on_windows and Path(name).suffix == "": + # try adding .exe suffix on windows (for portability from other OS) + exe_path = _resolve(f"{name}.exe") + + # raise if we are unforgiving, otherwise return None + if exe_path is None: if forgive: warn( - f"The program {exe_name} does not exist or is not executable." + f"The program {exe_name} does not exist or is not executable.", + category=UserWarning, ) return None raise FileNotFoundError( f"The program {exe_name} does not exist or is not executable." ) - return exe + + return exe_path # external exceptions for users @@ -404,7 +417,8 @@ def __init__( except: warn( f"\n{model_ws} not valid, " - f"workspace-folder was changed to {os.getcwd()}\n" + f"workspace-folder was changed to {os.getcwd()}\n", + category=UserWarning, ) model_ws = os.getcwd() self._model_ws = str(model_ws) @@ -635,20 +649,20 @@ def add_package(self, p): pn = p.name[idx] except: pn = p.name - if self.verbose: - print( - f"\nWARNING:\n unit {u} of package {pn} already in use." - ) + warn( + f"Unit {u} of package {pn} already in use.", + category=UserWarning, + ) self.package_units.append(u) for i, pp in enumerate(self.packagelist): if pp.allowDuplicates: continue elif isinstance(p, type(pp)): - if self.verbose: - print( - "\nWARNING:\n Two packages of the same type, " - f"Replacing existing '{p.name[0]}' package." - ) + warn( + "Two packages of the same type, " + f"Replacing existing '{p.name[0]}' package.", + category=UserWarning, + ) self.packagelist[i] = p return if self.verbose: diff --git a/flopy/mf6/modflow/mfems.py b/flopy/mf6/modflow/mfems.py index a75fbc5e1..b3fa1f522 100644 --- a/flopy/mf6/modflow/mfems.py +++ b/flopy/mf6/modflow/mfems.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on August 25, 2023 23:00:27 UTC +# FILE created on September 30, 2023 14:44:04 UTC from .. import mfpackage diff --git a/flopy/mf6/modflow/mfgnc.py b/flopy/mf6/modflow/mfgnc.py index b3da2b859..a5206142c 100644 --- a/flopy/mf6/modflow/mfgnc.py +++ b/flopy/mf6/modflow/mfgnc.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on August 25, 2023 23:00:27 UTC +# FILE created on September 30, 2023 14:44:04 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/flopy/mf6/modflow/mfgwf.py b/flopy/mf6/modflow/mfgwf.py index 9c5cc500b..3d9f8d167 100644 --- a/flopy/mf6/modflow/mfgwf.py +++ b/flopy/mf6/modflow/mfgwf.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on August 25, 2023 23:00:27 UTC +# FILE created on September 30, 2023 14:44:04 UTC from .. import mfmodel from ..data.mfdatautil import ArrayTemplateGenerator, ListTemplateGenerator diff --git a/flopy/mf6/modflow/mfgwfapi.py b/flopy/mf6/modflow/mfgwfapi.py index 2fbb5e105..1a8e17645 100644 --- a/flopy/mf6/modflow/mfgwfapi.py +++ b/flopy/mf6/modflow/mfgwfapi.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on August 25, 2023 23:00:28 UTC +# FILE created on September 30, 2023 14:44:04 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/flopy/mf6/modflow/mfgwfbuy.py b/flopy/mf6/modflow/mfgwfbuy.py index 9e7e8f3fa..bda007d81 100644 --- a/flopy/mf6/modflow/mfgwfbuy.py +++ b/flopy/mf6/modflow/mfgwfbuy.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on August 25, 2023 23:00:28 UTC +# FILE created on September 30, 2023 14:44:04 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/flopy/mf6/modflow/mfgwfchd.py b/flopy/mf6/modflow/mfgwfchd.py index d3c7654ad..dd5864bcd 100644 --- a/flopy/mf6/modflow/mfgwfchd.py +++ b/flopy/mf6/modflow/mfgwfchd.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on August 25, 2023 23:00:27 UTC +# FILE created on September 30, 2023 14:44:04 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/flopy/mf6/modflow/mfgwfcsub.py b/flopy/mf6/modflow/mfgwfcsub.py index 43073af3d..a1204cbc7 100644 --- a/flopy/mf6/modflow/mfgwfcsub.py +++ b/flopy/mf6/modflow/mfgwfcsub.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on August 25, 2023 23:00:28 UTC +# FILE created on September 30, 2023 14:44:04 UTC from .. import mfpackage from ..data.mfdatautil import ArrayTemplateGenerator, ListTemplateGenerator diff --git a/flopy/mf6/modflow/mfgwfdis.py b/flopy/mf6/modflow/mfgwfdis.py index 583b6d15d..1e33334a1 100644 --- a/flopy/mf6/modflow/mfgwfdis.py +++ b/flopy/mf6/modflow/mfgwfdis.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on August 25, 2023 23:00:27 UTC +# FILE created on September 30, 2023 14:44:04 UTC from .. import mfpackage from ..data.mfdatautil import ArrayTemplateGenerator diff --git a/flopy/mf6/modflow/mfgwfdisu.py b/flopy/mf6/modflow/mfgwfdisu.py index eb6a5ae45..5a9ac212b 100644 --- a/flopy/mf6/modflow/mfgwfdisu.py +++ b/flopy/mf6/modflow/mfgwfdisu.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on August 25, 2023 23:00:27 UTC +# FILE created on September 30, 2023 14:44:04 UTC from .. import mfpackage from ..data.mfdatautil import ArrayTemplateGenerator, ListTemplateGenerator diff --git a/flopy/mf6/modflow/mfgwfdisv.py b/flopy/mf6/modflow/mfgwfdisv.py index 7b6a3cb78..4e4d2dfe3 100644 --- a/flopy/mf6/modflow/mfgwfdisv.py +++ b/flopy/mf6/modflow/mfgwfdisv.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on August 25, 2023 23:00:27 UTC +# FILE created on September 30, 2023 14:44:04 UTC from .. import mfpackage from ..data.mfdatautil import ArrayTemplateGenerator, ListTemplateGenerator diff --git a/flopy/mf6/modflow/mfgwfdrn.py b/flopy/mf6/modflow/mfgwfdrn.py index 87d73562a..741c2f6fb 100644 --- a/flopy/mf6/modflow/mfgwfdrn.py +++ b/flopy/mf6/modflow/mfgwfdrn.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on August 25, 2023 23:00:27 UTC +# FILE created on September 30, 2023 14:44:04 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/flopy/mf6/modflow/mfgwfevt.py b/flopy/mf6/modflow/mfgwfevt.py index 48ca63400..c72356732 100644 --- a/flopy/mf6/modflow/mfgwfevt.py +++ b/flopy/mf6/modflow/mfgwfevt.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on August 25, 2023 23:00:27 UTC +# FILE created on September 30, 2023 14:44:04 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/flopy/mf6/modflow/mfgwfevta.py b/flopy/mf6/modflow/mfgwfevta.py index e17975132..26ade65cf 100644 --- a/flopy/mf6/modflow/mfgwfevta.py +++ b/flopy/mf6/modflow/mfgwfevta.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on August 25, 2023 23:00:27 UTC +# FILE created on September 30, 2023 14:44:04 UTC from .. import mfpackage from ..data.mfdatautil import ArrayTemplateGenerator, ListTemplateGenerator diff --git a/flopy/mf6/modflow/mfgwfghb.py b/flopy/mf6/modflow/mfgwfghb.py index 8d11af146..4db50892a 100644 --- a/flopy/mf6/modflow/mfgwfghb.py +++ b/flopy/mf6/modflow/mfgwfghb.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on August 25, 2023 23:00:27 UTC +# FILE created on September 30, 2023 14:44:04 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/flopy/mf6/modflow/mfgwfgnc.py b/flopy/mf6/modflow/mfgwfgnc.py index f16e30f8e..3802a3672 100644 --- a/flopy/mf6/modflow/mfgwfgnc.py +++ b/flopy/mf6/modflow/mfgwfgnc.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on August 25, 2023 23:00:28 UTC +# FILE created on September 30, 2023 14:44:04 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/flopy/mf6/modflow/mfgwfgwf.py b/flopy/mf6/modflow/mfgwfgwf.py index 5d427823b..c8f56e372 100644 --- a/flopy/mf6/modflow/mfgwfgwf.py +++ b/flopy/mf6/modflow/mfgwfgwf.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on August 25, 2023 23:00:27 UTC +# FILE created on September 30, 2023 14:44:04 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/flopy/mf6/modflow/mfgwfgwt.py b/flopy/mf6/modflow/mfgwfgwt.py index 5c4839e79..0b736c156 100644 --- a/flopy/mf6/modflow/mfgwfgwt.py +++ b/flopy/mf6/modflow/mfgwfgwt.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on August 25, 2023 23:00:27 UTC +# FILE created on September 30, 2023 14:44:04 UTC from .. import mfpackage diff --git a/flopy/mf6/modflow/mfgwfhfb.py b/flopy/mf6/modflow/mfgwfhfb.py index 53d73cd86..afce6426a 100644 --- a/flopy/mf6/modflow/mfgwfhfb.py +++ b/flopy/mf6/modflow/mfgwfhfb.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on August 25, 2023 23:00:27 UTC +# FILE created on September 30, 2023 14:44:04 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/flopy/mf6/modflow/mfgwfic.py b/flopy/mf6/modflow/mfgwfic.py index 75554b6ec..fe8dbe984 100644 --- a/flopy/mf6/modflow/mfgwfic.py +++ b/flopy/mf6/modflow/mfgwfic.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on August 25, 2023 23:00:27 UTC +# FILE created on September 30, 2023 14:44:04 UTC from .. import mfpackage from ..data.mfdatautil import ArrayTemplateGenerator diff --git a/flopy/mf6/modflow/mfgwflak.py b/flopy/mf6/modflow/mfgwflak.py index 7dd3476ed..26138668f 100644 --- a/flopy/mf6/modflow/mfgwflak.py +++ b/flopy/mf6/modflow/mfgwflak.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on August 25, 2023 23:00:28 UTC +# FILE created on September 30, 2023 14:44:04 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/flopy/mf6/modflow/mfgwfmaw.py b/flopy/mf6/modflow/mfgwfmaw.py index 72bc13ccf..762472241 100644 --- a/flopy/mf6/modflow/mfgwfmaw.py +++ b/flopy/mf6/modflow/mfgwfmaw.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on August 25, 2023 23:00:28 UTC +# FILE created on September 30, 2023 14:44:04 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/flopy/mf6/modflow/mfgwfmvr.py b/flopy/mf6/modflow/mfgwfmvr.py index 0ecd694d5..203d57f32 100644 --- a/flopy/mf6/modflow/mfgwfmvr.py +++ b/flopy/mf6/modflow/mfgwfmvr.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on August 25, 2023 23:00:28 UTC +# FILE created on September 30, 2023 14:44:04 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/flopy/mf6/modflow/mfgwfnam.py b/flopy/mf6/modflow/mfgwfnam.py index 86a8dd46a..b01c1741f 100644 --- a/flopy/mf6/modflow/mfgwfnam.py +++ b/flopy/mf6/modflow/mfgwfnam.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on August 25, 2023 23:00:27 UTC +# FILE created on September 30, 2023 14:44:04 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/flopy/mf6/modflow/mfgwfnpf.py b/flopy/mf6/modflow/mfgwfnpf.py index c601e4642..56c886882 100644 --- a/flopy/mf6/modflow/mfgwfnpf.py +++ b/flopy/mf6/modflow/mfgwfnpf.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on August 25, 2023 23:00:27 UTC +# FILE created on September 30, 2023 14:44:04 UTC from .. import mfpackage from ..data.mfdatautil import ArrayTemplateGenerator, ListTemplateGenerator diff --git a/flopy/mf6/modflow/mfgwfoc.py b/flopy/mf6/modflow/mfgwfoc.py index b8f2352db..347a0d938 100644 --- a/flopy/mf6/modflow/mfgwfoc.py +++ b/flopy/mf6/modflow/mfgwfoc.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on August 25, 2023 23:00:28 UTC +# FILE created on September 30, 2023 14:44:04 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/flopy/mf6/modflow/mfgwfrch.py b/flopy/mf6/modflow/mfgwfrch.py index 3fdc69052..d512bb1be 100644 --- a/flopy/mf6/modflow/mfgwfrch.py +++ b/flopy/mf6/modflow/mfgwfrch.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on August 25, 2023 23:00:27 UTC +# FILE created on September 30, 2023 14:44:04 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/flopy/mf6/modflow/mfgwfrcha.py b/flopy/mf6/modflow/mfgwfrcha.py index ead28e748..e6034848a 100644 --- a/flopy/mf6/modflow/mfgwfrcha.py +++ b/flopy/mf6/modflow/mfgwfrcha.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on August 25, 2023 23:00:27 UTC +# FILE created on September 30, 2023 14:44:04 UTC from .. import mfpackage from ..data.mfdatautil import ArrayTemplateGenerator, ListTemplateGenerator diff --git a/flopy/mf6/modflow/mfgwfriv.py b/flopy/mf6/modflow/mfgwfriv.py index c38073f68..7417d4453 100644 --- a/flopy/mf6/modflow/mfgwfriv.py +++ b/flopy/mf6/modflow/mfgwfriv.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on August 25, 2023 23:00:27 UTC +# FILE created on September 30, 2023 14:44:04 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/flopy/mf6/modflow/mfgwfsfr.py b/flopy/mf6/modflow/mfgwfsfr.py index eff474703..24655b69e 100644 --- a/flopy/mf6/modflow/mfgwfsfr.py +++ b/flopy/mf6/modflow/mfgwfsfr.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on August 25, 2023 23:00:28 UTC +# FILE created on September 30, 2023 14:44:04 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/flopy/mf6/modflow/mfgwfsto.py b/flopy/mf6/modflow/mfgwfsto.py index 617c4ccad..2bdb75f27 100644 --- a/flopy/mf6/modflow/mfgwfsto.py +++ b/flopy/mf6/modflow/mfgwfsto.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on August 25, 2023 23:00:27 UTC +# FILE created on September 30, 2023 14:44:04 UTC from .. import mfpackage from ..data.mfdatautil import ArrayTemplateGenerator, ListTemplateGenerator diff --git a/flopy/mf6/modflow/mfgwfuzf.py b/flopy/mf6/modflow/mfgwfuzf.py index cec6ae87c..4fea151fe 100644 --- a/flopy/mf6/modflow/mfgwfuzf.py +++ b/flopy/mf6/modflow/mfgwfuzf.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on August 25, 2023 23:00:28 UTC +# FILE created on September 30, 2023 14:44:04 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/flopy/mf6/modflow/mfgwfvsc.py b/flopy/mf6/modflow/mfgwfvsc.py index 1cda4b286..5285cbb72 100644 --- a/flopy/mf6/modflow/mfgwfvsc.py +++ b/flopy/mf6/modflow/mfgwfvsc.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on August 25, 2023 23:00:28 UTC +# FILE created on September 30, 2023 14:44:04 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/flopy/mf6/modflow/mfgwfwel.py b/flopy/mf6/modflow/mfgwfwel.py index e101db5b5..ae14cd206 100644 --- a/flopy/mf6/modflow/mfgwfwel.py +++ b/flopy/mf6/modflow/mfgwfwel.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on August 25, 2023 23:00:27 UTC +# FILE created on September 30, 2023 14:44:04 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/flopy/mf6/modflow/mfgwt.py b/flopy/mf6/modflow/mfgwt.py index 37c0bacee..517eb771e 100644 --- a/flopy/mf6/modflow/mfgwt.py +++ b/flopy/mf6/modflow/mfgwt.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on August 25, 2023 23:00:28 UTC +# FILE created on September 30, 2023 14:44:04 UTC from .. import mfmodel from ..data.mfdatautil import ArrayTemplateGenerator, ListTemplateGenerator diff --git a/flopy/mf6/modflow/mfgwtadv.py b/flopy/mf6/modflow/mfgwtadv.py index 32f9d005c..9003e73c8 100644 --- a/flopy/mf6/modflow/mfgwtadv.py +++ b/flopy/mf6/modflow/mfgwtadv.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on August 25, 2023 23:00:28 UTC +# FILE created on September 30, 2023 14:44:04 UTC from .. import mfpackage diff --git a/flopy/mf6/modflow/mfgwtapi.py b/flopy/mf6/modflow/mfgwtapi.py index affba6912..b5ed4050c 100644 --- a/flopy/mf6/modflow/mfgwtapi.py +++ b/flopy/mf6/modflow/mfgwtapi.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on August 25, 2023 23:00:28 UTC +# FILE created on September 30, 2023 14:44:04 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/flopy/mf6/modflow/mfgwtcnc.py b/flopy/mf6/modflow/mfgwtcnc.py index b47f9325e..fb3b823b6 100644 --- a/flopy/mf6/modflow/mfgwtcnc.py +++ b/flopy/mf6/modflow/mfgwtcnc.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on August 25, 2023 23:00:28 UTC +# FILE created on September 30, 2023 14:44:04 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/flopy/mf6/modflow/mfgwtdis.py b/flopy/mf6/modflow/mfgwtdis.py index 38e0746e6..dc66d78ad 100644 --- a/flopy/mf6/modflow/mfgwtdis.py +++ b/flopy/mf6/modflow/mfgwtdis.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on August 25, 2023 23:00:28 UTC +# FILE created on September 30, 2023 14:44:04 UTC from .. import mfpackage from ..data.mfdatautil import ArrayTemplateGenerator diff --git a/flopy/mf6/modflow/mfgwtdisu.py b/flopy/mf6/modflow/mfgwtdisu.py index a28827577..03fcf41cf 100644 --- a/flopy/mf6/modflow/mfgwtdisu.py +++ b/flopy/mf6/modflow/mfgwtdisu.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on August 25, 2023 23:00:28 UTC +# FILE created on September 30, 2023 14:44:04 UTC from .. import mfpackage from ..data.mfdatautil import ArrayTemplateGenerator, ListTemplateGenerator diff --git a/flopy/mf6/modflow/mfgwtdisv.py b/flopy/mf6/modflow/mfgwtdisv.py index 071467786..a65194bad 100644 --- a/flopy/mf6/modflow/mfgwtdisv.py +++ b/flopy/mf6/modflow/mfgwtdisv.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on August 25, 2023 23:00:28 UTC +# FILE created on September 30, 2023 14:44:04 UTC from .. import mfpackage from ..data.mfdatautil import ArrayTemplateGenerator, ListTemplateGenerator diff --git a/flopy/mf6/modflow/mfgwtdsp.py b/flopy/mf6/modflow/mfgwtdsp.py index f841cf798..ad263956e 100644 --- a/flopy/mf6/modflow/mfgwtdsp.py +++ b/flopy/mf6/modflow/mfgwtdsp.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on August 25, 2023 23:00:28 UTC +# FILE created on September 30, 2023 14:44:04 UTC from .. import mfpackage from ..data.mfdatautil import ArrayTemplateGenerator diff --git a/flopy/mf6/modflow/mfgwtfmi.py b/flopy/mf6/modflow/mfgwtfmi.py index b8333dece..3eeabfaea 100644 --- a/flopy/mf6/modflow/mfgwtfmi.py +++ b/flopy/mf6/modflow/mfgwtfmi.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on August 25, 2023 23:00:28 UTC +# FILE created on September 30, 2023 14:44:04 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/flopy/mf6/modflow/mfgwtgwt.py b/flopy/mf6/modflow/mfgwtgwt.py index 959f2a411..98bd1ce7a 100644 --- a/flopy/mf6/modflow/mfgwtgwt.py +++ b/flopy/mf6/modflow/mfgwtgwt.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on August 25, 2023 23:00:27 UTC +# FILE created on September 30, 2023 14:44:04 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/flopy/mf6/modflow/mfgwtic.py b/flopy/mf6/modflow/mfgwtic.py index 171bab192..1c8527100 100644 --- a/flopy/mf6/modflow/mfgwtic.py +++ b/flopy/mf6/modflow/mfgwtic.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on August 25, 2023 23:00:28 UTC +# FILE created on September 30, 2023 14:44:04 UTC from .. import mfpackage from ..data.mfdatautil import ArrayTemplateGenerator diff --git a/flopy/mf6/modflow/mfgwtist.py b/flopy/mf6/modflow/mfgwtist.py index 3f1d126e4..3018130b0 100644 --- a/flopy/mf6/modflow/mfgwtist.py +++ b/flopy/mf6/modflow/mfgwtist.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on August 25, 2023 23:00:28 UTC +# FILE created on September 30, 2023 14:44:04 UTC from .. import mfpackage from ..data.mfdatautil import ArrayTemplateGenerator, ListTemplateGenerator diff --git a/flopy/mf6/modflow/mfgwtlkt.py b/flopy/mf6/modflow/mfgwtlkt.py index dd22f9220..89b2d6816 100644 --- a/flopy/mf6/modflow/mfgwtlkt.py +++ b/flopy/mf6/modflow/mfgwtlkt.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on August 25, 2023 23:00:28 UTC +# FILE created on September 30, 2023 14:44:04 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/flopy/mf6/modflow/mfgwtmst.py b/flopy/mf6/modflow/mfgwtmst.py index 93cff4e6d..ffe1b4791 100644 --- a/flopy/mf6/modflow/mfgwtmst.py +++ b/flopy/mf6/modflow/mfgwtmst.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on August 25, 2023 23:00:28 UTC +# FILE created on September 30, 2023 14:44:04 UTC from .. import mfpackage from ..data.mfdatautil import ArrayTemplateGenerator diff --git a/flopy/mf6/modflow/mfgwtmvt.py b/flopy/mf6/modflow/mfgwtmvt.py index 33e86b080..cf7b668ff 100644 --- a/flopy/mf6/modflow/mfgwtmvt.py +++ b/flopy/mf6/modflow/mfgwtmvt.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on August 25, 2023 23:00:28 UTC +# FILE created on September 30, 2023 14:44:04 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/flopy/mf6/modflow/mfgwtmwt.py b/flopy/mf6/modflow/mfgwtmwt.py index c1d573c53..41c7c33bf 100644 --- a/flopy/mf6/modflow/mfgwtmwt.py +++ b/flopy/mf6/modflow/mfgwtmwt.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on August 25, 2023 23:00:28 UTC +# FILE created on September 30, 2023 14:44:04 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/flopy/mf6/modflow/mfgwtnam.py b/flopy/mf6/modflow/mfgwtnam.py index 1ed27c5c2..218b89545 100644 --- a/flopy/mf6/modflow/mfgwtnam.py +++ b/flopy/mf6/modflow/mfgwtnam.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on August 25, 2023 23:00:28 UTC +# FILE created on September 30, 2023 14:44:04 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/flopy/mf6/modflow/mfgwtoc.py b/flopy/mf6/modflow/mfgwtoc.py index 2637402c3..bffcd7c22 100644 --- a/flopy/mf6/modflow/mfgwtoc.py +++ b/flopy/mf6/modflow/mfgwtoc.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on August 25, 2023 23:00:28 UTC +# FILE created on September 30, 2023 14:44:04 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/flopy/mf6/modflow/mfgwtsft.py b/flopy/mf6/modflow/mfgwtsft.py index 5c4356d1a..a46c886cf 100644 --- a/flopy/mf6/modflow/mfgwtsft.py +++ b/flopy/mf6/modflow/mfgwtsft.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on August 25, 2023 23:00:28 UTC +# FILE created on September 30, 2023 14:44:04 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/flopy/mf6/modflow/mfgwtsrc.py b/flopy/mf6/modflow/mfgwtsrc.py index afbc3de3d..6cbab49a5 100644 --- a/flopy/mf6/modflow/mfgwtsrc.py +++ b/flopy/mf6/modflow/mfgwtsrc.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on August 25, 2023 23:00:28 UTC +# FILE created on September 30, 2023 14:44:04 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/flopy/mf6/modflow/mfgwtssm.py b/flopy/mf6/modflow/mfgwtssm.py index 9e23f0d6c..592b090bb 100644 --- a/flopy/mf6/modflow/mfgwtssm.py +++ b/flopy/mf6/modflow/mfgwtssm.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on August 25, 2023 23:00:28 UTC +# FILE created on September 30, 2023 14:44:04 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/flopy/mf6/modflow/mfgwtuzt.py b/flopy/mf6/modflow/mfgwtuzt.py index 7556150f6..5750e46a2 100644 --- a/flopy/mf6/modflow/mfgwtuzt.py +++ b/flopy/mf6/modflow/mfgwtuzt.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on August 25, 2023 23:00:28 UTC +# FILE created on September 30, 2023 14:44:04 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/flopy/mf6/modflow/mfims.py b/flopy/mf6/modflow/mfims.py index a80681e5d..80e0f905c 100644 --- a/flopy/mf6/modflow/mfims.py +++ b/flopy/mf6/modflow/mfims.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on August 25, 2023 23:00:27 UTC +# FILE created on September 30, 2023 14:44:04 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/flopy/mf6/modflow/mfmvr.py b/flopy/mf6/modflow/mfmvr.py index 19e0b4c6c..8a3846eda 100644 --- a/flopy/mf6/modflow/mfmvr.py +++ b/flopy/mf6/modflow/mfmvr.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on August 25, 2023 23:00:27 UTC +# FILE created on September 30, 2023 14:44:04 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/flopy/mf6/modflow/mfmvt.py b/flopy/mf6/modflow/mfmvt.py index 9b3facc2c..372294b09 100644 --- a/flopy/mf6/modflow/mfmvt.py +++ b/flopy/mf6/modflow/mfmvt.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on August 25, 2023 23:00:27 UTC +# FILE created on September 30, 2023 14:44:04 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/flopy/mf6/modflow/mfnam.py b/flopy/mf6/modflow/mfnam.py index d355a3c59..780f56a36 100644 --- a/flopy/mf6/modflow/mfnam.py +++ b/flopy/mf6/modflow/mfnam.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on August 25, 2023 23:00:27 UTC +# FILE created on September 30, 2023 14:44:04 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/flopy/mf6/modflow/mftdis.py b/flopy/mf6/modflow/mftdis.py index 6da201fb4..ee7a280b8 100644 --- a/flopy/mf6/modflow/mftdis.py +++ b/flopy/mf6/modflow/mftdis.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on August 25, 2023 23:00:27 UTC +# FILE created on September 30, 2023 14:44:04 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/flopy/mf6/modflow/mfutlats.py b/flopy/mf6/modflow/mfutlats.py index cba03823c..8fd34420f 100644 --- a/flopy/mf6/modflow/mfutlats.py +++ b/flopy/mf6/modflow/mfutlats.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on August 25, 2023 23:00:27 UTC +# FILE created on September 30, 2023 14:44:04 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/flopy/mf6/modflow/mfutllaktab.py b/flopy/mf6/modflow/mfutllaktab.py index ab6d26a79..ca634be4d 100644 --- a/flopy/mf6/modflow/mfutllaktab.py +++ b/flopy/mf6/modflow/mfutllaktab.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on August 25, 2023 23:00:27 UTC +# FILE created on September 30, 2023 14:44:04 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/flopy/mf6/modflow/mfutlobs.py b/flopy/mf6/modflow/mfutlobs.py index 5c2388ff2..687ee545c 100644 --- a/flopy/mf6/modflow/mfutlobs.py +++ b/flopy/mf6/modflow/mfutlobs.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on August 25, 2023 23:00:27 UTC +# FILE created on September 30, 2023 14:44:04 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/flopy/mf6/modflow/mfutlsfrtab.py b/flopy/mf6/modflow/mfutlsfrtab.py index 8bbcbcc91..04b8db647 100644 --- a/flopy/mf6/modflow/mfutlsfrtab.py +++ b/flopy/mf6/modflow/mfutlsfrtab.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on August 25, 2023 23:00:27 UTC +# FILE created on September 30, 2023 14:44:04 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/flopy/mf6/modflow/mfutlspc.py b/flopy/mf6/modflow/mfutlspc.py index f6a6a2713..0616bda59 100644 --- a/flopy/mf6/modflow/mfutlspc.py +++ b/flopy/mf6/modflow/mfutlspc.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on August 25, 2023 23:00:27 UTC +# FILE created on September 30, 2023 14:44:04 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/flopy/mf6/modflow/mfutlspca.py b/flopy/mf6/modflow/mfutlspca.py index ddf1681b2..b49074124 100644 --- a/flopy/mf6/modflow/mfutlspca.py +++ b/flopy/mf6/modflow/mfutlspca.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on August 25, 2023 23:00:27 UTC +# FILE created on September 30, 2023 14:44:04 UTC from .. import mfpackage from ..data.mfdatautil import ArrayTemplateGenerator, ListTemplateGenerator diff --git a/flopy/mf6/modflow/mfutltas.py b/flopy/mf6/modflow/mfutltas.py index 11a5c0c51..2db3efb6f 100644 --- a/flopy/mf6/modflow/mfutltas.py +++ b/flopy/mf6/modflow/mfutltas.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on August 25, 2023 23:00:27 UTC +# FILE created on September 30, 2023 14:44:04 UTC from .. import mfpackage from ..data.mfdatautil import ArrayTemplateGenerator, ListTemplateGenerator diff --git a/flopy/mf6/modflow/mfutlts.py b/flopy/mf6/modflow/mfutlts.py index ec5258b45..b6ddc5f47 100644 --- a/flopy/mf6/modflow/mfutlts.py +++ b/flopy/mf6/modflow/mfutlts.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on August 25, 2023 23:00:27 UTC +# FILE created on September 30, 2023 14:44:04 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/flopy/mf6/modflow/mfutltvk.py b/flopy/mf6/modflow/mfutltvk.py index d82859181..01f9a782e 100644 --- a/flopy/mf6/modflow/mfutltvk.py +++ b/flopy/mf6/modflow/mfutltvk.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on August 25, 2023 23:00:27 UTC +# FILE created on September 30, 2023 14:44:04 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/flopy/mf6/modflow/mfutltvs.py b/flopy/mf6/modflow/mfutltvs.py index 806803271..e0f4cb6a9 100644 --- a/flopy/mf6/modflow/mfutltvs.py +++ b/flopy/mf6/modflow/mfutltvs.py @@ -1,6 +1,6 @@ # DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY # mf6/utils/createpackages.py -# FILE created on August 25, 2023 23:00:27 UTC +# FILE created on September 30, 2023 14:44:04 UTC from .. import mfpackage from ..data.mfdatautil import ListTemplateGenerator diff --git a/flopy/mf6/utils/postprocessing.py b/flopy/mf6/utils/postprocessing.py index df8299780..a5b00a9b4 100644 --- a/flopy/mf6/utils/postprocessing.py +++ b/flopy/mf6/utils/postprocessing.py @@ -4,7 +4,14 @@ def get_structured_faceflows( - flowja, grb_file=None, ia=None, ja=None, verbose=False + flowja, + grb_file=None, + ia=None, + ja=None, + nlay=None, + nrow=None, + ncol=None, + verbose=False, ): """ Get the face flows for the flow right face, flow front face, and @@ -22,6 +29,12 @@ def get_structured_faceflows( CRS row pointers. Only required if grb_file is not provided. ja : list or ndarray CRS column pointers. Only required if grb_file is not provided. + nlay : int + number of layers in the grid. Only required if grb_file is not provided. + nrow : int + number of rows in the grid. Only required if grb_file is not provided. + ncol : int + number of columns in the grid. Only required if grb_file is not provided. verbose: bool Write information to standard output @@ -43,11 +56,19 @@ def get_structured_faceflows( "is only for structured DIS grids" ) ia, ja = grb.ia, grb.ja + nlay, nrow, ncol = grb.nlay, grb.nrow, grb.ncol else: - if ia is None or ja is None: + if ( + ia is None + or ja is None + or nlay is None + or nrow is None + or ncol is None + ): raise ValueError( - "ia and ja arrays must be specified if the MODFLOW 6" - "binary grid file name is not specified." + "ia, ja, nlay, nrow, and ncol must be" + "specified if a MODFLOW 6 binary grid" + "file name is not specified." ) # flatten flowja, if necessary @@ -57,27 +78,71 @@ def get_structured_faceflows( # evaluate size of flowja relative to ja __check_flowja_size(flowja, ja) - # create face flow arrays - shape = (grb.nlay, grb.nrow, grb.ncol) - frf = np.zeros(shape, dtype=float).flatten() - fff = np.zeros(shape, dtype=float).flatten() - flf = np.zeros(shape, dtype=float).flatten() + # create empty flat face flow arrays + shape = (nlay, nrow, ncol) + frf = np.zeros(shape, dtype=float).flatten() # right + fff = np.zeros(shape, dtype=float).flatten() # front + flf = np.zeros(shape, dtype=float).flatten() # lower + + def get_face(m, n, nlay, nrow, ncol): + """ + Determine connection direction at (m, n) + in a connection or intercell flow matrix. + + Notes + ----- + For visual intuition in 2 dimensions + https://stackoverflow.com/a/16330162/6514033 + helps. MODFLOW uses the left-side scheme in 3D. + + Parameters + ---------- + m : int + row index + n : int + column index + nlay : int + number of layers in the grid + nrow : int + number of rows in the grid + ncol : int + number of columns in the grid + + Returns + ------- + face : int + 0: right, 1: front, 2: lower + """ + + d = m - n + if d == 1: + # handle 1D cases + if nrow == 1 and ncol == 1: + return 2 + elif nlay == 1 and ncol == 1: + return 1 + elif nlay == 1 and nrow == 1: + return 0 + else: + # handle 2D layers/rows case + return 1 if ncol == 1 else 0 + elif d == nrow * ncol: + return 2 + else: + return 1 - # fill flow terms - vmult = [-1.0, -1.0, -1.0] + # fill right, front and lower face flows + # (below main diagonal) flows = [frf, fff, flf] for n in range(grb.nodes): - i0, i1 = ia[n] + 1, ia[n + 1] - for j in range(i0, i1): - jcol = ja[j] - if jcol > n: - if jcol == n + 1: - ipos = 0 - elif jcol == n + grb.ncol: - ipos = 1 - else: - ipos = 2 - flows[ipos][n] = vmult[ipos] * flowja[j] + for i in range(ia[n] + 1, ia[n + 1]): + m = ja[i] + if m <= n: + continue + face = get_face(m, n, nlay, nrow, ncol) + flows[face][n] = -1 * flowja[i] + + # reshape and return return frf.reshape(shape), fff.reshape(shape), flf.reshape(shape) diff --git a/flopy/mfusg/mfusgbcf.py b/flopy/mfusg/mfusgbcf.py index 231e80d1e..6bda77d7c 100644 --- a/flopy/mfusg/mfusgbcf.py +++ b/flopy/mfusg/mfusgbcf.py @@ -219,7 +219,7 @@ def __init__( locat=self.unit_number[0], ) if not structured: - self.ksat = Util3d( + self.ksat = Util2d( model, (njag,), np.float32, diff --git a/flopy/modflow/mfsfr2.py b/flopy/modflow/mfsfr2.py index cf8355c01..ef8d8a657 100644 --- a/flopy/modflow/mfsfr2.py +++ b/flopy/modflow/mfsfr2.py @@ -181,6 +181,16 @@ class ModflowSfr2(Package): Numpy record array of length equal to nss, with columns for each variable entered in items 6a, 6b and 6c (see SFR package input instructions). Segment numbers are one-based. + channel_geometry_data : dict of dicts containing lists + Optional. Outer dictionary keyed by stress period (0-based); inner + dictionaries keyed by segment number (1-based), for which 8-point channel + cross section geometries are desired. Inner dict values are lists of shape + (2,8) - with the first dimension referring to two lists: one of 8 XCPT + values, and the other of 8 ZCPT values. + Example structure: {kper: {segment: [[xcpt1...xcpt8],[zcpt1...zcpt8]]}}. + Note that for these to be applied, the user must also specify an icalc + value of 2 for each corresponding segment in segment_data for the + relevant stress periods. dataset_5 : dict of lists Optional; will be built automatically from segment_data unless specified. Dict of lists, with key for each stress period. Each list diff --git a/flopy/utils/binaryfile.py b/flopy/utils/binaryfile.py index db7ffaf9f..a1c2029bf 100644 --- a/flopy/utils/binaryfile.py +++ b/flopy/utils/binaryfile.py @@ -786,6 +786,7 @@ def __init__( self.imethlist = [] self.paknamlist = [] self.nrecords = 0 + self.compact = True # compact budget file flag self.dis = None self.modelgrid = None @@ -980,7 +981,9 @@ def _build_index(self): header = self._get_header() self.nrecords += 1 totim = header["totim"] - if totim == 0: + # if old-style (non-compact) file, + # compute totim from kstp and kper + if not self.compact: totim = self._totim_from_kstpkper( (header["kstp"] - 1, header["kper"] - 1) ) @@ -1133,7 +1136,8 @@ def _get_header(self): """ header1 = binaryread(self.file, self.header1_dtype, (1,)) nlay = header1["nlay"] - if nlay < 0: + self.compact = bool(nlay < 0) + if self.compact: # fill header2 by first reading imeth, delt, pertim and totim # and then adding modelnames and paknames if imeth = 6 temp = binaryread(self.file, self.header2_dtype0, (1,)) diff --git a/flopy/version.py b/flopy/version.py index e88b55a2c..8c76397b2 100644 --- a/flopy/version.py +++ b/flopy/version.py @@ -1,3 +1,3 @@ -# flopy version file automatically created using update_version.py on August 25, 2023 23:00:24 +# flopy version file automatically created using update_version.py on September 30, 2023 14:44:00 -__version__ = "3.4.2" +__version__ = "3.4.3" diff --git a/version.txt b/version.txt index a423d4217..8a0feb98c 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -3.4.2 \ No newline at end of file +3.4.3 \ No newline at end of file