Mesh Connectivity
polaris.mesh.connectivity answers questions about which cells of a mesh a
model can actually move a quantity between, given a mask saying which cells
belong to the domain. Its main use is finding land-locked cells and other
disconnected pockets before a mesh is culled; see the
design document on land-locked cells
for the reasoning behind the criteria below.
The key point is that sharing an edge is not the same as being connected. Whether two neighboring cells are connected depends on the grid staggering of the model that will use the mesh, so these functions take the mask and return the connectivity, rather than assuming one answer.
Active edges
An edge of a cell is active when the cell across it is also in the domain.
polaris.mesh.connectivity.active_edge_masks() returns three
(nCells, maxEdges) boolean arrays: whether each local edge is active, and
whether the next and previous edges around the same cell are. The next and
previous masks are what make vertex questions answerable, since two edges that
are adjacent in a cell’s edge ordering meet at a vertex.
Two convenience functions sit on top of it:
polaris.mesh.connectivity.count_active_edges()counts the active edges of each cell. An ocean cell on a C-grid needs at least two – one way in and one way out – and they need not be adjacent.polaris.mesh.connectivity.has_active_vertex()finds cells with at least one vertex all of whose surrounding cells are in the domain. A sea-ice cell on a B-grid needs one of these, or there is no velocity point by which ice can leave it.
Both evaluate every cell, including cells outside the domain, so mask the result if that matters.
Connectivity to seeds
polaris.mesh.connectivity.connected_to_seeds() flood-fills the
domain from a set of seed cells and returns the cells it reaches. Cells in
the domain that it does not reach are the disconnected pockets – inland seas,
land-locked cells, and lakes that a global ocean should not include.
The link_mask argument chooses the grid staggering. The default connects
every active edge, which is the ocean’s C-grid connectivity. For sea ice on a
B-grid, pass polaris.mesh.connectivity.transport_link_mask()
instead: the velocity that moves ice across an edge is built from the
velocities at that edge’s two vertices, so an edge whose vertices are both
inactive carries no flux and does not connect the cells it separates, even
though they share an edge.
Seeds usually come from a handful of known-open locations.
polaris.mesh.connectivity.seed_mask_from_points() turns longitudes
and latitudes in degrees into a mask on the nearest cell to each point:
from polaris.mesh.connectivity import connected_to_seeds, seed_mask_from_points
seed_mask = seed_mask_from_points(ds_mesh, lon_seed, lat_seed)
connected = connected_to_seeds(ds_mesh, cell_mask, seed_mask)
Seeds that land outside the domain are ignored rather than raising, so a seed point that a particular mesh resolution turns to land does not break the workflow.