Skip to content

Commit

Permalink
refactor(CrossSectionPlot, GeoSpatialUtil): (#1521)
Browse files Browse the repository at this point in the history
* accept flopy & shapely LineString for cross section line via GeoSpatialUtil
* check when creating new GeoSpatialUtil that linestrings have 2+ coordinates
  • Loading branch information
wpbonelli committed Sep 2, 2022
1 parent 265ee59 commit 18a3679
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 1 deletion.
7 changes: 7 additions & 0 deletions autotest/test_geospatial_util.py
Expand Up @@ -543,3 +543,10 @@ def test_mixed_collection(
raise AssertionError(
"GeoSpatialCollection conversion error"
)


@requires_pkg("shapely", "geojson")
def test_create_linestring_with_single_point_fails():
point = [0, 0]
with pytest.raises(ValueError):
GeoSpatialUtil(point, shapetype="linestring")
78 changes: 78 additions & 0 deletions autotest/test_plot.py
Expand Up @@ -28,6 +28,7 @@
from flopy.modpath import Modpath6, Modpath6Bas
from flopy.plot import PlotCrossSection, PlotMapView
from flopy.utils import CellBudgetFile, HeadFile, PathlineFile
from flopy.utils.geometry import LineString


def test_map_view():
Expand Down Expand Up @@ -523,3 +524,80 @@ def test_cross_section_with_quasi3d_layers(quasi3d_model):
cs.plot_bc("wel")
cs.plot_vector(frf, fff, flf, head=head)
plt.savefig(os.path.join(str(quasi3d_model.model_ws), "plt02.png"))
plt.close()


def structured_square_grid(side: int = 10, thick: int = 10):
"""
Creates a basic 1-layer structured grid with the given thickness and number of cells per side
Parameters
----------
side : The number of cells per side
thick : The thickness of the grid's single layer
Returns
-------
A single-layer StructuredGrid of the given size and thickness
"""

from flopy.discretization.structuredgrid import StructuredGrid

delr = np.ones(side)
delc = np.ones(side)
top = np.ones((side, side)) * thick
botm = np.ones((side, side)) * (top - thick).reshape(1, side, side)
return StructuredGrid(delr=delr, delc=delc, top=top, botm=botm)


@pytest.mark.parametrize(
"line",
[
(0, 0),
[0, 0],
],
)
def test_cross_section_line_as_point_fails(line):
grid = structured_square_grid(side=10)
with pytest.raises(ValueError):
flopy.plot.PlotCrossSection(modelgrid=grid, line={"line": line})


@requires_pkg("shapely")
@pytest.mark.parametrize(
"line",
[
# diagonal line
[(0, 0), (10, 10)], # test list of tuples
([0, 0], [10, 10]), # and tuple of lists
# horizontal line
([0, 5.5], [10, 5.5]),
[(0, 5.5), (10, 5.5)],
# vertical line
[(0, 5.5), (10, 5.5)],
([0, 5.5], [10, 5.5]),
# line with multiple segments
[(0, 0), (4, 6), (10, 10)],
([0, 0], [4, 6], [10, 10]),
],
)
def test_cross_section_line_representations(line):
import shapely

grid = structured_square_grid(side=10)

fls = LineString(line)
sls = shapely.geometry.LineString(line)

# use raw, flopy.utils.geometry and shapely.geometry representations
lxc = flopy.plot.PlotCrossSection(modelgrid=grid, line={"line": line})
fxc = flopy.plot.PlotCrossSection(modelgrid=grid, line={"line": fls})
sxc = flopy.plot.PlotCrossSection(modelgrid=grid, line={"line": sls})

# make sure parsed points are identical for all line representations
assert np.allclose(lxc.pts, fxc.pts) and np.allclose(lxc.pts, sxc.pts)
assert (
set(lxc.xypts.keys()) == set(fxc.xypts.keys()) == set(sxc.xypts.keys())
)
for k in lxc.xypts.keys():
assert np.allclose(lxc.xypts[k], fxc.xypts[k]) and np.allclose(
lxc.xypts[k], sxc.xypts[k]
)
9 changes: 8 additions & 1 deletion flopy/plot/crosssection.py
Expand Up @@ -7,6 +7,7 @@
from matplotlib.patches import Polygon

from ..utils import geometry
from ..utils.geospatial_utils import GeoSpatialUtil
from . import plotutil

warnings.simplefilter("always", PendingDeprecationWarning)
Expand Down Expand Up @@ -135,7 +136,13 @@ def __init__(
(xcenter[int(line[onkey])], yedge[-1] - eps),
]
else:
verts = line[onkey]
ln = line[onkey]
gu = GeoSpatialUtil(ln, shapetype="linestring")
assert (
gu.shapetype == "LineString"
) # unnecessary if GSU guarantees shapetype is same as requested

verts = gu.points
xp = []
yp = []
for [v1, v2] in verts:
Expand Down
3 changes: 3 additions & 0 deletions flopy/utils/geospatial_utils.py
Expand Up @@ -75,6 +75,9 @@ def __init__(self, obj, shapetype=None):
)
raise AssertionError(err)

if shapetype == "linestring" and len(np.array(obj).shape) == 1:
raise ValueError(f"linestring must have 2 or more coordinates")

self.__geo_interface = {
"type": shape_types[shapetype],
"coordinates": list(obj),
Expand Down

0 comments on commit 18a3679

Please sign in to comment.