diff --git a/.docs/Notebooks/mf_error_tutorial01.py b/.docs/Notebooks/mf_error_tutorial01.py index 94851c8786..367b5775fc 100644 --- a/.docs/Notebooks/mf_error_tutorial01.py +++ b/.docs/Notebooks/mf_error_tutorial01.py @@ -79,6 +79,7 @@ try: import pandas as pd + summary_pth = os.path.join(workspace, "checksummary.csv") df = pd.read_csv(summary_pth) except: diff --git a/.docs/Notebooks/mf_watertable_recharge_example.py b/.docs/Notebooks/mf_watertable_recharge_example.py index 814e2f6faa..e357d66665 100644 --- a/.docs/Notebooks/mf_watertable_recharge_example.py +++ b/.docs/Notebooks/mf_watertable_recharge_example.py @@ -66,12 +66,7 @@ def analytical_water_table_solution(h1, h2, z, R, K, L, x): # x -= dx b1 = h1 - z b2 = h2 - z - h = ( - np.sqrt( - b1**2 - (x / L) * (b1**2 - b2**2) + (R * x / K) * (L - x) - ) - + z - ) + h = np.sqrt(b1**2 - (x / L) * (b1**2 - b2**2) + (R * x / K) * (L - x)) + z return h diff --git a/.gitignore b/.gitignore index 3f1996eb74..fea24ed341 100644 --- a/.gitignore +++ b/.gitignore @@ -97,4 +97,7 @@ venv app # IDE files -.vscode \ No newline at end of file +.vscode + +# mac files +**.DS_Store \ No newline at end of file diff --git a/autotest/test_copy.py b/autotest/test_copy.py index ee8cdf9264..476a560ab5 100644 --- a/autotest/test_copy.py +++ b/autotest/test_copy.py @@ -1,5 +1,6 @@ """Test copying of flopy objects. """ + import copy import inspect diff --git a/autotest/test_geospatial_util.py b/autotest/test_geospatial_util.py index 2d0508c1ed..d029334fd0 100644 --- a/autotest/test_geospatial_util.py +++ b/autotest/test_geospatial_util.py @@ -397,7 +397,7 @@ def test_polygon_collection(polygon, poly_w_hole, multipolygon): assert is_equal, "GeoSpatialCollection Polygon conversion error" -@requires_pkg("shapely", "geojson") +@requires_pkg("shapely", "geojson", "geopandas") def test_point_collection(point, multipoint): col = [Shape.from_geojson(point), Shape.from_geojson(multipoint)] @@ -427,7 +427,7 @@ def test_point_collection(point, multipoint): ) -@requires_pkg("shapely", "geojson") +@requires_pkg("shapely", "geojson", "geopandas") def test_linestring_collection(linestring, multilinestring): col = [Shape.from_geojson(linestring), Shape.from_geojson(multilinestring)] @@ -457,7 +457,7 @@ def test_linestring_collection(linestring, multilinestring): ) -@requires_pkg("shapely", "geojson") +@requires_pkg("shapely", "geojson", "geopandas") def test_mixed_collection( polygon, poly_w_hole, diff --git a/autotest/test_get_modflow.py b/autotest/test_get_modflow.py index 3228dce218..ca161a04d7 100644 --- a/autotest/test_get_modflow.py +++ b/autotest/test_get_modflow.py @@ -1,4 +1,5 @@ """Test get-modflow utility.""" + import os import platform import sys @@ -20,9 +21,11 @@ flopy_dir = get_project_root_path() get_modflow_script = flopy_dir / "flopy" / "utils" / "get_modflow.py" bindir_options = { - "flopy": Path(expandvars(r"%LOCALAPPDATA%\flopy")) / "bin" - if system() == "Windows" - else Path.home() / ".local" / "share" / "flopy" / "bin", + "flopy": ( + Path(expandvars(r"%LOCALAPPDATA%\flopy")) / "bin" + if system() == "Windows" + else Path.home() / ".local" / "share" / "flopy" / "bin" + ), "python": Path(sys.prefix) / ("Scripts" if system() == "Windows" else "bin"), "home": Path.home() / ".local" / "bin", diff --git a/autotest/test_grid.py b/autotest/test_grid.py index 523441514f..d6c89f2334 100644 --- a/autotest/test_grid.py +++ b/autotest/test_grid.py @@ -4,7 +4,6 @@ from contextlib import nullcontext from warnings import warn -import geopandas import matplotlib import numpy as np import pytest @@ -14,11 +13,11 @@ from matplotlib import pyplot as plt from modflow_devtools.markers import requires_exe, requires_pkg from modflow_devtools.misc import has_pkg -from pytest_cases import parametrize_with_cases from flopy.discretization import StructuredGrid, UnstructuredGrid, VertexGrid from flopy.mf6 import MFSimulation from flopy.modflow import Modflow, ModflowDis +from flopy.utils import import_optional_dependency from flopy.utils.crs import get_authority_crs from flopy.utils.cvfdutil import gridlist_to_disv_gridprops, to_cvfd from flopy.utils.triangle import Triangle @@ -1090,7 +1089,17 @@ def test_voronoi_vertex_grid(function_tmpdir): @flaky @requires_exe("triangle") @requires_pkg("shapely", "scipy") -@parametrize_with_cases("grid_info", cases=GridCases, prefix="voronoi") +@pytest.mark.parametrize( + "grid_info", + [ + GridCases.voronoi_polygon(), + GridCases.voronoi_rectangle(), + GridCases.voronoi_circle(), + GridCases.voronoi_nested_circles(), + GridCases.voronoi_polygons(), + GridCases.voronoi_many_polygons(), + ], +) def test_voronoi_grid(request, function_tmpdir, grid_info): name = ( request.node.name.replace("/", "_") @@ -1239,13 +1248,11 @@ def test_unstructured_neighbors(unstructured_grid): queen_neighbors = unstructured_grid.neighbors( 5, method="queen", reset=True ) - assert np.allclose( - queen_neighbors, [0, 10, 1, 6, 11, 2, 3, 7, 8, 12, 13] - ) + assert np.allclose(queen_neighbors, [0, 10, 1, 6, 11, 2, 3, 7, 8, 12, 13]) -@parametrize_with_cases("grid", cases=GridCases, prefix="structured_cbd") -def test_structured_ncb_thickness(grid): +def test_structured_ncb_thickness(): + grid = GridCases.structured_cbd_small() thickness = grid.cell_thickness assert thickness.shape[0] == grid.nlay + np.count_nonzero( @@ -1267,7 +1274,9 @@ def test_structured_ncb_thickness(grid): ), "saturated_thickness is not properly indexing confining beds" -@parametrize_with_cases("grid", cases=GridCases, prefix="unstructured") +@pytest.mark.parametrize( + "grid", [GridCases.unstructured_small(), GridCases.unstructured_medium()] +) def test_unstructured_iverts(grid): iverts = grid.iverts assert not any( @@ -1275,21 +1284,30 @@ def test_unstructured_iverts(grid): ), "None type should not be returned in iverts list" -@parametrize_with_cases("grid", cases=GridCases, prefix="structured") +@pytest.mark.parametrize( + "grid", [GridCases.structured_small(), GridCases.structured_cbd_small()] +) def test_get_lni_structured(grid): for nn in range(0, grid.nnodes): layer, i = grid.get_lni([nn])[0] assert layer * grid.ncpl + i == nn -@parametrize_with_cases("grid", cases=GridCases, prefix="vertex") +@pytest.mark.parametrize( + "grid", + [ + GridCases.vertex_small(), + ], +) def test_get_lni_vertex(grid): for nn in range(0, grid.nnodes): layer, i = grid.get_lni([nn])[0] assert layer * grid.ncpl + i == nn -@parametrize_with_cases("grid", cases=GridCases, prefix="unstructured") +@pytest.mark.parametrize( + "grid", [GridCases.unstructured_small(), GridCases.unstructured_medium()] +) def test_get_lni_unstructured(grid): for nn in range(0, grid.nnodes): layer, i = grid.get_lni([nn])[0] @@ -1344,11 +1362,8 @@ def test_unstructured_convert(unstructured_grid): @requires_pkg("geopandas") def test_geo_dataframe(structured_grid, vertex_grid, unstructured_grid): - grids = ( - structured_grid, - vertex_grid, - unstructured_grid - ) + geopandas = import_optional_dependency("geopandas") + grids = (structured_grid, vertex_grid, unstructured_grid) for grid in grids: gdf = grid.geo_dataframe diff --git a/autotest/test_grid_cases.py b/autotest/test_grid_cases.py index 1db81a37e4..00c778a29c 100644 --- a/autotest/test_grid_cases.py +++ b/autotest/test_grid_cases.py @@ -1,3 +1,6 @@ +from pathlib import Path +from tempfile import TemporaryDirectory + import numpy as np from flopy.discretization import StructuredGrid, UnstructuredGrid, VertexGrid @@ -6,7 +9,8 @@ class GridCases: - def structured_small(self): + @staticmethod + def structured_small(): nlay, nrow, ncol = 3, 2, 3 delc = 1.0 * np.ones(nrow, dtype=float) delr = 1.0 * np.ones(ncol, dtype=float) @@ -24,10 +28,11 @@ def structured_small(self): delr=delr, top=top, botm=botm, - idomain=idomain + idomain=idomain, ) - def structured_cbd_small(self): + @staticmethod + def structured_cbd_small(): nlay = 3 nrow = ncol = 15 laycbd = np.array([1, 2, 0], dtype=int) @@ -61,7 +66,8 @@ def structured_cbd_small(self): laycbd=laycbd, ) - def vertex_small(self): + @staticmethod + def vertex_small(): nlay, ncpl = 3, 5 vertices = [ [0, 0.0, 3.0], @@ -96,10 +102,11 @@ def vertex_small(self): cell2d=cell2d, top=top, botm=botm, - idomain=idomain + idomain=idomain, ) - def unstructured_small(self): + @staticmethod + def unstructured_small(): nlay = 3 ncpl = [5, 5, 5] vertices = [ @@ -164,10 +171,11 @@ def unstructured_small(self): ncpl=ncpl, top=top.flatten(), botm=botm.flatten(), - idomain=idomain.flatten() + idomain=idomain.flatten(), ) - def unstructured_medium(self): + @staticmethod + def unstructured_medium(): iverts = [ [4, 3, 2, 1, 0, None], [7, 0, 1, 6, 5, None], @@ -211,7 +219,8 @@ def unstructured_medium(self): return UnstructuredGrid(verts, iverts, ncpl=[len(iverts)]) - def voronoi_polygon(self, function_tmpdir): + @staticmethod + def voronoi_polygon(): ncpl = 3803 domain = [ [1831.381546, 6335.543757], @@ -237,18 +246,20 @@ def voronoi_polygon(self, function_tmpdir): max_area = 100.0**2 angle = 30 - tri = Triangle( - maximum_area=max_area, angle=angle, model_ws=str(function_tmpdir) - ) - tri.add_polygon(poly) - tri.build(verbose=False) - vor = VoronoiGrid(tri) - gridprops = vor.get_gridprops_vertexgrid() - grid = VertexGrid(**gridprops, nlay=1) + with TemporaryDirectory() as tempdir: + tri = Triangle( + maximum_area=max_area, angle=angle, model_ws=str(Path(tempdir)) + ) + tri.add_polygon(poly) + tri.build(verbose=False) + vor = VoronoiGrid(tri) + gridprops = vor.get_gridprops_vertexgrid() + grid = VertexGrid(**gridprops, nlay=1) return ncpl, vor, gridprops, grid - def voronoi_rectangle(self, function_tmpdir): + @staticmethod + def voronoi_rectangle(): ncpl = 1679 xmin = 0.0 xmax = 2.0 @@ -260,18 +271,20 @@ def voronoi_rectangle(self, function_tmpdir): max_area = 0.001 angle = 30 - tri = Triangle( - maximum_area=max_area, angle=angle, model_ws=str(function_tmpdir) - ) - tri.add_polygon(poly) - tri.build(verbose=False) - vor = VoronoiGrid(tri) - gridprops = vor.get_gridprops_vertexgrid() - grid = VertexGrid(**gridprops, nlay=1) + with TemporaryDirectory() as tempdir: + tri = Triangle( + maximum_area=max_area, angle=angle, model_ws=str(Path(tempdir)) + ) + tri.add_polygon(poly) + tri.build(verbose=False) + vor = VoronoiGrid(tri) + gridprops = vor.get_gridprops_vertexgrid() + grid = VertexGrid(**gridprops, nlay=1) return ncpl, vor, gridprops, grid - def voronoi_circle(self, function_tmpdir): + @staticmethod + def voronoi_circle(): ncpl = 538 theta = np.arange(0.0, 2 * np.pi, 0.2) radius = 100.0 @@ -281,18 +294,20 @@ def voronoi_circle(self, function_tmpdir): max_area = 50 angle = 30 - tri = Triangle( - maximum_area=max_area, angle=angle, model_ws=str(function_tmpdir) - ) - tri.add_polygon(poly) - tri.build(verbose=False) - vor = VoronoiGrid(tri) - gridprops = vor.get_gridprops_vertexgrid() - grid = VertexGrid(**gridprops, nlay=1) + with TemporaryDirectory() as tempdir: + tri = Triangle( + maximum_area=max_area, angle=angle, model_ws=str(Path(tempdir)) + ) + tri.add_polygon(poly) + tri.build(verbose=False) + vor = VoronoiGrid(tri) + gridprops = vor.get_gridprops_vertexgrid() + grid = VertexGrid(**gridprops, nlay=1) return ncpl, vor, gridprops, grid - def voronoi_nested_circles(self, function_tmpdir): + @staticmethod + def voronoi_nested_circles(): ncpl = 300 theta = np.arange(0.0, 2 * np.pi, 0.2) @@ -311,86 +326,92 @@ def voronoi_nested_circles(self, function_tmpdir): max_area = 100 angle = 30 - tri = Triangle( - maximum_area=max_area, angle=angle, model_ws=str(function_tmpdir) - ) - for poly in polys: - tri.add_polygon(poly) - tri.add_hole((25, 25)) - tri.build(verbose=False) - vor = VoronoiGrid(tri) - gridprops = vor.get_gridprops_vertexgrid() - grid = VertexGrid(**gridprops, nlay=1) + with TemporaryDirectory() as tempdir: + tri = Triangle( + maximum_area=max_area, angle=angle, model_ws=str(Path(tempdir)) + ) + for poly in polys: + tri.add_polygon(poly) + tri.add_hole((25, 25)) + tri.build(verbose=False) + vor = VoronoiGrid(tri) + gridprops = vor.get_gridprops_vertexgrid() + grid = VertexGrid(**gridprops, nlay=1) return ncpl, vor, gridprops, grid - def voronoi_polygons(self, function_tmpdir): + @staticmethod + def voronoi_polygons(): ncpl = 410 active_domain = [(0, 0), (100, 0), (100, 100), (0, 100)] area1 = [(10, 10), (40, 10), (40, 40), (10, 40)] area2 = [(60, 60), (80, 60), (80, 80), (60, 80)] - tri = Triangle(angle=30, model_ws=str(function_tmpdir)) - tri.add_polygon(active_domain) - tri.add_polygon(area1) - tri.add_polygon(area2) - tri.add_region( - (1, 1), 0, maximum_area=100 - ) # point inside active domain - tri.add_region((11, 11), 1, maximum_area=10) # point inside area1 - tri.add_region((61, 61), 2, maximum_area=3) # point inside area2 - tri.build(verbose=False) - vor = VoronoiGrid(tri) - gridprops = vor.get_gridprops_vertexgrid() - grid = VertexGrid(**gridprops, nlay=1) + + with TemporaryDirectory() as tempdir: + tri = Triangle(angle=30, model_ws=str(Path(tempdir))) + tri.add_polygon(active_domain) + tri.add_polygon(area1) + tri.add_polygon(area2) + tri.add_region( + (1, 1), 0, maximum_area=100 + ) # point inside active domain + tri.add_region((11, 11), 1, maximum_area=10) # point inside area1 + tri.add_region((61, 61), 2, maximum_area=3) # point inside area2 + tri.build(verbose=False) + vor = VoronoiGrid(tri) + gridprops = vor.get_gridprops_vertexgrid() + grid = VertexGrid(**gridprops, nlay=1) return ncpl, vor, gridprops, grid - def voronoi_many_polygons(self, function_tmpdir): + @staticmethod + def voronoi_many_polygons(): ncpl = 1305 active_domain = [(0, 0), (100, 0), (100, 100), (0, 100)] area1 = [(10, 10), (40, 10), (40, 40), (10, 40)] area2 = [(70, 70), (90, 70), (90, 90), (70, 90)] - tri = Triangle(angle=30, model_ws=str(function_tmpdir)) - - # requirement that active_domain is first polygon to be added - tri.add_polygon(active_domain) - - # requirement that any holes be added next - theta = np.arange(0.0, 2 * np.pi, 0.2) - radius = 10.0 - x = radius * np.cos(theta) + 50.0 - y = radius * np.sin(theta) + 70.0 - circle_poly0 = [(x, y) for x, y in zip(x, y)] - tri.add_polygon(circle_poly0) - tri.add_hole((50, 70)) - - # Add a polygon to force cells to conform to it - theta = np.arange(0.0, 2 * np.pi, 0.2) - radius = 10.0 - x = radius * np.cos(theta) + 70.0 - y = radius * np.sin(theta) + 20.0 - circle_poly1 = [(x, y) for x, y in zip(x, y)] - tri.add_polygon(circle_poly1) - # tri.add_hole((70, 20)) - - # add line through domain to force conforming cells - line = [(x, x) for x in np.linspace(11, 89, 100)] - tri.add_polygon(line) - - # then regions and other polygons should follow - tri.add_polygon(area1) - tri.add_polygon(area2) - tri.add_region( - (1, 1), 0, maximum_area=100 - ) # point inside active domain - tri.add_region((11, 11), 1, maximum_area=10) # point inside area1 - tri.add_region((70, 70), 2, maximum_area=1) # point inside area2 - - tri.build(verbose=False) - - vor = VoronoiGrid(tri) - gridprops = vor.get_gridprops_vertexgrid() - grid = VertexGrid(**gridprops, nlay=1) + with TemporaryDirectory() as tempdir: + tri = Triangle(angle=30, model_ws=str(Path(tempdir))) + + # requirement that active_domain is first polygon to be added + tri.add_polygon(active_domain) + + # requirement that any holes be added next + theta = np.arange(0.0, 2 * np.pi, 0.2) + radius = 10.0 + x = radius * np.cos(theta) + 50.0 + y = radius * np.sin(theta) + 70.0 + circle_poly0 = [(x, y) for x, y in zip(x, y)] + tri.add_polygon(circle_poly0) + tri.add_hole((50, 70)) + + # Add a polygon to force cells to conform to it + theta = np.arange(0.0, 2 * np.pi, 0.2) + radius = 10.0 + x = radius * np.cos(theta) + 70.0 + y = radius * np.sin(theta) + 20.0 + circle_poly1 = [(x, y) for x, y in zip(x, y)] + tri.add_polygon(circle_poly1) + # tri.add_hole((70, 20)) + + # add line through domain to force conforming cells + line = [(x, x) for x in np.linspace(11, 89, 100)] + tri.add_polygon(line) + + # then regions and other polygons should follow + tri.add_polygon(area1) + tri.add_polygon(area2) + tri.add_region( + (1, 1), 0, maximum_area=100 + ) # point inside active domain + tri.add_region((11, 11), 1, maximum_area=10) # point inside area1 + tri.add_region((70, 70), 2, maximum_area=1) # point inside area2 + + tri.build(verbose=False) + + vor = VoronoiGrid(tri) + gridprops = vor.get_gridprops_vertexgrid() + grid = VertexGrid(**gridprops, nlay=1) return ncpl, vor, gridprops, grid diff --git a/autotest/test_mfnwt.py b/autotest/test_mfnwt.py index 0366dc3529..b45f0fd116 100644 --- a/autotest/test_mfnwt.py +++ b/autotest/test_mfnwt.py @@ -24,12 +24,7 @@ def analytical_water_table_solution(h1, h2, z, R, K, L, x): h = np.zeros((x.shape[0]), float) b1 = h1 - z b2 = h2 - z - h = ( - np.sqrt( - b1**2 - (x / L) * (b1**2 - b2**2) + (R * x / K) * (L - x) - ) - + z - ) + h = np.sqrt(b1**2 - (x / L) * (b1**2 - b2**2) + (R * x / K) * (L - x)) + z return h diff --git a/autotest/test_mnw.py b/autotest/test_mnw.py index f50036dcdb..20ec79188c 100644 --- a/autotest/test_mnw.py +++ b/autotest/test_mnw.py @@ -349,12 +349,16 @@ def test_mnw2_create_file(function_tmpdir, dataframe): wellids[i], nnodes=nlayers[i], nper=len(stress_period_data.index), - node_data=node_data.to_records(index=False) - if not dataframe - else node_data, - stress_period_data=stress_period_data.to_records(index=False) - if not dataframe - else stress_period_data, + node_data=( + node_data.to_records(index=False) + if not dataframe + else node_data + ), + stress_period_data=( + stress_period_data.to_records(index=False) + if not dataframe + else stress_period_data + ), ) wells.append(wl) diff --git a/autotest/test_mp6.py b/autotest/test_mp6.py index 545ffe70d1..e9f3e59b98 100644 --- a/autotest/test_mp6.py +++ b/autotest/test_mp6.py @@ -1,14 +1,14 @@ import os import shutil +from pprint import pformat +from types import SimpleNamespace import matplotlib.pyplot as plt import numpy as np import pytest from autotest.conftest import get_example_data_path -from autotest.test_mp6_cases import Mp6Cases1, Mp6Cases2 from modflow_devtools.markers import requires_exe, requires_pkg from numpy.lib.recfunctions import repack_fields -from pytest_cases import parametrize_with_cases import flopy from flopy.discretization import StructuredGrid @@ -534,15 +534,126 @@ def eval_timeseries(file): ) +def get_mf2005_model(name, ws, alt=False): + nrow = 3 + ncol = 4 + nlay = 2 + nper = 1 + l1_ibound = np.array( + [[[-1, -1, -1, -1], [-1, 1, 1, -1], [-1, -1, -1, -1]]] + ) + l2_ibound = np.ones((1, nrow, ncol)) + l2_ibound_alt = np.ones((1, nrow, ncol)) + l2_ibound_alt[0, 0, 0] = 0 + bt1 = np.ones((1, nrow, ncol)) + 5 + bt2 = np.ones((1, nrow, ncol)) + 3 + ctx = SimpleNamespace( + nrow=nrow, + ncol=ncol, + nlay=nlay, + nper=nper, + l1_ibound=l1_ibound, + l2_ibound=l2_ibound, + l2_ibound_alt=l2_ibound_alt, + ibound=np.concatenate( + (l1_ibound, l2_ibound_alt if alt else l2_ibound), axis=0 + ), + laytype=[0, 0 if alt else 1], + hnoflow=-888, + hdry=-777, + top=np.zeros((1, nrow, ncol)) + 10, + bt1=bt1, + bt2=bt2, + botm=np.concatenate((bt1, bt2), axis=0), + ipakcb=740, + ) + + # create modflow model + m = flopy.modflow.Modflow( + modelname=name + ("alt" if alt else ""), + namefile_ext="nam", + version="mf2005", + exe_name="mf2005", + model_ws=ws, + ) + + # dis + dis = flopy.modflow.ModflowDis( + model=m, + nlay=nlay, + nrow=nrow, + ncol=ncol, + nper=nper, + delr=1.0, + delc=1.0, + laycbd=0, + top=ctx.top, + botm=ctx.botm, + perlen=1, + nstp=1, + tsmult=1, + steady=True, + ) + + # bas + bas = flopy.modflow.ModflowBas( + model=m, + ibound=ctx.ibound, + strt=10, + ifrefm=True, + ixsec=False, + ichflg=False, + stoper=None, + hnoflo=ctx.hnoflow, + extension="bas", + unitnumber=None, + filenames=None, + ) + # lpf + lpf = flopy.modflow.ModflowLpf( + model=m, + ipakcb=ctx.ipakcb, + laytyp=ctx.laytype, + hk=10, + vka=10, + hdry=ctx.hdry, + ) + + # well + wel = flopy.modflow.ModflowWel( + model=m, + ipakcb=ctx.ipakcb, + stress_period_data={0: [[1, 1, 1, -5.0]]}, + ) + + flopy.modflow.ModflowPcg( + m, hclose=0.001, rclose=0.001, mxiter=150, iter1=30 + ) + + ocspd = {} + for p in range(nper): + ocspd[(p, 0)] = ["save head", "save budget"] + ocspd[(0, 0)] = [ + "save head", + "save budget", + ] # pretty sure it just uses the last for everything + flopy.modflow.ModflowOc(m, stress_period_data=ocspd) + + return m, ctx + + @requires_exe("mf2005", "mp6") -@parametrize_with_cases("ml", cases=Mp6Cases1) -def test_data_pass_no_modflow(ml): +@pytest.mark.parametrize("alt", [True, False]) +def test_data_pass_no_modflow(function_tmpdir, alt): """ test that user can pass and create a mp model without an accompanying modflow model - Returns - ------- - """ + + ml, ctx = get_mf2005_model("data_pass", function_tmpdir, alt) + ml.write_input() + success, buff = ml.run_model() + assert success, pformat(buff) + dis_file = f"{ml.name}.dis" bud_file = f"{ml.name}.cbc" hd_file = f"{ml.name}.hds" @@ -568,30 +679,30 @@ def test_data_pass_no_modflow(ml): assert mp.budget_file == bud_file assert mp.dis_file == dis_file assert mp.nrow_ncol_nlay_nper == ( - Mp6Cases1.nrow, - Mp6Cases1.ncol, - Mp6Cases1.nlay, - Mp6Cases1.nper, + ctx.nrow, + ctx.ncol, + ctx.nlay, + ctx.nper, ) mpbas = flopy.modpath.Modpath6Bas( mp, - hnoflo=Mp6Cases1.hnoflow, - hdry=Mp6Cases1.hdry, + hnoflo=ctx.hnoflow, + hdry=ctx.hdry, def_face_ct=0, bud_label=None, def_iface=None, - laytyp=Mp6Cases1.laytype[ml.name], - ibound=Mp6Cases1.ibound[ml.name], + laytyp=ctx.laytype, + ibound=ctx.ibound, prsity=0.30, prsityCB=0.30, extension="mpbas", unitnumber=86, ) # test layertype is created correctly - assert np.isclose(mpbas.laytyp.array, Mp6Cases1.laytype[ml.name]).all() + assert np.isclose(mpbas.laytyp.array, ctx.laytype).all() # test ibound is pulled from modflow model - assert np.isclose(mpbas.ibound.array, Mp6Cases1.ibound[ml.name]).all() + assert np.isclose(mpbas.ibound.array, ctx.ibound).all() sim = flopy.modpath.Modpath6Sim(model=mp) stl = flopy.modpath.mp6sim.StartingLocationsFile(model=mp) @@ -609,14 +720,17 @@ def test_data_pass_no_modflow(ml): @requires_exe("mf2005", "mp6") -@parametrize_with_cases("ml", cases=Mp6Cases1) -def test_data_pass_with_modflow(ml): +@pytest.mark.parametrize("alt", [True, False]) +def test_data_pass_with_modflow(function_tmpdir, alt): """ test that user specified head files etc. are preferred over files from the modflow model - Returns - ------- - """ + + ml, ctx = get_mf2005_model("data_pass", function_tmpdir, alt) + ml.write_input() + success, buff = ml.run_model() + assert success, pformat(buff) + dis_file = f"{ml.name}.dis" bud_file = f"{ml.name}.cbc" hd_file = f"{ml.name}.hds" @@ -642,21 +756,21 @@ def test_data_pass_with_modflow(ml): assert mp.budget_file == bud_file assert mp.dis_file == dis_file assert mp.nrow_ncol_nlay_nper == ( - Mp6Cases1.nrow, - Mp6Cases1.ncol, - Mp6Cases1.nlay, - Mp6Cases1.nper, + ctx.nrow, + ctx.ncol, + ctx.nlay, + ctx.nper, ) mpbas = flopy.modpath.Modpath6Bas( mp, - hnoflo=Mp6Cases1.hnoflow, - hdry=Mp6Cases1.hdry, + hnoflo=ctx.hnoflow, + hdry=ctx.hdry, def_face_ct=0, bud_label=None, def_iface=None, - laytyp=Mp6Cases1.laytype[ml.name], - ibound=Mp6Cases1.ibound[ml.name], + laytyp=ctx.laytype, + ibound=ctx.ibound, prsity=0.30, prsityCB=0.30, extension="mpbas", @@ -664,9 +778,9 @@ def test_data_pass_with_modflow(ml): ) # test layertype is created correctly! - assert np.isclose(mpbas.laytyp.array, Mp6Cases1.laytype[ml.name]).all() + assert np.isclose(mpbas.laytyp.array, ctx.laytype).all() # test ibound is pulled from modflow model - assert np.isclose(mpbas.ibound.array, Mp6Cases1.ibound[ml.name]).all() + assert np.isclose(mpbas.ibound.array, ctx.ibound).all() sim = flopy.modpath.Modpath6Sim(model=mp) stl = flopy.modpath.mp6sim.StartingLocationsFile(model=mp) @@ -684,14 +798,17 @@ def test_data_pass_with_modflow(ml): @requires_exe("mf2005", "mp6") -@parametrize_with_cases("ml", cases=Mp6Cases1) -def test_just_from_model(ml): +@pytest.mark.parametrize("alt", [True, False]) +def test_just_from_model(function_tmpdir, alt): """ test that user specified head files etc. are preferred over files from the modflow model - Returns - ------- - """ + + ml, ctx = get_mf2005_model("data_pass", function_tmpdir, alt) + ml.write_input() + success, buff = ml.run_model() + assert success, pformat(buff) + dis_file = f"{ml.name}.dis" bud_file = f"{ml.name}.cbc" hd_file = f"{ml.name}.hds" @@ -717,16 +834,16 @@ def test_just_from_model(ml): assert mp.budget_file == bud_file assert mp.dis_file == dis_file assert mp.nrow_ncol_nlay_nper == ( - Mp6Cases1.nrow, - Mp6Cases1.ncol, - Mp6Cases1.nlay, - Mp6Cases1.nper, + ctx.nrow, + ctx.ncol, + ctx.nlay, + ctx.nper, ) mpbas = flopy.modpath.Modpath6Bas( mp, - hnoflo=Mp6Cases1.hnoflow, - hdry=Mp6Cases1.hdry, + hnoflo=ctx.hnoflow, + hdry=ctx.hdry, def_face_ct=0, bud_label=None, def_iface=None, @@ -738,10 +855,10 @@ def test_just_from_model(ml): unitnumber=86, ) # test layertype is created correctly! - assert np.isclose(mpbas.laytyp.array, Mp6Cases1.laytype[ml.name]).all() + assert np.isclose(mpbas.laytyp.array, ctx.laytype).all() # test ibound is pulled from modflow model - assert np.isclose(mpbas.ibound.array, Mp6Cases1.ibound[ml.name]).all() + assert np.isclose(mpbas.ibound.array, ctx.ibound).all() sim = flopy.modpath.Modpath6Sim(model=mp) stl = flopy.modpath.mp6sim.StartingLocationsFile(model=mp) @@ -758,9 +875,9 @@ def test_just_from_model(ml): assert success -def make_mp_model(nm, m, ws, use_pandas): +def get_mp6_model(m, ctx, name, ws, use_pandas): mp = flopy.modpath.Modpath6( - modelname=nm, + modelname=name, simfile_ext="mpsim", namefile_ext="mpnam", version="modpath", @@ -778,13 +895,13 @@ def make_mp_model(nm, m, ws, use_pandas): mpbas = flopy.modpath.Modpath6Bas( mp, - hnoflo=Mp6Cases2.hnoflow, - hdry=Mp6Cases2.hdry, + hnoflo=ctx.hnoflow, + hdry=ctx.hdry, def_face_ct=0, bud_label=None, def_iface=None, - laytyp=Mp6Cases2.laytype["mf1"], - ibound=Mp6Cases2.ibound["mf1"], + laytyp=ctx.laytype, + ibound=ctx.ibound, prsity=0.30, prsityCB=0.30, extension="mpbas", @@ -803,31 +920,30 @@ def make_mp_model(nm, m, ws, use_pandas): stldata[1]["xloc0"] = 0.1 stldata[1]["yloc0"] = 0.2 stl.data = stldata + return mp @requires_exe("mf2005") -@parametrize_with_cases("ml", cases=Mp6Cases2) -def test_mp_wpandas_wo_pandas(ml): - """ - test that user can pass and create a mp model without an accompanying modflow model - Returns - ------- - - """ +def test_mp_pandas(function_tmpdir): + name = "mp_pandas" + ml, ctx = get_mf2005_model(name, function_tmpdir) + ml.write_input() + success, _ = ml.run_model() + assert success - mp_pandas = make_mp_model("pandas", ml, ml.model_ws, use_pandas=True) - mp_no_pandas = make_mp_model( - "no_pandas", ml, ml.model_ws, use_pandas=False + mp_pandas = get_mp6_model(ml, ctx, name, function_tmpdir, use_pandas=True) + mp_no_pandas = get_mp6_model( + ml, ctx, name, function_tmpdir, use_pandas=False ) mp_no_pandas.write_input() success, buff = mp_no_pandas.run_model() - assert success + assert success, pformat(buff) mp_pandas.write_input() success, buff = mp_pandas.run_model() - assert success + assert success, pformat(buff) # read the two files and ensure they are identical with open(mp_pandas.get_package("loc").fn_path) as f: diff --git a/autotest/test_mp6_cases.py b/autotest/test_mp6_cases.py deleted file mode 100644 index ceae0a672c..0000000000 --- a/autotest/test_mp6_cases.py +++ /dev/null @@ -1,297 +0,0 @@ -import numpy as np - -import flopy - - -class Mp6Cases1: - nrow = 3 - ncol = 4 - nlay = 2 - nper = 1 - l1_ibound = np.array( - [[[-1, -1, -1, -1], [-1, 1, 1, -1], [-1, -1, -1, -1]]] - ) - l2_ibound = np.ones((1, nrow, ncol)) - l2_ibound_alt = np.ones((1, nrow, ncol)) - l2_ibound_alt[0, 0, 0] = 0 - ibound = { - "mf1": np.concatenate( - (l1_ibound, l2_ibound), axis=0 - ), # constant heads around model on top row - "mf2": np.concatenate( - (l1_ibound, l2_ibound_alt), axis=0 - ), # constant heads around model on top row - } - laytype = {"mf1": [0, 1], "mf2": [0, 0]} - hnoflow = -888 - hdry = -777 - top = np.zeros((1, nrow, ncol)) + 10 - bt1 = np.ones((1, nrow, ncol)) + 5 - bt2 = np.ones((1, nrow, ncol)) + 3 - botm = np.concatenate((bt1, bt2), axis=0) - ipakcb = 740 - - def case_1(self, function_tmpdir): - m = flopy.modflow.Modflow( - modelname="mf1", - namefile_ext="nam", - version="mf2005", - exe_name="mf2005", - model_ws=function_tmpdir, - ) - - # dis - dis = flopy.modflow.ModflowDis( - model=m, - nlay=self.nlay, - nrow=self.nrow, - ncol=self.ncol, - nper=self.nper, - delr=1.0, - delc=1.0, - laycbd=0, - top=self.top, - botm=self.botm, - perlen=1, - nstp=1, - tsmult=1, - steady=True, - ) - - # bas - bas = flopy.modflow.ModflowBas( - model=m, - ibound=self.ibound[m.name], - strt=10, - ifrefm=True, - ixsec=False, - ichflg=False, - stoper=None, - hnoflo=self.hnoflow, - extension="bas", - unitnumber=None, - filenames=None, - ) - # lpf - lpf = flopy.modflow.ModflowLpf( - model=m, - ipakcb=self.ipakcb, - laytyp=self.laytype[m.name], - hk=10, - vka=10, - hdry=self.hdry, - ) - - # well - wel = flopy.modflow.ModflowWel( - model=m, - ipakcb=self.ipakcb, - stress_period_data={0: [[1, 1, 1, -5.0]]}, - ) - - flopy.modflow.ModflowPcg( - m, - hclose=0.001, - rclose=0.001, - mxiter=150, - iter1=30, - ) - - ocspd = {} - for p in range(self.nper): - ocspd[(p, 0)] = ["save head", "save budget"] - ocspd[(0, 0)] = [ - "save head", - "save budget", - ] # pretty sure it just uses the last for everything - flopy.modflow.ModflowOc(m, stress_period_data=ocspd) - - m.write_input() - success, buff = m.run_model() - assert success - return m - - def case_2(self, function_tmpdir): - m = flopy.modflow.Modflow( - modelname="mf2", - namefile_ext="nam", - version="mf2005", - exe_name="mf2005", - model_ws=function_tmpdir, - ) - - # dis - dis = flopy.modflow.ModflowDis( - model=m, - nlay=self.nlay, - nrow=self.nrow, - ncol=self.ncol, - nper=self.nper, - delr=1.0, - delc=1.0, - laycbd=0, - top=self.top, - botm=self.botm, - perlen=1, - nstp=1, - tsmult=1, - steady=True, - ) - - # bas - bas = flopy.modflow.ModflowBas( - model=m, - ibound=self.ibound[m.name], - strt=10, - ifrefm=True, - ixsec=False, - ichflg=False, - stoper=None, - hnoflo=self.hnoflow, - extension="bas", - unitnumber=None, - filenames=None, - ) - # lpf - lpf = flopy.modflow.ModflowLpf( - model=m, - ipakcb=self.ipakcb, - laytyp=self.laytype[m.name], - hk=10, - vka=10, - hdry=self.hdry, - ) - - # well - wel = flopy.modflow.ModflowWel( - model=m, - ipakcb=self.ipakcb, - stress_period_data={0: [[1, 1, 1, -5.0]]}, - ) - - flopy.modflow.ModflowPcg( - m, - hclose=0.001, - rclose=0.001, - mxiter=150, - iter1=30, - ) - - ocspd = {} - for p in range(self.nper): - ocspd[(p, 0)] = ["save head", "save budget"] - ocspd[(0, 0)] = [ - "save head", - "save budget", - ] # pretty sure it just uses the last for everything - flopy.modflow.ModflowOc(m, stress_period_data=ocspd) - - m.write_input() - success, buff = m.run_model() - assert success - return m - - -class Mp6Cases2: - nrow = 3 - ncol = 4 - nlay = 2 - nper = 1 - l1_ibound = np.array( - [[[-1, -1, -1, -1], [-1, 1, 1, -1], [-1, -1, -1, -1]]] - ) - l2_ibound = np.ones((1, nrow, ncol)) - l2_ibound_alt = np.ones((1, nrow, ncol)) - l2_ibound_alt[0, 0, 0] = 0 - ibound = { - "mf1": np.concatenate( - (l1_ibound, l2_ibound), axis=0 - ), # constant heads around model on top row - } - laytype = { - "mf1": [0, 1], - } - hnoflow = -888 - hdry = -777 - top = np.zeros((1, nrow, ncol)) + 10 - bt1 = np.ones((1, nrow, ncol)) + 5 - bt2 = np.ones((1, nrow, ncol)) + 3 - botm = np.concatenate((bt1, bt2), axis=0) - ipakcb = 740 - - def case_1(self, function_tmpdir): - m = flopy.modflow.Modflow( - modelname=f"mf1", - namefile_ext="nam", - version="mf2005", - exe_name="mf2005", - model_ws=function_tmpdir, - ) - - # dis - dis = flopy.modflow.ModflowDis( - model=m, - nlay=self.nlay, - nrow=self.nrow, - ncol=self.ncol, - nper=self.nper, - delr=1.0, - delc=1.0, - laycbd=0, - top=self.top, - botm=self.botm, - perlen=1, - nstp=1, - tsmult=1, - steady=True, - ) - - # bas - bas = flopy.modflow.ModflowBas( - model=m, - ibound=self.ibound[m.name], - strt=10, - ifrefm=True, - ixsec=False, - ichflg=False, - stoper=None, - hnoflo=self.hnoflow, - extension="bas", - unitnumber=None, - filenames=None, - ) - # lpf - lpf = flopy.modflow.ModflowLpf( - model=m, - ipakcb=self.ipakcb, - laytyp=self.laytype[m.name], - hk=10, - vka=10, - hdry=self.hdry, - ) - - # well - wel = flopy.modflow.ModflowWel( - model=m, - ipakcb=self.ipakcb, - stress_period_data={0: [[1, 1, 1, -5.0]]}, - ) - - flopy.modflow.ModflowPcg( - m, hclose=0.001, rclose=0.001, mxiter=150, iter1=30 - ) - - ocspd = {} - for p in range(self.nper): - ocspd[(p, 0)] = ["save head", "save budget"] - ocspd[(0, 0)] = [ - "save head", - "save budget", - ] # pretty sure it just uses the last for everything - flopy.modflow.ModflowOc(m, stress_period_data=ocspd) - - m.write_input() - success, buff = m.run_model() - assert success - - return m diff --git a/etc/environment.yml b/etc/environment.yml index a5a8b3cdc4..01f3f86010 100644 --- a/etc/environment.yml +++ b/etc/environment.yml @@ -25,7 +25,6 @@ dependencies: - modflow-devtools - pytest - pytest-benchmark - - pytest-cases - pytest-cov - pytest-dotenv - pytest-xdist diff --git a/examples/data/mf6/test005_advgw_tidal/expected_output/AdvGW_tidal.cbc b/examples/data/mf6/test005_advgw_tidal/expected_output/AdvGW_tidal.cbc new file mode 100644 index 0000000000..dd14925dc6 Binary files /dev/null and b/examples/data/mf6/test005_advgw_tidal/expected_output/AdvGW_tidal.cbc differ diff --git a/examples/data/mf6/test005_advgw_tidal/expected_output/AdvGW_tidal.hds b/examples/data/mf6/test005_advgw_tidal/expected_output/AdvGW_tidal.hds new file mode 100644 index 0000000000..4b77049f3e Binary files /dev/null and b/examples/data/mf6/test005_advgw_tidal/expected_output/AdvGW_tidal.hds differ diff --git a/examples/data/mf6/test005_advgw_tidal/tides.txt b/examples/data/mf6/test005_advgw_tidal/tides.txt new file mode 100644 index 0000000000..7d4d363ca8 --- /dev/null +++ b/examples/data/mf6/test005_advgw_tidal/tides.txt @@ -0,0 +1,365 @@ +0 , -2.5 +0.05 , -2.1 +0.206, 2.1 +0.256, 2.5 +0.306, 2.0 +0.462, -2.4 +0.512, -2.8 +0.562, -2.4 +0.718, 2.4 +0.768, 2.8 +0.818, 2.4 +0.974, -2.1 +1.024, -2.5 +1.074, -2.1 +1.23, 2.1 +1.28, 2.5 +1.33, 2.0 +1.486, -2.4 +1.536, -2.8 +1.586, -2.4 +1.742, 2.4 +1.792, 2.8 +1.842, 2.4 +1.998, -2.1 +2.048, -2.5 +2.098, -2.1 +2.254, 2.1 +2.304, 2.5 +2.354, 2.0 +2.51, -2.4 +2.56, -2.8 +2.61, -2.4 +2.766, 2.4 +2.816, 2.8 +2.866, 2.4 +3.022, -2.1 +3.072, -2.5 +3.122, -2.1 +3.278, 2.1 +3.328, 2.5 +3.378, 2.0 +3.534, -2.4 +3.584, -2.8 +3.634, -2.4 +3.79, 2.4 +3.84, 2.8 +3.89, 2.4 +4.046, -2.1 +4.096, -2.5 +4.146, -2.1 +4.302, 2.1 +4.352, 2.5 +4.402, 2.0 +4.558, -2.4 +4.608, -2.8 +4.658, -2.4 +4.814, 2.4 +4.864, 2.8 +4.914, 2.4 +5.07, -2.1 +5.12, -2.5 +5.17, -2.1 +5.326, 2.1 +5.376, 2.5 +5.426, 2.0 +5.582, -2.4 +5.632, -2.8 +5.682, -2.4 +5.838, 2.4 +5.888, 2.8 +5.938, 2.4 +6.094, -2.1 +6.144, -2.5 +6.194, -2.1 +6.35, 2.1 +6.4, 2.5 +6.45, 2.0 +6.606, -2.4 +6.656, -2.8 +6.706, -2.4 +6.862, 2.4 +6.912, 2.8 +6.962, 2.4 +7.118, -2.1 +7.168, -2.5 +7.218, -2.1 +7.374, 2.1 +7.424, 2.5 +7.474, 2.0 +7.63, -2.4 +7.68, -2.8 +7.73, -2.4 +7.886, 2.4 +7.936, 2.8 +7.986, 2.4 +8.142, -2.1 +8.192, -2.5 +8.242, -2.1 +8.398, 2.1 +8.448, 2.5 +8.498, 2.0 +8.654, -2.4 +8.704, -2.8 +8.754, -2.4 +8.91, 2.4 +8.96, 2.8 +9.01, 2.4 +9.166, -2.1 +9.216, -2.5 +9.266, -2.1 +9.422, 2.1 +9.472, 2.5 +9.522, 2.0 +9.678, -2.4 +9.728, -2.8 +9.778, -2.4 +9.934, 2.4 +9.984, 2.8 +10.034, 2.4 +10.19, -2.1 +10.24, -2.5 +10.29, -2.1 +10.446, 2.1 +10.496, 2.5 +10.546, 2.0 +10.702, -2.4 +10.752, -2.8 +10.802, -2.4 +10.958, 2.4 +11.008, 2.8 +11.058, 2.4 +11.214, -2.1 +11.264, -2.5 +11.314, -2.1 +11.47, 2.1 +11.52, 2.5 +11.57, 2.0 +11.726, -2.4 +11.776, -2.8 +11.826, -2.4 +11.982, 2.4 +12.032, 2.8 +12.082, 2.4 +12.238, -2.1 +12.288, -2.5 +12.338, -2.1 +12.494, 2.1 +12.544, 2.5 +12.594, 2.0 +12.75, -2.4 +12.8, 2.8 +12.85, -2.4 +13.006, 2.4 +13.056, 2.8 +13.106, 2.4 +13.262, -2.1 +13.312, -2.5 +13.362, -2.1 +13.518, 2.1 +13.568, 2.5 +13.618, 2.0 +13.774, -2.4 +13.824, -2.8 +13.874, -2.4 +14.03, 2.4 +14.08, 2.8 +14.13, 2.4 +14.286, -2.1 +14.336, -2.5 +14.386, -2.1 +14.542, 2.1 +14.592, 2.5 +14.642, 2.0 +14.798, -2.4 +14.848, -2.8 +14.898, -2.4 +15.054, 2.4 +15.104, 2.8 +15.154, 2.4 +15.31, -2.1 +15.36, -2.5 +15.41, -2.1 +15.566, 2.1 +15.616, 2.5 +15.666, 2.0 +15.822, -2.4 +15.872, -2.8 +15.922, -2.4 +16.078, 2.4 +16.128, 2.8 +16.178, 2.4 +16.334, -2.1 +16.384, -2.5 +16.434, -2.1 +16.59, 2.1 +16.64, 2.5 +16.69, 2.0 +16.846, -2.4 +16.896, -2.8 +16.946, -2.4 +17.102, 2.4 +17.152, 2.8 +17.202, 2.4 +17.358, -2.1 +17.408, -2.5 +17.458, -2.1 +17.614, 2.1 +17.664, 2.5 +17.714, 2.0 +17.87, -2.4 +17.92, -2.8 +17.97, -2.4 +18.126, 2.4 +18.176, 2.8 +18.226, 2.4 +18.382, -2.1 +18.432, -2.5 +18.482, -2.1 +18.638, 2.1 +18.688, 2.5 +18.738, 2.0 +18.894, -2.4 +18.944, -2.8 +18.994, -2.4 +19.15, 2.4 +19.2, 2.8 +19.25, 2.4 +19.406, -2.1 +19.456, -2.5 +19.506, -2.1 +19.662, 2.1 +19.712, 2.5 +19.762, 2.0 +19.918, -2.4 +19.968, -2.8 +20.018, -2.4 +20.174, 2.4 +20.224, 2.8 +20.274, 2.4 +20.43, -2.1 +20.48, -2.5 +20.53, -2.1 +20.686, 2.1 +20.736, 2.5 +20.786, 2.0 +20.942, -2.4 +20.992, -2.8 +21.042, -2.4 +21.198, 2.4 +21.248, 2.8 +21.298, 2.4 +21.454, -2.1 +21.504, -2.5 +21.554, -2.1 +21.71, 2.1 +21.76, 2.5 +21.81, 2.0 +21.966, -2.4 +22.016, -2.8 +22.066, -2.4 +22.222, 2.4 +22.272, 2.8 +22.322, 2.4 +22.478, -2.1 +22.528, -2.5 +22.578, -2.1 +22.734, 2.1 +22.784, 2.5 +22.834, 2.0 +22.99, -2.4 +23.04, -2.8 +23.09, -2.4 +23.246, 2.4 +23.296, 2.8 +23.346, 2.4 +23.502, -2.1 +23.552, -2.5 +23.602, -2.1 +23.758, 2.1 +23.808, 2.5 +23.858, 2.0 +24.014, -2.4 +24.064, -2.8 +24.114, -2.4 +24.27, 2.4 +24.32, 2.8 +24.37, 2.4 +24.526, -2.1 +24.576, -2.5 +24.626, -2.1 +24.782, 2.1 +24.832, 2.5 +24.882, 2.0 +25.038, -2.4 +25.088, -2.8 +25.138, -2.4 +25.294, 2.4 +25.344, 2.8 +25.394, 2.4 +25.55, -2.1 +25.6, 2.5 +25.65, -2.1 +25.806, 2.1 +25.856, 2.5 +25.906, 2.0 +26.062, -2.4 +26.112, -2.8 +26.162, -2.4 +26.318, 2.4 +26.368, 2.8 +26.418, 2.4 +26.574, -2.1 +26.624, -2.5 +26.674, -2.1 +26.83, 2.1 +26.88, 2.5 +26.93, 2.0 +27.086, -2.4 +27.136, -2.8 +27.186, -2.4 +27.342, 2.4 +27.392, 2.8 +27.442, 2.4 +27.598, -2.1 +27.648, -2.5 +27.698, -2.1 +27.854, 2.1 +27.904, 2.5 +27.954, 2.0 +28.11, -2.4 +28.16, -2.8 +28.21, -2.4 +28.366, 2.4 +28.416, 2.8 +28.466, 2.4 +28.622, -2.1 +28.672, -2.5 +28.722, -2.1 +28.878, 2.1 +28.928, 2.5 +28.978, 2.0 +29.134, -2.4 +29.184, -2.8 +29.234, -2.4 +29.39, 2.4 +29.44, 2.8 +29.49, 2.4 +29.646, -2.1 +29.696, -2.5 +29.746, -2.1 +29.902, 2.1 +29.952, 2.5 +30.002, 2.0 +30.158, -2.4 +30.208, -2.8 +30.258, -2.4 +30.414, 2.4 +30.464, 2.8 +30.514, 2.4 +30.67, -2.1 +30.72, -2.5 +30.77, -2.1 +30.926, 2.1 +30.976, 2.5 +31.026, 2.0 \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 576b33047a..1ddff9292d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -52,9 +52,8 @@ test = [ "jupyter", "jupytext", "modflow-devtools", - "pytest < 8.0.0", + "pytest", "pytest-benchmark", - "pytest-cases", "pytest-cov", "pytest-dotenv", "pytest-xdist", diff --git a/scripts/update_version.py b/scripts/update_version.py index 19390073da..4720d98fbe 100644 --- a/scripts/update_version.py +++ b/scripts/update_version.py @@ -328,8 +328,8 @@ def update_version( else: update_version( timestamp=datetime.now(), - version=Version(args.version) - if args.version - else _current_version, + version=( + Version(args.version) if args.version else _current_version + ), approved=args.approve, )