def auto_generate(self, threshold: float=0.0, land_ibtype: int=0, interior_ibtype: int=1):
    'Automatically detect boundaries based on elevation data.\n\n        Parameters\n        ----------\n        threshold : float, default=0\n            Threshold above which nodes are considered dry nodes\n            for ocean vs land boundary detection\n        land_ibtype : int, default=0\n            Value to assign to land boundary type\n        interior_ibtype : int, default=1\n            Value to assign to island boundary type\n\n        Returns\n        -------\n        None\n\n        Raises\n        ------\n        ValueError\n            If any of the values assigned to a mesh node is `np.nan`.\n\n        Notes\n        -----\n        An edge is considered dry if any of the attached nodes are\n        dry (its elevation is larger than or equal to the `threshold`).\n        '
    values = self.mesh.value
    if np.any(np.isnan(values)):
        raise ValueError('Mesh contains invalid values. Raster values mustbe interpolated to the mesh before generating boundaries.')
    coords = self.mesh.msh_t.vert2['coord']
    coo_to_idx = {tuple(coo): idx for (idx, coo) in enumerate(coords)}
    polys = utils.get_mesh_polygons(self.mesh.msh_t)
    boundaries = defaultdict(defaultdict)
    bdry_type = dict
    get_id = self.mesh.nodes.get_id_by_index
    for poly in polys:
        ext_ring_coo = poly.exterior.coords
        ext_ring = np.array([(coo_to_idx[ext_ring_coo[e]], coo_to_idx[ext_ring_coo[(e + 1)]]) for (e, coo) in enumerate(ext_ring_coo[:(- 1)])])
        edge_tag = np.full(ext_ring.shape, 0)
        edge_tag[(np.where((values[ext_ring[:, 0]] < threshold))[0], 0)] = (- 1)
        edge_tag[(np.where((values[ext_ring[:, 1]] < threshold))[0], 1)] = (- 1)
        edge_tag[(np.where((values[ext_ring[:, 0]] >= threshold))[0], 0)] = 1
        edge_tag[(np.where((values[ext_ring[:, 1]] >= threshold))[0], 1)] = 1
        ocean_boundary = []
        land_boundary = []
        for (i, (e0, e1)) in enumerate(edge_tag):
            if np.any((np.asarray((e0, e1)) == 1)):
                land_boundary.append(tuple(ext_ring[i, :]))
            elif np.any((np.asarray((e0, e1)) == (- 1))):
                ocean_boundary.append(tuple(ext_ring[i, :]))
        ocean_boundaries = []
        if (len(ocean_boundary) != 0):
            ocean_segs = linemerge(coords[np.array(ocean_boundary)].tolist())
            ocean_segs = ([ocean_segs] if isinstance(ocean_segs, LineString) else ocean_segs)
            ocean_boundaries = [[(coo_to_idx[seg.coords[e]], coo_to_idx[seg.coords[(e + 1)]]) for (e, coo) in enumerate(seg.coords[:(- 1)])] for seg in ocean_segs]
        land_boundaries = []
        if (len(land_boundary) != 0):
            land_segs = linemerge(coords[np.array(land_boundary)].tolist())
            land_segs = ([land_segs] if isinstance(land_segs, LineString) else land_segs)
            land_boundaries = [[(coo_to_idx[seg.coords[e]], coo_to_idx[seg.coords[(e + 1)]]) for (e, coo) in enumerate(seg.coords[:(- 1)])] for seg in land_segs]
        _bnd_id = len(boundaries[None])
        for bnd in ocean_boundaries:
            (e0, e1) = [list(t) for t in zip(*bnd)]
            e0 = [get_id(vert) for vert in e0]
            data = (e0 + [get_id(e1[(- 1)])])
            boundaries[None][_bnd_id] = bdry_type(indexes=data, properties={})
            _bnd_id += 1
        _bnd_id = len(boundaries[land_ibtype])
        for bnd in land_boundaries:
            (e0, e1) = [list(t) for t in zip(*bnd)]
            e0 = [get_id(vert) for vert in e0]
            data = (e0 + [get_id(e1[(- 1)])])
            boundaries[land_ibtype][_bnd_id] = bdry_type(indexes=data, properties={})
            _bnd_id += 1
    _bnd_id = 0
    interior_boundaries = defaultdict()
    for poly in polys:
        interiors = poly.interiors
        for interior in interiors:
            int_ring_coo = interior.coords
            int_ring = [(coo_to_idx[int_ring_coo[e]], coo_to_idx[int_ring_coo[(e + 1)]]) for (e, coo) in enumerate(int_ring_coo[:(- 1)])]
            (e0, e1) = [list(t) for t in zip(*int_ring)]
            if (utils.signed_polygon_area(self.mesh.coord[e0, :]) < 0):
                e0 = e0[::(- 1)]
                e1 = e1[::(- 1)]
            e0 = [get_id(vert) for vert in e0]
            e0.append(e0[0])
            interior_boundaries[_bnd_id] = e0
            _bnd_id += 1
    for (bnd_id, data) in interior_boundaries.items():
        boundaries[interior_ibtype][bnd_id] = bdry_type(indexes=data, properties={})
    self._data = boundaries
    self._init_dataframes.cache_clear()
    self.__call__.cache_clear()
    self._init_dataframes()
Automatically detect boundaries based on elevation data.

Parameters
----------
threshold : float, default=0
    Threshold above which nodes are considered dry nodes
    for ocean vs land boundary detection
land_ibtype : int, default=0
    Value to assign to land boundary type
interior_ibtype : int, default=1
    Value to assign to island boundary type

Returns
-------
None

Raises
------
ValueError
    If any of the values assigned to a mesh node is `np.nan`.

Notes
-----
An edge is considered dry if any of the attached nodes are
dry (its elevation is larger than or equal to the `threshold`).
def auto_generate(self, threshold: float=0.0, land_ibtype: int=0, interior_ibtype: int=1):
    'Automatically detect boundaries based on elevation data.\n\n        Parameters\n        ----------\n        threshold : float, default=0\n            Threshold above which nodes are considered dry nodes\n            for ocean vs land boundary detection\n        land_ibtype : int, default=0\n            Value to assign to land boundary type\n        interior_ibtype : int, default=1\n            Value to assign to island boundary type\n\n        Returns\n        -------\n        None\n\n        Raises\n        ------\n        ValueError\n            If any of the values assigned to a mesh node is `np.nan`.\n\n        Notes\n        -----\n        An edge is considered dry if any of the attached nodes are\n        dry (its elevation is larger than or equal to the `threshold`).\n        '
    values = self.mesh.value
    if np.any(np.isnan(values)):
        raise ValueError('Mesh contains invalid values. Raster values mustbe interpolated to the mesh before generating boundaries.')
    coords = self.mesh.msh_t.vert2['coord']
    coo_to_idx = {tuple(coo): idx for (idx, coo) in enumerate(coords)}
    polys = utils.get_mesh_polygons(self.mesh.msh_t)
    boundaries = defaultdict(defaultdict)
    bdry_type = dict
    get_id = self.mesh.nodes.get_id_by_index
    for poly in polys:
        ext_ring_coo = poly.exterior.coords
        ext_ring = np.array([(coo_to_idx[ext_ring_coo[e]], coo_to_idx[ext_ring_coo[(e + 1)]]) for (e, coo) in enumerate(ext_ring_coo[:(- 1)])])
        edge_tag = np.full(ext_ring.shape, 0)
        edge_tag[(np.where((values[ext_ring[:, 0]] < threshold))[0], 0)] = (- 1)
        edge_tag[(np.where((values[ext_ring[:, 1]] < threshold))[0], 1)] = (- 1)
        edge_tag[(np.where((values[ext_ring[:, 0]] >= threshold))[0], 0)] = 1
        edge_tag[(np.where((values[ext_ring[:, 1]] >= threshold))[0], 1)] = 1
        ocean_boundary = []
        land_boundary = []
        for (i, (e0, e1)) in enumerate(edge_tag):
            if np.any((np.asarray((e0, e1)) == 1)):
                land_boundary.append(tuple(ext_ring[i, :]))
            elif np.any((np.asarray((e0, e1)) == (- 1))):
                ocean_boundary.append(tuple(ext_ring[i, :]))
        ocean_boundaries = []
        if (len(ocean_boundary) != 0):
            ocean_segs = linemerge(coords[np.array(ocean_boundary)].tolist())
            ocean_segs = ([ocean_segs] if isinstance(ocean_segs, LineString) else ocean_segs)
            ocean_boundaries = [[(coo_to_idx[seg.coords[e]], coo_to_idx[seg.coords[(e + 1)]]) for (e, coo) in enumerate(seg.coords[:(- 1)])] for seg in ocean_segs]
        land_boundaries = []
        if (len(land_boundary) != 0):
            land_segs = linemerge(coords[np.array(land_boundary)].tolist())
            land_segs = ([land_segs] if isinstance(land_segs, LineString) else land_segs)
            land_boundaries = [[(coo_to_idx[seg.coords[e]], coo_to_idx[seg.coords[(e + 1)]]) for (e, coo) in enumerate(seg.coords[:(- 1)])] for seg in land_segs]
        _bnd_id = len(boundaries[None])
        for bnd in ocean_boundaries:
            (e0, e1) = [list(t) for t in zip(*bnd)]
            e0 = [get_id(vert) for vert in e0]
            data = (e0 + [get_id(e1[(- 1)])])
            boundaries[None][_bnd_id] = bdry_type(indexes=data, properties={})
            _bnd_id += 1
        _bnd_id = len(boundaries[land_ibtype])
        for bnd in land_boundaries:
            (e0, e1) = [list(t) for t in zip(*bnd)]
            e0 = [get_id(vert) for vert in e0]
            data = (e0 + [get_id(e1[(- 1)])])
            boundaries[land_ibtype][_bnd_id] = bdry_type(indexes=data, properties={})
            _bnd_id += 1
    _bnd_id = 0
    interior_boundaries = defaultdict()
    for poly in polys:
        interiors = poly.interiors
        for interior in interiors:
            int_ring_coo = interior.coords
            int_ring = [(coo_to_idx[int_ring_coo[e]], coo_to_idx[int_ring_coo[(e + 1)]]) for (e, coo) in enumerate(int_ring_coo[:(- 1)])]
            (e0, e1) = [list(t) for t in zip(*int_ring)]
            if (utils.signed_polygon_area(self.mesh.coord[e0, :]) < 0):
                e0 = e0[::(- 1)]
                e1 = e1[::(- 1)]
            e0 = [get_id(vert) for vert in e0]
            e0.append(e0[0])
            interior_boundaries[_bnd_id] = e0
            _bnd_id += 1
    for (bnd_id, data) in interior_boundaries.items():
        boundaries[interior_ibtype][bnd_id] = bdry_type(indexes=data, properties={})
    self._data = boundaries
    self._init_dataframes.cache_clear()
    self.__call__.cache_clear()
    self._init_dataframes()