Source code for earthkit.hydro.subnetwork._toplevel
import copy as cp
from earthkit.hydro._backends.numpy_backend import NumPyBackend
from earthkit.hydro._utils.decorators.masking import mask_last2_dims
from earthkit.hydro.data_structures import RiverNetwork
np = NumPyBackend()
[docs]
def from_mask(river_network: RiverNetwork, node_mask=None, edge_mask=None, copy=True):
"""
Create a subnetwork from a river network.
Parameters
----------
river_network : RiverNetwork
Original river network from which to create a subnetwork.
node_mask : array, optional
A mask of the network nodes or gridcells. Default is None (all True).
edge_mask : array, optional
A mask of the network edges. Default is None (all True).
copy : bool, optional
Whether or not to modify the original river network or return a copy. Default is True.
Returns
-------
RiverNetwork
The river network object created from the given data.
"""
if river_network.array_backend != "numpy" or copy is not True:
raise NotImplementedError
if node_mask is None and edge_mask is None:
return cp.deepcopy(river_network)
if node_mask is not None:
if node_mask.shape[-2:] == river_network.shape:
node_mask = mask_last2_dims(
np, node_mask, river_network.mask, node_mask.shape
)
node_relabel = np.empty(river_network.n_nodes, dtype=int)
node_relabel[node_mask] = np.arange(node_mask.sum())
storage = cp.deepcopy(river_network._storage)
if edge_mask is not None and node_mask is not None:
valid_edges = edge_mask[storage.sorted_data[2]] & (
node_mask[storage.sorted_data[0]] & node_mask[storage.sorted_data[1]]
)
elif edge_mask is None:
valid_edges = (
node_mask[storage.sorted_data[0]] & node_mask[storage.sorted_data[1]]
)
else:
valid_edges = edge_mask[storage.sorted_data[2]]
original_order_edge_mask = np.empty(river_network.n_edges, dtype=bool)
original_order_edge_mask[storage.sorted_data[2]] = valid_edges
edge_relabel = np.empty(river_network.n_edges, dtype=int)
edge_relabel[original_order_edge_mask] = np.arange(original_order_edge_mask.sum())
storage.sorted_data = storage.sorted_data[..., valid_edges]
storage.sorted_data[0] = node_relabel[storage.sorted_data[0]]
storage.sorted_data[1] = node_relabel[storage.sorted_data[1]]
storage.sorted_data[2] = edge_relabel[storage.sorted_data[2]]
storage.splits = np.cumsum(valid_edges)[storage.splits - 1]
storage.mask = storage.mask[node_mask]
storage.n_nodes = storage.mask.shape[0]
storage.n_edges = storage.sorted_data.shape[1]
return RiverNetwork(storage)
[docs]
def crop(river_network: RiverNetwork, copy=True):
"""
Crop a gridded network to the minimum bounding grid.
Parameters
----------
river_network : RiverNetwork
Original river network from which to create a cropped network.
copy : bool, optional
Whether or not to modify the original river network or return a copy. Default is True.
Returns
-------
RiverNetwork
The river network object created from the given data.
"""
if river_network.array_backend != "numpy" or copy is not True:
raise NotImplementedError
storage = cp.deepcopy(river_network._storage)
rows, cols = np.unravel_index(storage.mask, shape=(storage.shape))
row_min, row_max = rows.min(), rows.max()
col_min, col_max = cols.min(), cols.max()
storage.shape = (int(row_max - row_min + 1), int(col_max - col_min + 1))
storage.mask = np.ravel_multi_index(
(rows - row_min, cols - col_min), dims=storage.shape
)
for i, key in enumerate(storage.coords.keys()):
if i == 0:
storage.coords[key] = storage.coords[key][row_min : row_max + 1]
elif i == 1:
storage.coords[key] = storage.coords[key][col_min : col_max + 1]
else:
raise ValueError("coords must not have more than 2 keys.")
return RiverNetwork(storage)