Skip to content

Commit 1eaab1c

Browse files
authored
Merge pull request #2305 from modflowpy/v3.8.1
Release 3.8.1
2 parents 49889ec + 167ad39 commit 1eaab1c

File tree

17 files changed

+573
-92
lines changed

17 files changed

+573
-92
lines changed

.docs/md/version_changes.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,19 @@
11
# Changelog
2+
### Version 3.8.1
3+
4+
#### New features
5+
6+
* [feat(cell1d)](https://github.com/modflowpy/flopy/commit/4ea71927f251c3675acf1b578bca623d023ccd2c): Add support for 1D vertex grids (#2296). Committed by langevin-usgs on 2024-08-23.
7+
8+
#### Bug fixes
9+
10+
* [fix(ParticleTrackFile.write_shapefile)](https://github.com/modflowpy/flopy/commit/f86881d6354071bf7c675384c2684ea184e281eb): Check for "k" even if "i", "j are not present (#2294). Committed by Joshua Larsen on 2024-08-17.
11+
* [fix(modelgrid)](https://github.com/modflowpy/flopy/commit/c42d8787bbcd4131b2f493ebc5a5a384b2e8b861): Add more support for mf6 surface water models (#2295). Committed by langevin-usgs on 2024-08-22.
12+
13+
#### Refactoring
14+
15+
* [refactor(model_splitter.py)](https://github.com/modflowpy/flopy/commit/d02967db167b98e32cfaa26ef6636475ea2441a8): Update UnstructuredGrid support (#2292). Committed by Joshua Larsen on 2024-08-16.
16+
217
### Version 3.8.0
318

419
#### New features

.github/workflows/release.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ jobs:
8484
8585
- name: Generate changelog
8686
id: cliff
87-
uses: orhun/git-cliff-action@v3
87+
uses: orhun/git-cliff-action@v4
8888
with:
8989
config: cliff.toml
9090
args: --verbose --unreleased --tag ${{ steps.version.outputs.version }}
@@ -120,7 +120,7 @@ jobs:
120120
git config core.sharedRepository true
121121
git config user.name "github-actions[bot]"
122122
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
123-
git add -A
123+
git add flopy docs .docs CITATION.cff README.md version.txt
124124
git commit -m "ci(release): set version to ${{ steps.version.outputs.version }}, update plugins from DFN files, update changelog"
125125
git push origin "${{ github.ref_name }}"
126126

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.0
7-
date-released: '2024-08-08'
6+
version: 3.8.1
7+
date-released: '2024-09-05'
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.0
4+
### Version 3.8.1
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.0: U.S. Geological Survey Software Release, 08 August 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.1: U.S. Geological Survey Software Release, 05 September 2024, https://doi.org/10.5066/F7BK19FH](https://doi.org/10.5066/F7BK19FH)
154154

155155

156156
Additional FloPy Related Publications

autotest/test_grid.py

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1450,3 +1450,64 @@ def test_geo_dataframe(structured_grid, vertex_grid, unstructured_grid):
14501450
raise AssertionError(
14511451
f"Cell vertices incorrect for node={node}"
14521452
)
1453+
1454+
1455+
def test_unstructured_iverts_cleanup():
1456+
grid = GridCases.structured_small()
1457+
1458+
# begin building unstructured grid information
1459+
top = grid.top.ravel()
1460+
botm = grid.botm[0].ravel()
1461+
idomain = np.ones(botm.shape, dtype=int)
1462+
1463+
# build iac and ja
1464+
neighbors = grid.neighbors(method="rook", reset=True)
1465+
iac, ja = [], []
1466+
for cell, neigh in neighbors.items():
1467+
iac.append(len(neigh) + 1)
1468+
ja.extend(
1469+
[
1470+
cell,
1471+
]
1472+
+ neigh
1473+
)
1474+
1475+
# build iverts and verts without using shared vertices
1476+
verts, iverts = [], []
1477+
xverts, yverts = grid.cross_section_vertices
1478+
ivt = 0
1479+
for cid, xvs in enumerate(xverts):
1480+
yvs = yverts[cid]
1481+
ivts = []
1482+
for ix, vert in enumerate(xvs[:-1]):
1483+
ivts.append(ivt)
1484+
verts.append([ivt, vert, yvs[ix]])
1485+
ivt += 1
1486+
1487+
ivts.append(ivts[0])
1488+
iverts.append(ivts)
1489+
1490+
ugrid = UnstructuredGrid(
1491+
vertices=verts,
1492+
iverts=iverts,
1493+
xcenters=grid.xcellcenters.ravel(),
1494+
ycenters=grid.ycellcenters.ravel(),
1495+
iac=iac,
1496+
ja=ja,
1497+
top=top,
1498+
botm=botm,
1499+
idomain=idomain,
1500+
)
1501+
1502+
if ugrid.nvert != (grid.ncpl * 4):
1503+
raise AssertionError(
1504+
"UnstructuredGrid is being built incorrectly for test case"
1505+
)
1506+
1507+
cleaned_vert_num = (grid.nrow + 1) * (grid.ncol + 1)
1508+
clean_ugrid = ugrid.clean_iverts()
1509+
1510+
if clean_ugrid.nvert != cleaned_vert_num:
1511+
raise AssertionError(
1512+
"Improper number of vertices for cleaned 'shared' iverts"
1513+
)

autotest/test_model_splitter.py

Lines changed: 172 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ def test_structured_model_splitter(function_tmpdir):
2626
for row in range(modelgrid.nrow):
2727
if row != 0 and row % 2 == 0:
2828
ncol += 1
29-
array[row, ncol:] = 2
29+
array[row, ncol:] = 100
3030

3131
mfsplit = Mf6Splitter(sim)
3232
new_sim = mfsplit.split_model(array)
@@ -37,13 +37,13 @@ def test_structured_model_splitter(function_tmpdir):
3737

3838
original_heads = gwf.output.head().get_alldata()[-1]
3939

40-
ml0 = new_sim.get_model("freyberg_1")
41-
ml1 = new_sim.get_model("freyberg_2")
40+
ml0 = new_sim.get_model("freyberg_001")
41+
ml1 = new_sim.get_model("freyberg_100")
4242

4343
heads0 = ml0.output.head().get_alldata()[-1]
4444
heads1 = ml1.output.head().get_alldata()[-1]
4545

46-
new_heads = mfsplit.reconstruct_array({1: heads0, 2: heads1})
46+
new_heads = mfsplit.reconstruct_array({1: heads0, 100: heads1})
4747

4848
err_msg = "Heads from original and split models do not match"
4949
np.testing.assert_allclose(new_heads, original_heads, err_msg=err_msg)
@@ -691,3 +691,171 @@ def test_idomain_none(function_tmpdir):
691691

692692
err_msg = "Heads from original and split models do not match"
693693
np.testing.assert_allclose(new_head, head, atol=1e-07, err_msg=err_msg)
694+
695+
696+
@requires_exe("mf6")
697+
def test_unstructured_complex_disu(function_tmpdir):
698+
sim_path = function_tmpdir
699+
split_sim_path = sim_path / "model_split"
700+
701+
# build the simulation structure
702+
sim = flopy.mf6.MFSimulation(sim_ws=sim_path)
703+
ims = flopy.mf6.ModflowIms(sim, complexity="SIMPLE")
704+
tdis = flopy.mf6.ModflowTdis(sim)
705+
706+
mname = "disu_model"
707+
gwf = flopy.mf6.ModflowGwf(sim, modelname=mname)
708+
709+
# start structured and then create a USG from it
710+
nlay = 1
711+
nrow = 10
712+
ncol = 10
713+
delc = np.ones((nrow,))
714+
delr = np.ones((ncol,))
715+
top = np.ones((nrow, ncol))
716+
botm = np.zeros((nlay, nrow, ncol))
717+
idomain = np.ones(botm.shape, dtype=int)
718+
idomain[0, 1, 4] = 0
719+
idomain[0, 8, 5] = 0
720+
721+
grid = flopy.discretization.StructuredGrid(
722+
delc=delc, delr=delr, top=top, botm=botm, idomain=idomain
723+
)
724+
725+
# build the USG connection information
726+
neighbors = grid.neighbors(method="rook", reset=True)
727+
iac, ja, ihc, cl12, hwva, angldegx = [], [], [], [], [], []
728+
for cell, neigh in neighbors.items():
729+
iac.append(len(neigh) + 1)
730+
ihc.extend(
731+
[
732+
1,
733+
]
734+
* (len(neigh) + 1)
735+
)
736+
ja.extend(
737+
[
738+
cell,
739+
]
740+
+ neigh
741+
)
742+
cl12.extend(
743+
[
744+
0,
745+
]
746+
+ [
747+
1,
748+
]
749+
* len(neigh)
750+
)
751+
hwva.extend(
752+
[
753+
0,
754+
]
755+
+ [
756+
1,
757+
]
758+
* len(neigh)
759+
)
760+
adx = [
761+
0,
762+
]
763+
for n in neigh:
764+
ev = cell - n
765+
if ev == -1 * ncol:
766+
adx.append(270)
767+
elif ev == ncol:
768+
adx.append(90)
769+
elif ev == -1:
770+
adx.append(0)
771+
else:
772+
adx.append(180)
773+
angldegx.extend(adx)
774+
775+
# build iverts and verts. Do not use shared iverts and mess with verts a
776+
# tiny bit
777+
verts, cell2d = [], []
778+
xverts, yverts = grid.cross_section_vertices
779+
xcenters = grid.xcellcenters.ravel()
780+
ycenters = grid.ycellcenters.ravel()
781+
ivert = 0
782+
for cell_num, xvs in enumerate(xverts):
783+
if (cell_num - 3) % 10 == 0:
784+
xvs[2] -= 0.001
785+
xvs[3] -= 0.001
786+
yvs = yverts[cell_num]
787+
788+
c2drec = [cell_num, xcenters[cell_num], ycenters[cell_num], len(xvs)]
789+
for ix, vert in enumerate(xvs[:-1]):
790+
c2drec.append(ivert)
791+
verts.append([ivert, vert, yvs[ix]])
792+
ivert += 1
793+
794+
c2drec.append(c2drec[4])
795+
cell2d.append(c2drec)
796+
797+
nodes = len(cell2d)
798+
nja = len(ja)
799+
nvert = len(verts)
800+
801+
dis = flopy.mf6.ModflowGwfdisu(
802+
gwf,
803+
nodes=nodes,
804+
nja=nja,
805+
nvert=nvert,
806+
top=np.ravel(grid.top),
807+
bot=np.ravel(grid.botm),
808+
area=np.ones((nodes,)),
809+
idomain=grid.idomain.ravel(),
810+
iac=iac,
811+
ja=ja,
812+
ihc=ihc,
813+
cl12=cl12,
814+
hwva=hwva,
815+
angldegx=angldegx,
816+
vertices=verts,
817+
cell2d=cell2d,
818+
)
819+
820+
# build npf, ic, CHD, OC package
821+
npf = flopy.mf6.ModflowGwfnpf(gwf)
822+
ic = flopy.mf6.ModflowGwfic(gwf)
823+
824+
spd = []
825+
for i in range(nrow):
826+
spd.append((0 + (i * 10), 0.9))
827+
spd.append((9 + (i * 10), 0.5))
828+
829+
chd = flopy.mf6.ModflowGwfchd(gwf, stress_period_data=spd)
830+
831+
spd = {0: [("HEAD", "LAST")]}
832+
oc = flopy.mf6.ModflowGwfoc(
833+
gwf, head_filerecord=f"{mname}.hds", saverecord=spd
834+
)
835+
836+
sim.write_simulation()
837+
sim.run_simulation()
838+
839+
heads = gwf.output.head().get_alldata()[-1]
840+
841+
array = np.zeros((nrow, ncol), dtype=int)
842+
array[:, 5:] = 1
843+
844+
mfsplit = Mf6Splitter(sim)
845+
new_sim = mfsplit.split_model(array)
846+
847+
new_sim.set_sim_path(split_sim_path)
848+
new_sim.write_simulation()
849+
new_sim.run_simulation()
850+
851+
gwf0 = new_sim.get_model(f"{mname}_0")
852+
gwf1 = new_sim.get_model(f"{mname}_1")
853+
854+
heads0 = gwf0.output.head().get_alldata()[-1]
855+
heads1 = gwf1.output.head().get_alldata()[-1]
856+
857+
new_heads = mfsplit.reconstruct_array({0: heads0, 1: heads1})
858+
859+
diff = np.abs(heads - new_heads)
860+
if np.max(diff) > 1e-07:
861+
raise AssertionError("Reconstructed head results outside of tolerance")

cliff.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,16 @@ trim = true
2020
conventional_commits = true
2121
filter_unconventional = true
2222
split_commits = false
23+
commit_preprocessors = [
24+
{ pattern = "^ *", replace = ""}
25+
]
2326
commit_parsers = [
2427
{ message = "^[fF]eat", group = "feat"},
2528
{ message = "^[fF]ix", group = "fix"},
2629
{ message = "^[bB]ug", group = "fix"},
2730
{ message = "^[pP]erf", group = "perf"},
2831
{ message = "^[rR]efactor", group = "refactor"},
29-
{ message = "^[uU]pdate", group = "refactor"},
32+
{ message = "^[uU]pdate.*", group = "refactor"},
3033
{ message = "^[dD]oc.*", group = "docs", skip = true},
3134
{ message = "^[bB]inder", group = "docs", skip = true},
3235
{ message = "^[nN]otebook.*", group = "docs", skip = true},

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.0: U.S. Geological Survey Software Release, 08 August 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.1: U.S. Geological Survey Software Release, 05 September 2024, https://doi.org/10.5066/F7BK19FH](https://doi.org/10.5066/F7BK19FH)

flopy/discretization/grid.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -595,7 +595,7 @@ def xyzvertices(self):
595595
def cross_section_vertices(self):
596596
return self.xyzvertices[0], self.xyzvertices[1]
597597

598-
def geo_dataframe(self, polys):
598+
def geo_dataframe(self, features, featuretype="Polygon"):
599599
"""
600600
Method returns a geopandas GeoDataFrame of the Grid
601601
@@ -606,7 +606,7 @@ def geo_dataframe(self, polys):
606606
from ..utils.geospatial_utils import GeoSpatialCollection
607607

608608
gc = GeoSpatialCollection(
609-
polys, shapetype=["Polygon" for _ in range(len(polys))]
609+
features, shapetype=[featuretype for _ in range(len(features))]
610610
)
611611
gdf = gc.geo_dataframe
612612
if self.crs is not None:

flopy/discretization/structuredgrid.py

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -192,14 +192,18 @@ def __init__(
192192
if top is not None:
193193
assert self.__nrow * self.__ncol == len(np.ravel(top))
194194
if botm is not None:
195-
assert self.__nrow * self.__ncol == len(np.ravel(botm[0]))
196-
if nlay is not None:
197-
self.__nlay = nlay
198-
else:
199-
if laycbd is not None:
200-
self.__nlay = len(botm) - np.count_nonzero(laycbd)
195+
if botm.ndim == 3:
196+
assert self.__nrow * self.__ncol == len(np.ravel(botm[0]))
197+
if nlay is not None:
198+
self.__nlay = nlay
201199
else:
202-
self.__nlay = len(botm)
200+
if laycbd is not None:
201+
self.__nlay = len(botm) - np.count_nonzero(laycbd)
202+
else:
203+
self.__nlay = len(botm)
204+
elif botm.ndim == 2:
205+
assert botm.shape == (self.__nrow, self.__ncol)
206+
self.__nlay = 1
203207
else:
204208
self.__nlay = nlay
205209
if laycbd is not None:

0 commit comments

Comments
 (0)