Skip to content

Commit e20a298

Browse files
author
langevin-usgs
authored
feat(gridutil): add function to help create DISV grid (#1952)
1 parent 2fa32da commit e20a298

File tree

2 files changed

+156
-3
lines changed

2 files changed

+156
-3
lines changed

autotest/test_gridutil.py

+43-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,12 @@
33
import numpy as np
44
import pytest
55

6-
from flopy.utils.gridutil import get_disu_kwargs, get_lni, uniform_flow_field
6+
from flopy.utils.gridutil import (
7+
get_disu_kwargs,
8+
get_disv_kwargs,
9+
get_lni,
10+
uniform_flow_field,
11+
)
712

813

914
@pytest.mark.parametrize(
@@ -102,6 +107,43 @@ def test_get_disu_kwargs(nlay, nrow, ncol, delr, delc, tp, botm):
102107
# print(kwargs["nja"])
103108

104109

110+
@pytest.mark.parametrize(
111+
"nlay, nrow, ncol, delr, delc, tp, botm",
112+
[
113+
(
114+
1,
115+
61,
116+
61,
117+
np.array(61 * [50.0]),
118+
np.array(61 * [50.0]),
119+
-10.0,
120+
-50.0,
121+
),
122+
(
123+
2,
124+
61,
125+
61,
126+
np.array(61 * [50.0]),
127+
np.array(61 * [50.0]),
128+
-10.0,
129+
[-30.0, -50.0],
130+
),
131+
],
132+
)
133+
def test_get_disv_kwargs(nlay, nrow, ncol, delr, delc, tp, botm):
134+
kwargs = get_disv_kwargs(
135+
nlay=nlay, nrow=nrow, ncol=ncol, delr=delr, delc=delc, tp=tp, botm=botm
136+
)
137+
138+
assert kwargs["nlay"] == nlay
139+
assert kwargs["ncpl"] == nrow * ncol
140+
assert kwargs["nvert"] == (nrow + 1) * (ncol + 1)
141+
142+
# TODO: test other properties
143+
# print(kwargs["vertices"])
144+
# print(kwargs["cell2d"])
145+
146+
105147
@pytest.mark.parametrize(
106148
"qx, qy, qz, nlay, nrow, ncol",
107149
[

flopy/utils/gridutil.py

+113-2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
import numpy as np
88

9+
from .cvfdutil import get_disv_gridprops
10+
911

1012
def get_lni(ncpl, nodes) -> List[Tuple[int, int]]:
1113
"""
@@ -68,7 +70,8 @@ def get_disu_kwargs(
6870
botm,
6971
):
7072
"""
71-
Create args needed to construct a DISU package.
73+
Create args needed to construct a DISU package for a regular
74+
MODFLOW grid.
7275
7376
Parameters
7477
----------
@@ -85,7 +88,7 @@ def get_disu_kwargs(
8588
tp : int or numpy.ndarray
8689
Top elevation(s) of cells in the model's top layer
8790
botm : numpy.ndarray
88-
Bottom elevation(s) of all cells in the model
91+
Bottom elevation(s) for each layer
8992
"""
9093

9194
def get_nn(k, i, j):
@@ -181,6 +184,114 @@ def get_nn(k, i, j):
181184
return kw
182185

183186

187+
def get_disv_kwargs(
188+
nlay,
189+
nrow,
190+
ncol,
191+
delr,
192+
delc,
193+
tp,
194+
botm,
195+
xoff=0.0,
196+
yoff=0.0,
197+
):
198+
"""
199+
Create args needed to construct a DISV package.
200+
201+
Parameters
202+
----------
203+
nlay : int
204+
Number of layers
205+
nrow : int
206+
Number of rows
207+
ncol : int
208+
Number of columns
209+
delr : float or numpy.ndarray
210+
Column spacing along a row with shape (ncol)
211+
delc : float or numpy.ndarray
212+
Row spacing along a column with shape (nrow)
213+
tp : float or numpy.ndarray
214+
Top elevation(s) of cells in the model's top layer with shape (nrow, ncol)
215+
botm : list of floats or numpy.ndarray
216+
Bottom elevation(s) of all cells in the model with shape (nlay, nrow, ncol)
217+
xoff : float
218+
Value to add to all x coordinates. Optional (default = 0.)
219+
yoff : float
220+
Value to add to all y coordinates. Optional (default = 0.)
221+
"""
222+
223+
# validate input
224+
ncpl = nrow * ncol
225+
226+
# delr check
227+
if np.isscalar(delr):
228+
delr = delr * np.ones(ncol, dtype=float)
229+
else:
230+
assert delr.shape == (ncol,), "delr must be array with shape (ncol,)"
231+
232+
# delc check
233+
if np.isscalar(delc):
234+
delc = delc * np.ones(nrow, dtype=float)
235+
else:
236+
assert delc.shape == (nrow,), "delc must be array with shape (nrow,)"
237+
238+
# tp check
239+
if np.isscalar(tp):
240+
tp = tp * np.ones((nrow, ncol), dtype=float)
241+
else:
242+
assert tp.shape == (
243+
nrow,
244+
ncol,
245+
), "tp must be scalar or array with shape (nrow, ncol)"
246+
247+
# botm check
248+
if np.isscalar(botm):
249+
botm = botm * np.ones((nlay, nrow, ncol), dtype=float)
250+
elif isinstance(botm, List):
251+
assert (
252+
len(botm) == nlay
253+
), "if botm provided as a list it must have length nlay"
254+
b = np.empty((nlay, nrow, ncol), dtype=float)
255+
for k in range(nlay):
256+
b[k] = botm[k]
257+
botm = b
258+
else:
259+
assert botm.shape == (
260+
nlay,
261+
nrow,
262+
ncol,
263+
), "botm must be array with shape (nlay, nrow, ncol)"
264+
265+
# build vertices
266+
xv = np.cumsum(delr)
267+
xv = np.array([0] + list(xv))
268+
ymax = delc.sum()
269+
yv = np.cumsum(delc)
270+
yv = ymax - np.array([0] + list(yv))
271+
xmg, ymg = np.meshgrid(xv, yv)
272+
verts = np.array(list(zip(xmg.flatten(), ymg.flatten())))
273+
verts[:, 0] += xoff
274+
verts[:, 1] += yoff
275+
276+
# build iverts (list of vertices for each cell)
277+
iverts = []
278+
for i in range(nrow):
279+
for j in range(ncol):
280+
# number vertices in clockwise order
281+
iv0 = j + i * (ncol + 1) # upper left vertex
282+
iv1 = iv0 + 1 # upper right vertex
283+
iv3 = iv0 + ncol + 1 # lower left vertex
284+
iv2 = iv3 + 1 # lower right vertex
285+
iverts.append([iv0, iv1, iv2, iv3])
286+
kw = get_disv_gridprops(verts, iverts)
287+
288+
# reshape and add top and bottom
289+
kw["top"] = tp.reshape(ncpl)
290+
kw["botm"] = botm.reshape(nlay, ncpl)
291+
kw["nlay"] = nlay
292+
return kw
293+
294+
184295
def uniform_flow_field(qx, qy, qz, shape, delr=None, delc=None, delv=None):
185296
nlay, nrow, ncol = shape
186297

0 commit comments

Comments
 (0)