Skip to content

Irregular-spaced shoreline position computation #55

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 5 commits into from
May 1, 2021
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 79 additions & 0 deletions deltametrics/plan.py
Original file line number Diff line number Diff line change
Expand Up @@ -717,6 +717,85 @@ def compute_shoreline_length(shore_mask, origin=[0, 0], return_line=False):
return length


def compute_shoreline_distance(shore_mask, origin=[0, 0],
return_distances=False):
"""Compute mean and stddev distance from the delta apex to the shoreline.

Algorithm computes the mean distance from the delta apex/origin to all
shoreline points.

.. important::

This calculation is subtly different than the "mean delta radius",
because the measurements are not sampled evenly along the opening
angle of the delta.

.. note:: uses `np.nanmean` and `np.nanstd`.

Parameters
----------
shore_mask : :obj:`~deltametrics.mask.ShorelineMask`, :obj:`ndarray`
Shoreline mask. Can be a :obj:`~deltametrics.mask.ShorelineMask`
object, or a binarized array.

origin : :obj:`list`, :obj:`np.ndarray`, optional
Determines the location from where the distance to all shoreline
points is computed.

return_distances : :obj:`bool`
Whether to return the sorted line as a second argument. If True, a
``Nx2`` array of x-y points is returned. Default is `False`.

Returns
-------
length : :obj:`float`
Shoreline length, computed as described above.

line : :obj:`np.ndarray`
If :obj:`return_line` is `True`, the shoreline, as an ``Nx2`` array of
x-y points, is returned.

Examples
--------

.. doctest::

golf = dm.sample_data.golf()

sm = dm.mask.ShorelineMask(
golf['eta'][-1, :, :],
elevation_threshold=0,
elevation_offset=-0.5)

# compute mean and stddev distance
mean, stddev = dm.plan.compute_shoreline_distance(
sm, origin=[golf.meta['CTR'].data, golf.meta['L0'].data])

"""
# check if mask or already array
if isinstance(shore_mask, mask.ShorelineMask):
_sm = shore_mask.mask
else:
_sm = shore_mask

if not (np.sum(_sm) > 0):
raise ValueError('No pixels in shoreline mask.')

if _sm.ndim == 3:
_sm = _sm.squeeze()

# find where the mask is True (all x-y pairs along shore)
_y, _x = np.argwhere(_sm).T

# determine the distances
_dists = np.sqrt((_x - origin[0])**2 + (_y - origin[1])**2)

if return_distances:
return _dists
else:
return np.nanmean(_dists), np.nanstd(_dists)


@njit
def _compute_angles_between(c1, shoreandborder, Shallowsea, numviews):
"""Private helper for shaw_opening_angle_method.
Expand Down
1 change: 1 addition & 0 deletions docs/source/reference/plan/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,5 @@ Functions

compute_shoreline_roughness
compute_shoreline_length
compute_shoreline_distance
shaw_opening_angle_method
48 changes: 48 additions & 0 deletions tests/test_plan.py
Original file line number Diff line number Diff line change
Expand Up @@ -252,3 +252,51 @@ def test_rcm8_defaults_opposite(self):
plt.show()
breakpoint()
assert len_1 == pytest.approx(self.rcm8_expected, abs=5.0)


class TestShorelineDistance:

golf_path = _get_golf_path()
golf = cube.DataCube(golf_path)

sm = mask.ShorelineMask(
golf['eta'][-1, :, :],
elevation_threshold=0,
elevation_offset=-0.5)

def test_empty(self):
_arr = np.zeros((10, 10))
with pytest.raises(ValueError):
_, _ = plan.compute_shoreline_distance(_arr)

def test_single_point(self):
_arr = np.zeros((10, 10))
_arr[7, 5] = 1
mean00, stddev00 = plan.compute_shoreline_distance(
_arr)
mean05, stddev05 = plan.compute_shoreline_distance(
_arr, origin=[5, 0])
assert mean00 == np.sqrt(49 + 25)
assert mean05 == 7
assert stddev00 == 0
assert stddev05 == 0

def test_simple_case(self):
mean, stddev = plan.compute_shoreline_distance(
self.sm, origin=[self.golf.meta['CTR'].data,
self.golf.meta['L0'].data])

assert mean > stddev
assert stddev > 0

def test_simple_case_distances(self):
m, s = plan.compute_shoreline_distance(
self.sm, origin=[self.golf.meta['CTR'].data,
self.golf.meta['L0'].data])
dists = plan.compute_shoreline_distance(
self.sm, origin=[self.golf.meta['CTR'].data,
self.golf.meta['L0'].data],
return_distances=True)

assert len(dists) > 0
assert np.mean(dists) == m