Skip to content

Commit 70339c3

Browse files
authored
Merge pull request #2323 from modflowpy/v3.8.2
Release 3.8.2
2 parents 1eaab1c + 7ddfa3c commit 70339c3

File tree

15 files changed

+163
-62
lines changed

15 files changed

+163
-62
lines changed

.docs/md/version_changes.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,13 @@
11
# Changelog
2+
### Version 3.8.2
3+
4+
#### Bug fixes
5+
6+
* [fix(mp7particledata)](https://github.com/modflowpy/flopy/commit/a0e9219407b7be208d38f4f902cd2b5b96da1351): Fix get_extent() vertical extent calculation (#2307). Committed by wpbonelli on 2024-09-12.
7+
* [fix(array3d_export)](https://github.com/modflowpy/flopy/commit/693f01a0ce41f08d05395832b540fcc4f7dcff43): Fix exporting of array3d to shp (#2310). Committed by martclanor on 2024-09-16.
8+
* [fix(binaryfile)](https://github.com/modflowpy/flopy/commit/181e101a605bdb9b628c6781abff7b3276aca635): Accommodate windows drives for in-place reversal (#2312). Committed by wpbonelli on 2024-09-16.
9+
* [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.
10+
211
### Version 3.8.1
312

413
#### New features

CITATION.cff

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ message: If you use this software, please cite both the article from preferred-c
33
references, and the software itself.
44
type: software
55
title: FloPy
6-
version: 3.8.1
7-
date-released: '2024-09-05'
6+
version: 3.8.2
7+
date-released: '2024-10-03'
88
doi: 10.5066/F7BK19FH
99
abstract: A Python package to create, run, and post-process MODFLOW-based models.
1010
repository-artifact: https://pypi.org/project/flopy

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11

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

4-
### Version 3.8.1
4+
### Version 3.8.2
55
[![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)
66
[![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)
77

@@ -150,7 +150,7 @@ How to Cite
150150

151151
##### ***Software/Code citation for FloPy:***
152152

153-
[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)
153+
[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)
154154

155155

156156
Additional FloPy Related Publications

autotest/test_export.py

Lines changed: 63 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -409,7 +409,6 @@ def test_export_shapefile_polygon_closed(function_tmpdir):
409409
shp.close()
410410

411411

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

475474

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

648647

648+
@pytest.mark.mf6
649+
@requires_pkg("pyshp", name_map={"pyshp": "shapefile"})
650+
def test_array3d_export_structured(function_tmpdir):
651+
from shapefile import Reader
652+
653+
xll, yll = 468970, 3478635
654+
xur, yur = 681010, 3716462
655+
spacing = 20000
656+
ncol = int((xur - xll) / spacing)
657+
nrow = int((yur - yll) / spacing)
658+
sim = flopy.mf6.MFSimulation("sim", sim_ws=function_tmpdir)
659+
gwf = flopy.mf6.ModflowGwf(
660+
sim,
661+
modelname="array3d_export_unstructured",
662+
)
663+
flopy.mf6.ModflowGwfdis(
664+
gwf,
665+
nlay=3,
666+
top=5,
667+
botm=[4, 3, 2],
668+
delr=spacing,
669+
delc=spacing,
670+
nrow=nrow,
671+
ncol=ncol,
672+
)
673+
674+
shp_file = os.path.join(function_tmpdir, "dis_botm.shp")
675+
gwf.dis.botm.export(shp_file)
676+
677+
with Reader(shp_file) as shp:
678+
assert list(shp.shapeRecord(-1).record) == [
679+
110, # node
680+
11, # row
681+
10, # column
682+
4.0, # botm_1
683+
3.0, # botm_2
684+
2.0, # botm_3
685+
]
686+
687+
688+
@requires_pkg("pyshp", name_map={"pyshp": "shapefile"})
689+
def test_array3d_export_unstructured(function_tmpdir):
690+
from shapefile import Reader
691+
692+
name = "array3d_export_unstructured"
693+
sim = disu_sim(name, function_tmpdir)
694+
gwf = sim.get_model(name)
695+
696+
shp_file = function_tmpdir / "disu_bot.shp"
697+
gwf.disu.bot.export(shp_file)
698+
699+
with Reader(shp_file) as shp:
700+
assert list(shp.shapeRecord(-1).record) == [
701+
1770, # node
702+
3, # layer
703+
0.0, # bot
704+
]
705+
706+
649707
@requires_pkg("pyshp", "shapely", name_map={"pyshp": "shapefile"})
650708
def test_export_array_contours_structured(function_tmpdir):
651709
nrow = 7

autotest/test_particledata.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
ParticleGroupLRCTemplate,
2727
ParticleGroupNodeTemplate,
2828
)
29+
from flopy.modpath.mp7particledata import get_extent
2930
from flopy.modpath.mp7particlegroup import ParticleGroup
3031
from flopy.utils.modpathfile import EndpointFile, PathlineFile
3132

@@ -47,6 +48,20 @@ def flatten(a):
4748
]
4849

4950

51+
# test get_extent()
52+
53+
54+
def test_get_extent_structured_multilayer():
55+
grid = GridCases().structured_small()
56+
i, j = 1, 2
57+
for k in range(grid.nlay):
58+
extent = get_extent(grid, k=k, i=i, j=j)
59+
assert extent.minz == grid.botm[k, i, j]
60+
assert extent.maxz == (
61+
grid.top[i, j] if k == 0 else grid.botm[k - 1, i, j]
62+
)
63+
64+
5065
# test initializers
5166

5267

docs/PyPI_release.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,4 @@ How to Cite
3030

3131
*Software/Code citation for FloPy:*
3232

33-
[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)
33+
[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)

flopy/export/utils.py

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1207,16 +1207,22 @@ def array3d_export(f: Union[str, os.PathLike], u3d, fmt=None, **kwargs):
12071207
f
12081208
).suffix.lower() == ".shp":
12091209
array_dict = {}
1210-
for ilay in range(modelgrid.nlay):
1211-
u2d = u3d[ilay]
1212-
if isinstance(u2d, np.ndarray):
1213-
dname = u3d.name
1214-
array = u2d
1215-
else:
1216-
dname = u2d.name
1217-
array = u2d.array
1218-
name = f"{shapefile_utils.shape_attr_name(dname)}_{ilay + 1}"
1219-
array_dict[name] = array
1210+
array_shape = u3d.array.shape
1211+
1212+
if len(array_shape) == 1:
1213+
name = shapefile_utils.shape_attr_name(u3d.name)
1214+
array_dict[name] = u3d.array
1215+
else:
1216+
for ilay in range(array_shape[0]):
1217+
u2d = u3d[ilay]
1218+
if isinstance(u2d, np.ndarray):
1219+
dname = u3d.name
1220+
array = u2d
1221+
else:
1222+
dname = u2d.name
1223+
array = u2d.array
1224+
name = f"{shapefile_utils.shape_attr_name(dname)}_{ilay + 1}"
1225+
array_dict[name] = array
12201226
shapefile_utils.write_grid_shapefile(f, modelgrid, array_dict)
12211227

12221228
elif isinstance(f, NetCdf) or isinstance(f, dict):

flopy/modpath/mp7particledata.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -809,7 +809,14 @@ def get_extent(grid, k=None, i=None, j=None, nn=None, localz=False) -> Extent:
809809
# get cell coords and span in each dimension
810810
if not (k is None or i is None or j is None):
811811
verts = grid.get_cell_vertices(i, j)
812-
minz, maxz = (0, 1) if localz else (grid.botm[k, i, j], grid.top[i, j])
812+
minz, maxz = (
813+
(0, 1)
814+
if localz
815+
else (
816+
grid.botm[k, i, j],
817+
grid.top[i, j] if k == 0 else grid.botm[k - 1, i, j],
818+
)
819+
)
813820
elif nn is not None:
814821
verts = grid.get_cell_vertices(nn)
815822
if grid.grid_type == "structured":

flopy/utils/binaryfile.py

Lines changed: 35 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import tempfile
1414
import warnings
1515
from pathlib import Path
16+
from shutil import move
1617
from typing import List, Optional, Union
1718

1819
import numpy as np
@@ -460,9 +461,9 @@ class BinaryLayerFile(LayerFile):
460461
"""
461462

462463
def __init__(
463-
self, filename: Union[str, os.PathLike], precision, verbose, kwargs
464+
self, filename: Union[str, os.PathLike], precision, verbose, **kwargs
464465
):
465-
super().__init__(filename, precision, verbose, kwargs)
466+
super().__init__(filename, precision, verbose, **kwargs)
466467

467468
def _build_index(self):
468469
"""
@@ -661,7 +662,7 @@ def __init__(
661662
self.header_dtype = BinaryHeader.set_dtype(
662663
bintype="Head", precision=precision
663664
)
664-
super().__init__(filename, precision, verbose, kwargs)
665+
super().__init__(filename, precision, verbose, **kwargs)
665666

666667
def reverse(self, filename: Optional[os.PathLike] = None):
667668
"""
@@ -733,10 +734,18 @@ def reverse_header(header):
733734
header["pertim"] = perlen - header["pertim"]
734735
return header
735736

736-
# reverse record order and write to temporary file
737-
temp_dir_path = Path(tempfile.gettempdir())
738-
temp_file_path = temp_dir_path / filename.name
739-
with open(temp_file_path, "wb") as f:
737+
target = filename
738+
739+
# if rewriting the same file, write
740+
# temp file then copy it into place
741+
inplace = filename == self.filename
742+
if inplace:
743+
temp_dir_path = Path(tempfile.gettempdir())
744+
temp_file_path = temp_dir_path / filename.name
745+
target = temp_file_path
746+
747+
# reverse record order
748+
with open(target, "wb") as f:
740749
for i in range(len(self) - 1, -1, -1):
741750
header = self.recordarray[i].copy()
742751
header = reverse_header(header)
@@ -752,16 +761,10 @@ def reverse_header(header):
752761
ilay=ilay,
753762
)
754763

755-
# if we're rewriting the original file, close it first
756-
if filename == self.filename:
757-
self.close()
758-
759-
# move temp file to destination
760-
temp_file_path.replace(filename)
761-
762764
# if we rewrote the original file, reinitialize
763-
if filename == self.filename:
764-
super().__init__(self.filename, self.precision, self.verbose, {})
765+
if inplace:
766+
move(target, filename)
767+
super().__init__(filename, self.precision, self.verbose)
765768

766769

767770
class UcnFile(BinaryLayerFile):
@@ -828,7 +831,7 @@ def __init__(
828831
self.header_dtype = BinaryHeader.set_dtype(
829832
bintype="Ucn", precision=precision
830833
)
831-
super().__init__(filename, precision, verbose, kwargs)
834+
super().__init__(filename, precision, verbose, **kwargs)
832835
return
833836

834837

@@ -898,7 +901,7 @@ def __init__(
898901
self.header_dtype = BinaryHeader.set_dtype(
899902
bintype="Head", precision=precision
900903
)
901-
super().__init__(filename, precision, verbose, kwargs)
904+
super().__init__(filename, precision, verbose, **kwargs)
902905

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

2328-
# open backward budget file
2329-
temp_dir_path = Path(tempfile.gettempdir())
2330-
temp_file_path = temp_dir_path / filename.name
2331-
with open(temp_file_path, "wb") as f:
2331+
target = filename
2332+
2333+
# if rewriting the same file, write
2334+
# temp file then copy it into place
2335+
inplace = filename == self.filename
2336+
if inplace:
2337+
temp_dir_path = Path(tempfile.gettempdir())
2338+
temp_file_path = temp_dir_path / filename.name
2339+
target = temp_file_path
2340+
2341+
with open(target, "wb") as f:
23322342
# loop over budget file records in reverse order
23332343
for idx in range(nrecords - 1, -1, -1):
23342344
# load header array
@@ -2415,13 +2425,7 @@ def reverse(self, filename: Optional[os.PathLike] = None):
24152425
# Write data
24162426
data.tofile(f)
24172427

2418-
# if we're rewriting the original file, close it first
2419-
if filename == self.filename:
2420-
self.close()
2421-
2422-
# move temp file to destination
2423-
temp_file_path.replace(filename)
2424-
24252428
# if we rewrote the original file, reinitialize
2426-
if filename == self.filename:
2427-
self.__init__(self.filename, self.precision, self.verbose)
2429+
if inplace:
2430+
move(target, filename)
2431+
self.__init__(filename, self.precision, self.verbose)

flopy/utils/datafile.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ class LayerFile:
157157
"""
158158

159159
def __init__(
160-
self, filename: Union[str, os.PathLike], precision, verbose, kwargs
160+
self, filename: Union[str, os.PathLike], precision, verbose, **kwargs
161161
):
162162
from ..discretization.structuredgrid import StructuredGrid
163163

0 commit comments

Comments
 (0)