Skip to content

Release 3.8.2 #2323

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Oct 3, 2024
9 changes: 9 additions & 0 deletions .docs/md/version_changes.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
# Changelog
### Version 3.8.2

#### Bug fixes

* [fix(mp7particledata)](https://github.com/modflowpy/flopy/commit/a0e9219407b7be208d38f4f902cd2b5b96da1351): Fix get_extent() vertical extent calculation (#2307). Committed by wpbonelli on 2024-09-12.
* [fix(array3d_export)](https://github.com/modflowpy/flopy/commit/693f01a0ce41f08d05395832b540fcc4f7dcff43): Fix exporting of array3d to shp (#2310). Committed by martclanor on 2024-09-16.
* [fix(binaryfile)](https://github.com/modflowpy/flopy/commit/181e101a605bdb9b628c6781abff7b3276aca635): Accommodate windows drives for in-place reversal (#2312). Committed by wpbonelli on 2024-09-16.
* [fix(get_modflow)](https://github.com/modflowpy/flopy/commit/38180335445fa09f5463cf8b9239e6ed0c10bf5b): Accommodate missing ratelimit info on api response (#2320). Committed by wpbonelli on 2024-10-01.

### Version 3.8.1

#### New features
Expand Down
4 changes: 2 additions & 2 deletions CITATION.cff
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ message: If you use this software, please cite both the article from preferred-c
references, and the software itself.
type: software
title: FloPy
version: 3.8.1
date-released: '2024-09-05'
version: 3.8.2
date-released: '2024-10-03'
doi: 10.5066/F7BK19FH
abstract: A Python package to create, run, and post-process MODFLOW-based models.
repository-artifact: https://pypi.org/project/flopy
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

<img src="https://raw.githubusercontent.com/modflowpy/flopy/master/examples/images/flopy3.png" alt="flopy3" style="width:50;height:20">

### Version 3.8.1
### Version 3.8.2
[![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)

Expand Down Expand Up @@ -150,7 +150,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., 2024, FloPy v3.8.1: U.S. Geological Survey Software Release, 05 September 2024, 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., 2024, FloPy v3.8.2: U.S. Geological Survey Software Release, 03 October 2024, https://doi.org/10.5066/F7BK19FH](https://doi.org/10.5066/F7BK19FH)


Additional FloPy Related Publications
Expand Down
68 changes: 63 additions & 5 deletions autotest/test_export.py
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,6 @@ def test_export_shapefile_polygon_closed(function_tmpdir):
shp.close()


@excludes_platform("Windows")
@requires_pkg("rasterio", "pyshp", "scipy", name_map={"pyshp": "shapefile"})
def test_export_array(function_tmpdir, example_data_path):
import rasterio
Expand Down Expand Up @@ -467,10 +466,10 @@ def test_export_array(function_tmpdir, example_data_path):
with rasterio.open(function_tmpdir / "fb.tif") as src:
arr = src.read(1)
assert src.shape == (m.nrow, m.ncol)
# TODO: these tests currently fail -- fix is in progress
# assert np.abs(src.bounds[0] - m.modelgrid.extent[0]) < 1e-6
# assert np.abs(src.bounds[1] - m.modelgrid.extent[1]) < 1e-6
pass
assert np.abs(src.bounds[0] - m.modelgrid.extent[0]) < 1e-6
assert np.abs(src.bounds[2] - m.modelgrid.extent[1]) < 1e-6
assert np.abs(src.bounds[1] - m.modelgrid.extent[2]) < 1e-6
assert np.abs(src.bounds[3] - m.modelgrid.extent[3]) < 1e-6


@requires_pkg("netCDF4", "pyproj")
Expand Down Expand Up @@ -646,6 +645,65 @@ def test_export_array2(function_tmpdir):
assert os.path.isfile(filename), "did not create array shapefile"


@pytest.mark.mf6
@requires_pkg("pyshp", name_map={"pyshp": "shapefile"})
def test_array3d_export_structured(function_tmpdir):
from shapefile import Reader

xll, yll = 468970, 3478635
xur, yur = 681010, 3716462
spacing = 20000
ncol = int((xur - xll) / spacing)
nrow = int((yur - yll) / spacing)
sim = flopy.mf6.MFSimulation("sim", sim_ws=function_tmpdir)
gwf = flopy.mf6.ModflowGwf(
sim,
modelname="array3d_export_unstructured",
)
flopy.mf6.ModflowGwfdis(
gwf,
nlay=3,
top=5,
botm=[4, 3, 2],
delr=spacing,
delc=spacing,
nrow=nrow,
ncol=ncol,
)

shp_file = os.path.join(function_tmpdir, "dis_botm.shp")
gwf.dis.botm.export(shp_file)

with Reader(shp_file) as shp:
assert list(shp.shapeRecord(-1).record) == [
110, # node
11, # row
10, # column
4.0, # botm_1
3.0, # botm_2
2.0, # botm_3
]


@requires_pkg("pyshp", name_map={"pyshp": "shapefile"})
def test_array3d_export_unstructured(function_tmpdir):
from shapefile import Reader

name = "array3d_export_unstructured"
sim = disu_sim(name, function_tmpdir)
gwf = sim.get_model(name)

shp_file = function_tmpdir / "disu_bot.shp"
gwf.disu.bot.export(shp_file)

with Reader(shp_file) as shp:
assert list(shp.shapeRecord(-1).record) == [
1770, # node
3, # layer
0.0, # bot
]


@requires_pkg("pyshp", "shapely", name_map={"pyshp": "shapefile"})
def test_export_array_contours_structured(function_tmpdir):
nrow = 7
Expand Down
15 changes: 15 additions & 0 deletions autotest/test_particledata.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
ParticleGroupLRCTemplate,
ParticleGroupNodeTemplate,
)
from flopy.modpath.mp7particledata import get_extent
from flopy.modpath.mp7particlegroup import ParticleGroup
from flopy.utils.modpathfile import EndpointFile, PathlineFile

Expand All @@ -47,6 +48,20 @@ def flatten(a):
]


# test get_extent()


def test_get_extent_structured_multilayer():
grid = GridCases().structured_small()
i, j = 1, 2
for k in range(grid.nlay):
extent = get_extent(grid, k=k, i=i, j=j)
assert extent.minz == grid.botm[k, i, j]
assert extent.maxz == (
grid.top[i, j] if k == 0 else grid.botm[k - 1, i, j]
)


# test initializers


Expand Down
2 changes: 1 addition & 1 deletion docs/PyPI_release.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,4 @@ 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., 2024, FloPy v3.8.1: U.S. Geological Survey Software Release, 05 September 2024, 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., 2024, FloPy v3.8.2: U.S. Geological Survey Software Release, 03 October 2024, https://doi.org/10.5066/F7BK19FH](https://doi.org/10.5066/F7BK19FH)
26 changes: 16 additions & 10 deletions flopy/export/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -1207,16 +1207,22 @@ def array3d_export(f: Union[str, os.PathLike], u3d, fmt=None, **kwargs):
f
).suffix.lower() == ".shp":
array_dict = {}
for ilay in range(modelgrid.nlay):
u2d = u3d[ilay]
if isinstance(u2d, np.ndarray):
dname = u3d.name
array = u2d
else:
dname = u2d.name
array = u2d.array
name = f"{shapefile_utils.shape_attr_name(dname)}_{ilay + 1}"
array_dict[name] = array
array_shape = u3d.array.shape

if len(array_shape) == 1:
name = shapefile_utils.shape_attr_name(u3d.name)
array_dict[name] = u3d.array
else:
for ilay in range(array_shape[0]):
u2d = u3d[ilay]
if isinstance(u2d, np.ndarray):
dname = u3d.name
array = u2d
else:
dname = u2d.name
array = u2d.array
name = f"{shapefile_utils.shape_attr_name(dname)}_{ilay + 1}"
array_dict[name] = array
shapefile_utils.write_grid_shapefile(f, modelgrid, array_dict)

elif isinstance(f, NetCdf) or isinstance(f, dict):
Expand Down
9 changes: 8 additions & 1 deletion flopy/modpath/mp7particledata.py
Original file line number Diff line number Diff line change
Expand Up @@ -809,7 +809,14 @@ def get_extent(grid, k=None, i=None, j=None, nn=None, localz=False) -> Extent:
# get cell coords and span in each dimension
if not (k is None or i is None or j is None):
verts = grid.get_cell_vertices(i, j)
minz, maxz = (0, 1) if localz else (grid.botm[k, i, j], grid.top[i, j])
minz, maxz = (
(0, 1)
if localz
else (
grid.botm[k, i, j],
grid.top[i, j] if k == 0 else grid.botm[k - 1, i, j],
)
)
elif nn is not None:
verts = grid.get_cell_vertices(nn)
if grid.grid_type == "structured":
Expand Down
66 changes: 35 additions & 31 deletions flopy/utils/binaryfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import tempfile
import warnings
from pathlib import Path
from shutil import move
from typing import List, Optional, Union

import numpy as np
Expand Down Expand Up @@ -460,9 +461,9 @@ class BinaryLayerFile(LayerFile):
"""

def __init__(
self, filename: Union[str, os.PathLike], precision, verbose, kwargs
self, filename: Union[str, os.PathLike], precision, verbose, **kwargs
):
super().__init__(filename, precision, verbose, kwargs)
super().__init__(filename, precision, verbose, **kwargs)

def _build_index(self):
"""
Expand Down Expand Up @@ -661,7 +662,7 @@ def __init__(
self.header_dtype = BinaryHeader.set_dtype(
bintype="Head", precision=precision
)
super().__init__(filename, precision, verbose, kwargs)
super().__init__(filename, precision, verbose, **kwargs)

def reverse(self, filename: Optional[os.PathLike] = None):
"""
Expand Down Expand Up @@ -733,10 +734,18 @@ def reverse_header(header):
header["pertim"] = perlen - header["pertim"]
return header

# reverse record order and write to temporary file
temp_dir_path = Path(tempfile.gettempdir())
temp_file_path = temp_dir_path / filename.name
with open(temp_file_path, "wb") as f:
target = filename

# if rewriting the same file, write
# temp file then copy it into place
inplace = filename == self.filename
if inplace:
temp_dir_path = Path(tempfile.gettempdir())
temp_file_path = temp_dir_path / filename.name
target = temp_file_path

# reverse record order
with open(target, "wb") as f:
for i in range(len(self) - 1, -1, -1):
header = self.recordarray[i].copy()
header = reverse_header(header)
Expand All @@ -752,16 +761,10 @@ def reverse_header(header):
ilay=ilay,
)

# if we're rewriting the original file, close it first
if filename == self.filename:
self.close()

# move temp file to destination
temp_file_path.replace(filename)

# if we rewrote the original file, reinitialize
if filename == self.filename:
super().__init__(self.filename, self.precision, self.verbose, {})
if inplace:
move(target, filename)
super().__init__(filename, self.precision, self.verbose)


class UcnFile(BinaryLayerFile):
Expand Down Expand Up @@ -828,7 +831,7 @@ def __init__(
self.header_dtype = BinaryHeader.set_dtype(
bintype="Ucn", precision=precision
)
super().__init__(filename, precision, verbose, kwargs)
super().__init__(filename, precision, verbose, **kwargs)
return


Expand Down Expand Up @@ -898,7 +901,7 @@ def __init__(
self.header_dtype = BinaryHeader.set_dtype(
bintype="Head", precision=precision
)
super().__init__(filename, precision, verbose, kwargs)
super().__init__(filename, precision, verbose, **kwargs)

def _get_data_array(self, totim=0.0):
"""
Expand Down Expand Up @@ -2325,10 +2328,17 @@ def reverse(self, filename: Optional[os.PathLike] = None):
# get number of records
nrecords = len(self)

# open backward budget file
temp_dir_path = Path(tempfile.gettempdir())
temp_file_path = temp_dir_path / filename.name
with open(temp_file_path, "wb") as f:
target = filename

# if rewriting the same file, write
# temp file then copy it into place
inplace = filename == self.filename
if inplace:
temp_dir_path = Path(tempfile.gettempdir())
temp_file_path = temp_dir_path / filename.name
target = temp_file_path

with open(target, "wb") as f:
# loop over budget file records in reverse order
for idx in range(nrecords - 1, -1, -1):
# load header array
Expand Down Expand Up @@ -2415,13 +2425,7 @@ def reverse(self, filename: Optional[os.PathLike] = None):
# Write data
data.tofile(f)

# if we're rewriting the original file, close it first
if filename == self.filename:
self.close()

# move temp file to destination
temp_file_path.replace(filename)

# if we rewrote the original file, reinitialize
if filename == self.filename:
self.__init__(self.filename, self.precision, self.verbose)
if inplace:
move(target, filename)
self.__init__(filename, self.precision, self.verbose)
2 changes: 1 addition & 1 deletion flopy/utils/datafile.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ class LayerFile:
"""

def __init__(
self, filename: Union[str, os.PathLike], precision, verbose, kwargs
self, filename: Union[str, os.PathLike], precision, verbose, **kwargs
):
from ..discretization.structuredgrid import StructuredGrid

Expand Down
4 changes: 3 additions & 1 deletion flopy/utils/datautil.py
Original file line number Diff line number Diff line change
Expand Up @@ -606,7 +606,9 @@ def build_list(self, callback):
(entry_point[0][-1], new_location)
)
else:
entry_point[0].append(callback(entry_point[1]))
entry_point[0].append(
callback(tuple(i + val for i in entry_point[1]))
)
entry_points = new_entry_points

def first_item(self):
Expand Down
6 changes: 3 additions & 3 deletions flopy/utils/formattedfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,8 @@ class FormattedLayerFile(LayerFile):

"""

def __init__(self, filename, precision, verbose, kwargs):
super().__init__(filename, precision, verbose, kwargs)
def __init__(self, filename, precision, verbose, **kwargs):
super().__init__(filename, precision, verbose, **kwargs)

def _build_index(self):
"""
Expand Down Expand Up @@ -376,7 +376,7 @@ def __init__(
**kwargs,
):
self.text = text
super().__init__(filename, precision, verbose, kwargs)
super().__init__(filename, precision, verbose, **kwargs)

def _get_text_header(self):
"""
Expand Down
4 changes: 2 additions & 2 deletions flopy/utils/get_modflow.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,8 +160,8 @@ def get_release(owner=None, repo=None, tag="latest", quiet=False) -> dict:
try:
with urllib.request.urlopen(request, timeout=10) as resp:
result = resp.read()
remaining = int(resp.headers["x-ratelimit-remaining"])
if remaining <= 10:
remaining = resp.headers.get("x-ratelimit-remaining", None)
if remaining and int(remaining) <= 10:
warnings.warn(
f"Only {remaining} GitHub API requests remaining "
"before rate-limiting"
Expand Down
Loading